+#define JUNIPER_PROTO_NULL 1
+#define JUNIPER_PROTO_IPV4 2
+#define JUNIPER_PROTO_IPV6 6
+
+#define MFR_BE_MASK 0xc0
+
+#ifdef DLT_JUNIPER_GGSN
+static const struct tok juniper_protocol_values[] = {
+ { JUNIPER_PROTO_NULL, "Null" },
+ { JUNIPER_PROTO_IPV4, "IPv4" },
+ { JUNIPER_PROTO_IPV6, "IPv6" },
+ { 0, NULL}
+};
+#endif
+
+static int ip_heuristic_guess(netdissect_options *, const u_char *, u_int);
+#ifdef DLT_JUNIPER_ATM2
+static int juniper_ppp_heuristic_guess(netdissect_options *, const u_char *, u_int);
+#endif
+static int juniper_parse_header(netdissect_options *, const u_char *, const struct pcap_pkthdr *, struct juniper_l2info_t *);
+
+#ifdef DLT_JUNIPER_GGSN
+void
+juniper_ggsn_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+ struct juniper_ggsn_header {
+ nd_uint8_t svc_id;
+ nd_uint8_t flags_len;
+ nd_uint8_t proto;
+ nd_uint8_t flags;
+ nd_uint16_t vlan_id;
+ nd_byte res[2];
+ };
+ const struct juniper_ggsn_header *gh;
+ uint8_t proto;
+
+ ndo->ndo_protocol = "juniper_ggsn";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_GGSN;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ gh = (struct juniper_ggsn_header *)&l2info.cookie;
+
+ /* use EXTRACT_, not GET_ (not packet buffer pointer) */
+ proto = EXTRACT_U_1(gh->proto);
+ if (ndo->ndo_eflag) {
+ ND_PRINT("proto %s (%u), vlan %u: ",
+ tok2str(juniper_protocol_values,"Unknown",proto),
+ proto,
+ EXTRACT_BE_U_2(gh->vlan_id));
+ }
+
+ switch (proto) {
+ case JUNIPER_PROTO_IPV4:
+ ip_print(ndo, p, l2info.length);
+ break;
+ case JUNIPER_PROTO_IPV6:
+ ip6_print(ndo, p, l2info.length);
+ break;
+ default:
+ if (!ndo->ndo_eflag)
+ ND_PRINT("unknown GGSN proto (%u)", proto);
+ }
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_ES
+void
+juniper_es_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+ struct juniper_ipsec_header {
+ nd_uint16_t sa_index;
+ nd_uint8_t ttl;
+ nd_uint8_t type;
+ nd_uint32_t spi;
+ nd_ipv4 src_ip;
+ nd_ipv4 dst_ip;
+ };
+ u_int rewrite_len,es_type_bundle;
+ const struct juniper_ipsec_header *ih;
+
+ ndo->ndo_protocol = "juniper_es";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_ES;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ ih = (const struct juniper_ipsec_header *)p;
+
+ ND_TCHECK_SIZE(ih);
+ switch (GET_U_1(ih->type)) {
+ case JUNIPER_IPSEC_O_ESP_ENCRYPT_ESP_AUTHEN_TYPE:
+ case JUNIPER_IPSEC_O_ESP_ENCRYPT_AH_AUTHEN_TYPE:
+ rewrite_len = 0;
+ es_type_bundle = 1;
+ break;
+ case JUNIPER_IPSEC_O_ESP_AUTHENTICATION_TYPE:
+ case JUNIPER_IPSEC_O_AH_AUTHENTICATION_TYPE:
+ case JUNIPER_IPSEC_O_ESP_ENCRYPTION_TYPE:
+ rewrite_len = 16;
+ es_type_bundle = 0;
+ break;
+ default:
+ ND_PRINT("ES Invalid type %u, length %u",
+ GET_U_1(ih->type),
+ l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ l2info.length-=rewrite_len;
+ p+=rewrite_len;
+
+ if (ndo->ndo_eflag) {
+ if (!es_type_bundle) {
+ ND_PRINT("ES SA, index %u, ttl %u type %s (%u), spi %u, Tunnel %s > %s, length %u\n",
+ GET_BE_U_2(ih->sa_index),
+ GET_U_1(ih->ttl),
+ tok2str(juniper_ipsec_type_values,"Unknown",GET_U_1(ih->type)),
+ GET_U_1(ih->type),
+ GET_BE_U_4(ih->spi),
+ GET_IPADDR_STRING(ih->src_ip),
+ GET_IPADDR_STRING(ih->dst_ip),
+ l2info.length);
+ } else {
+ ND_PRINT("ES SA, index %u, ttl %u type %s (%u), length %u\n",
+ GET_BE_U_2(ih->sa_index),
+ GET_U_1(ih->ttl),
+ tok2str(juniper_ipsec_type_values,"Unknown",GET_U_1(ih->type)),
+ GET_U_1(ih->type),
+ l2info.length);
+ }
+ }
+
+ ip_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_MONITOR
+void
+juniper_monitor_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+ struct juniper_monitor_header {
+ nd_uint8_t pkt_type;
+ nd_byte padding;
+ nd_uint16_t iif;
+ nd_uint32_t service_id;
+ };
+ const struct juniper_monitor_header *mh;
+
+ ndo->ndo_protocol = "juniper_monitor";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_MONITOR;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ mh = (const struct juniper_monitor_header *)p;
+
+ ND_TCHECK_SIZE(mh);
+ if (ndo->ndo_eflag)
+ ND_PRINT("service-id %u, iif %u, pkt-type %u: ",
+ GET_BE_U_4(mh->service_id),
+ GET_BE_U_2(mh->iif),
+ GET_U_1(mh->pkt_type));
+
+ /* no proto field - lets guess by first byte of IP header*/
+ ip_heuristic_guess (ndo, p, l2info.length);
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_SERVICES
+void
+juniper_services_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+ struct juniper_services_header {
+ nd_uint8_t svc_id;
+ nd_uint8_t flags_len;
+ nd_uint16_t svc_set_id;
+ nd_byte pad;
+ nd_uint24_t dir_iif;
+ };
+ const struct juniper_services_header *sh;
+
+ ndo->ndo_protocol = "juniper_services";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_SERVICES;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ sh = (const struct juniper_services_header *)p;
+
+ ND_TCHECK_SIZE(sh);
+ if (ndo->ndo_eflag)
+ ND_PRINT("service-id %u flags 0x%02x service-set-id 0x%04x iif %u: ",
+ GET_U_1(sh->svc_id),
+ GET_U_1(sh->flags_len),
+ GET_BE_U_2(sh->svc_set_id),
+ GET_BE_U_3(sh->dir_iif));
+
+ /* no proto field - lets guess by first byte of IP header*/
+ ip_heuristic_guess (ndo, p, l2info.length);
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_PPPOE
+void
+juniper_pppoe_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_pppoe";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_PPPOE;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ /* this DLT contains nothing but raw ethernet frames */
+ ether_print(ndo, p, l2info.length, l2info.caplen, NULL, NULL);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_ETHER
+void
+juniper_ether_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_ether";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_ETHER;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ /* this DLT contains nothing but raw Ethernet frames */
+ ndo->ndo_ll_hdr_len +=
+ l2info.header_len +
+ ether_print(ndo, p, l2info.length, l2info.caplen, NULL, NULL);
+}
+#endif
+
+#ifdef DLT_JUNIPER_PPP
+void
+juniper_ppp_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_ppp";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_PPP;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ /* this DLT contains nothing but raw ppp frames */
+ ppp_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_FRELAY
+void
+juniper_frelay_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_frelay";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_FRELAY;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ /* this DLT contains nothing but raw frame-relay frames */
+ fr_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_CHDLC
+void
+juniper_chdlc_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_chdlc";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_CHDLC;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+ /* this DLT contains nothing but raw c-hdlc frames */
+ chdlc_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_PPPOE_ATM
+void
+juniper_pppoe_atm_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+ uint16_t extracted_ethertype;
+
+ ndo->ndo_protocol = "juniper_pppoe_atm";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_PPPOE_ATM;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+
+ extracted_ethertype = GET_BE_U_2(p);
+ /* this DLT contains nothing but raw PPPoE frames,
+ * prepended with a type field*/
+ if (ethertype_print(ndo, extracted_ethertype,
+ p+ETHERTYPE_LEN,
+ l2info.length-ETHERTYPE_LEN,
+ l2info.caplen-ETHERTYPE_LEN,
+ NULL, NULL) == 0)
+ /* ether_type not known, probably it wasn't one */
+ ND_PRINT("unknown ethertype 0x%04x", extracted_ethertype);
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_MLPPP
+void
+juniper_mlppp_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_mlppp";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_MLPPP;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ /* suppress Bundle-ID if frame was captured on a child-link
+ * best indicator if the cookie looks like a proto */
+ if (ndo->ndo_eflag &&
+ /* use EXTRACT_, not GET_ (not packet buffer pointer) */
+ EXTRACT_BE_U_2(&l2info.cookie) != PPP_OSI &&
+ /* use EXTRACT_, not GET_ (not packet buffer pointer) */
+ EXTRACT_BE_U_2(&l2info.cookie) != (PPP_ADDRESS << 8 | PPP_CONTROL))
+ ND_PRINT("Bundle-ID %u: ", l2info.bundle);
+
+ p+=l2info.header_len;
+
+ /* first try the LSQ protos */
+ switch(l2info.proto) {
+ case JUNIPER_LSQ_L3_PROTO_IPV4:
+ /* IP traffic going to the RE would not have a cookie
+ * -> this must be incoming IS-IS over PPP
+ */
+ if (l2info.cookie[4] == (JUNIPER_LSQ_COOKIE_RE|JUNIPER_LSQ_COOKIE_DIR))
+ ppp_print(ndo, p, l2info.length);
+ else
+ ip_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ case JUNIPER_LSQ_L3_PROTO_IPV6:
+ ip6_print(ndo, p,l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ case JUNIPER_LSQ_L3_PROTO_MPLS:
+ mpls_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ case JUNIPER_LSQ_L3_PROTO_ISO:
+ isoclns_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ default:
+ break;
+ }
+
+ /* zero length cookie ? */
+ /* use EXTRACT_, not GET_ (not packet buffer pointer) */
+ switch (EXTRACT_BE_U_2(&l2info.cookie)) {
+ case PPP_OSI:
+ ppp_print(ndo, p - 2, l2info.length + 2);
+ break;
+ case (PPP_ADDRESS << 8 | PPP_CONTROL): /* fall through */
+ default:
+ ppp_print(ndo, p, l2info.length);
+ break;
+ }
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+
+#ifdef DLT_JUNIPER_MFR
+void
+juniper_mfr_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_mfr";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_MFR;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+
+ /* child-link ? */
+ if (l2info.cookie_len == 0) {
+ mfr_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ /* first try the LSQ protos */
+ if (l2info.cookie_len == AS_PIC_COOKIE_LEN) {
+ switch(l2info.proto) {
+ case JUNIPER_LSQ_L3_PROTO_IPV4:
+ ip_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ case JUNIPER_LSQ_L3_PROTO_IPV6:
+ ip6_print(ndo, p,l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ case JUNIPER_LSQ_L3_PROTO_MPLS:
+ mpls_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ case JUNIPER_LSQ_L3_PROTO_ISO:
+ isoclns_print(ndo, p, l2info.length);
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ default:
+ break;
+ }
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ /* suppress Bundle-ID if frame was captured on a child-link */
+ /* use EXTRACT_, not GET_ (not packet buffer pointer) */
+ if (ndo->ndo_eflag && EXTRACT_BE_U_4(l2info.cookie) != 1)
+ ND_PRINT("Bundle-ID %u, ", l2info.bundle);
+ switch (l2info.proto) {
+ case (LLCSAP_ISONS<<8 | LLCSAP_ISONS):
+ /* At least one byte is required */
+ ND_TCHECK_1(p);
+ isoclns_print(ndo, p + 1, l2info.length - 1);
+ break;
+ case (LLC_UI<<8 | NLPID_Q933):
+ case (LLC_UI<<8 | NLPID_IP):
+ case (LLC_UI<<8 | NLPID_IP6):
+ /* pass IP{4,6} to the OSI layer for proper link-layer printing */
+ isoclns_print(ndo, p - 1, l2info.length + 1);
+ break;
+ default:
+ ND_PRINT("unknown protocol 0x%04x, length %u", l2info.proto, l2info.length);
+ }
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif
+
+#ifdef DLT_JUNIPER_MLFR
+void
+juniper_mlfr_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct juniper_l2info_t l2info;
+
+ ndo->ndo_protocol = "juniper_mlfr";
+ memset(&l2info, 0, sizeof(l2info));
+ l2info.pictype = DLT_JUNIPER_MLFR;
+ if (juniper_parse_header(ndo, p, h, &l2info) == 0) {
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+ return;
+ }
+
+ p+=l2info.header_len;
+
+ /* suppress Bundle-ID if frame was captured on a child-link */
+ /* use EXTRACT_, not GET_ (not packet buffer pointer) */
+ if (ndo->ndo_eflag && EXTRACT_BE_U_4(l2info.cookie) != 1)
+ ND_PRINT("Bundle-ID %u, ", l2info.bundle);
+ switch (l2info.proto) {
+ case (LLC_UI):
+ case (LLC_UI<<8):
+ isoclns_print(ndo, p, l2info.length);
+ break;
+ case (LLC_UI<<8 | NLPID_Q933):
+ case (LLC_UI<<8 | NLPID_IP):
+ case (LLC_UI<<8 | NLPID_IP6):
+ /* pass IP{4,6} to the OSI layer for proper link-layer printing */
+ isoclns_print(ndo, p - 1, l2info.length + 1);
+ break;
+ default:
+ ND_PRINT("unknown protocol 0x%04x, length %u", l2info.proto, l2info.length);
+ }
+
+ ndo->ndo_ll_hdr_len += l2info.header_len;
+}
+#endif