| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that: (1) source code |
| * distributions retain the above copyright notice and this paragraph |
| * in its entirety, and (2) distributions including binary code include |
| * the above copyright notice and this paragraph in its entirety in |
| * the documentation or other materials provided with the distribution. |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND |
| * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT |
| * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE. |
| * |
| * Original code by Hannes Gredler (hannes@juniper.net) |
| */ |
| |
| #ifndef lint |
| static const char rcsid[] _U_ = |
| "@(#) $Header: /tcpdump/master/tcpdump/print-juniper.c,v 1.8 2005-04-06 21:32:41 mcr Exp $ (LBL)"; |
| #endif |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <tcpdump-stdinc.h> |
| |
| #include <pcap.h> |
| #include <stdio.h> |
| |
| #include "interface.h" |
| #include "extract.h" |
| #include "ppp.h" |
| #include "llc.h" |
| #include "nlpid.h" |
| |
| #define JUNIPER_BPF_OUT 0 /* Outgoing packet */ |
| #define JUNIPER_BPF_IN 1 /* Incoming packet */ |
| #define JUNIPER_BPF_PKT_IN 0x1 /* Incoming packet */ |
| #define JUNIPER_BPF_NO_L2 0x2 /* L2 header stripped */ |
| |
| #define LS_COOKIE_ID 0x54 |
| #define LS_MLFR_LEN 4 |
| #define ML_MLFR_LEN 2 |
| |
| #define ATM2_PKT_TYPE_MASK 0x70 |
| #define ATM2_GAP_COUNT_MASK 0x3F |
| |
| int ip_heuristic_guess(register const u_char *, u_int); |
| int juniper_ppp_heuristic_guess(register const u_char *, u_int); |
| static int juniper_parse_header (const u_char *, u_int8_t *, u_int); |
| |
| u_int |
| juniper_mlppp_print(const struct pcap_pkthdr *h, register const u_char *p) |
| { |
| register u_int length = h->len; |
| register u_int caplen = h->caplen; |
| u_int8_t direction,bundle,cookie_len; |
| u_int32_t cookie,proto; |
| |
| if(juniper_parse_header(p, &direction,length) == 0) |
| return 0; |
| |
| p+=4; |
| length-=4; |
| caplen-=4; |
| |
| if (p[0] == LS_COOKIE_ID) { |
| cookie=EXTRACT_32BITS(p); |
| if (eflag) printf("LSPIC-MLPPP cookie 0x%08x, ",cookie); |
| cookie_len = LS_MLFR_LEN; |
| bundle = cookie & 0xff; |
| } else { |
| cookie=EXTRACT_16BITS(p); |
| if (eflag) printf("MLPIC-MLPPP cookie 0x%04x, ",cookie); |
| cookie_len = ML_MLFR_LEN; |
| bundle = (cookie >> 8) & 0xff; |
| } |
| |
| proto = EXTRACT_16BITS(p+cookie_len); |
| p += cookie_len; |
| length-= cookie_len; |
| caplen-= cookie_len; |
| |
| /* suppress Bundle-ID if frame was captured on a child-link |
| * this may be the case if the cookie looks like a proto */ |
| if (eflag && |
| cookie != PPP_OSI && |
| cookie != (PPP_ADDRESS << 8 | PPP_CONTROL)) |
| printf("Bundle-ID %u, ",bundle); |
| |
| switch (cookie) { |
| case PPP_OSI: |
| ppp_print(p-2,length+2); |
| break; |
| case (PPP_ADDRESS << 8 | PPP_CONTROL): /* fall through */ |
| default: |
| ppp_print(p,length); |
| break; |
| } |
| |
| return cookie_len; |
| } |
| |
| |
| u_int |
| juniper_mlfr_print(const struct pcap_pkthdr *h, register const u_char *p) |
| { |
| register u_int length = h->len; |
| register u_int caplen = h->caplen; |
| u_int8_t direction,bundle,cookie_len; |
| u_int32_t cookie,proto,frelay_len = 0; |
| |
| if(juniper_parse_header(p, &direction,length) == 0) |
| return 0; |
| |
| p+=4; |
| length-=4; |
| caplen-=4; |
| |
| if (p[0] == LS_COOKIE_ID) { |
| cookie=EXTRACT_32BITS(p); |
| if (eflag) printf("LSPIC-MLFR cookie 0x%08x, ",cookie); |
| cookie_len = LS_MLFR_LEN; |
| bundle = cookie & 0xff; |
| } else { |
| cookie=EXTRACT_16BITS(p); |
| if (eflag) printf("MLPIC-MLFR cookie 0x%04x, ",cookie); |
| cookie_len = ML_MLFR_LEN; |
| bundle = (cookie >> 8) & 0xff; |
| } |
| |
| proto = EXTRACT_16BITS(p+cookie_len); |
| p += cookie_len+2; |
| length-= cookie_len+2; |
| caplen-= cookie_len+2; |
| |
| /* suppress Bundle-ID if frame was captured on a child-link */ |
| if (eflag && cookie != 1) printf("Bundle-ID %u, ",bundle); |
| |
| switch (proto) { |
| case (LLC_UI): |
| case (LLC_UI<<8): |
| isoclns_print(p, length, caplen); |
| break; |
| case (LLC_UI<<8 | NLPID_Q933): |
| case (LLC_UI<<8 | NLPID_IP): |
| case (LLC_UI<<8 | NLPID_IP6): |
| isoclns_print(p-1, length+1, caplen+1); /* pass IP{4,6} to the OSI layer for proper link-layer printing */ |
| break; |
| default: |
| printf("unknown protocol 0x%04x, length %u",proto, length); |
| } |
| |
| return cookie_len + frelay_len; |
| } |
| |
| /* |
| * ATM1 PIC cookie format |
| * |
| * +-----+-------------------------+-------------------------------+ |
| * |fmtid| vc index | channel ID | |
| * +-----+-------------------------+-------------------------------+ |
| */ |
| |
| u_int |
| juniper_atm1_print(const struct pcap_pkthdr *h, register const u_char *p) |
| { |
| register u_int length = h->len; |
| register u_int caplen = h->caplen; |
| u_int16_t extracted_ethertype; |
| u_int8_t direction; |
| u_int32_t cookie1; |
| |
| if(juniper_parse_header(p, &direction,length) == 0) |
| return 0; |
| |
| p+=4; |
| length-=4; |
| caplen-=4; |
| |
| cookie1=EXTRACT_32BITS(p); |
| |
| if (eflag) { |
| /* FIXME decode channel-id, vc-index, fmt-id |
| for once lets just hexdump the cookie */ |
| |
| printf("ATM1 cookie 0x%08x, ", cookie1); |
| } |
| |
| p+=4; |
| length-=4; |
| caplen-=4; |
| |
| if ((cookie1 >> 24) == 0x80) { /* OAM cell ? */ |
| oam_print(p,length); |
| return 0; |
| } |
| |
| if (EXTRACT_24BITS(p) == 0xfefe03 || /* NLPID encaps ? */ |
| EXTRACT_24BITS(p) == 0xaaaa03) { /* SNAP encaps ? */ |
| |
| if (llc_print(p, length, caplen, NULL, NULL, |
| &extracted_ethertype) != 0) |
| return 8; |
| } |
| |
| if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */ |
| isoclns_print(p + 1, length - 1, caplen - 1); |
| /* FIXME check if frame was recognized */ |
| return 8; |
| } |
| |
| if(ip_heuristic_guess(p, length) != 0) /* last try - vcmux encaps ? */ |
| return 0; |
| |
| return (8); |
| } |
| |
| /* |
| * ATM2 PIC cookie format |
| * |
| * +-------------------------------+---------+---+-----+-----------+ |
| * | channel ID | reserv |AAL| CCRQ| gap cnt | |
| * +-------------------------------+---------+---+-----+-----------+ |
| */ |
| |
| u_int |
| juniper_atm2_print(const struct pcap_pkthdr *h, register const u_char *p) |
| { |
| register u_int length = h->len; |
| register u_int caplen = h->caplen; |
| u_int16_t extracted_ethertype; |
| u_int8_t direction; |
| u_int32_t cookie1,cookie2; |
| |
| if(juniper_parse_header(p, &direction,length) == 0) |
| return 0; |
| |
| p+=4; |
| length-=4; |
| caplen-=4; |
| |
| cookie1=EXTRACT_32BITS(p); |
| cookie2=EXTRACT_32BITS(p+4); |
| |
| if (eflag) { |
| /* FIXME decode channel, fmt-id, ccrq, aal, gap cnt |
| for once lets just hexdump the cookie */ |
| |
| printf("ATM2 cookie 0x%08x%08x, ", |
| EXTRACT_32BITS(p), |
| EXTRACT_32BITS(p+4)); |
| } |
| |
| p+=8; |
| length-=8; |
| caplen-=8; |
| |
| if (cookie2 & ATM2_PKT_TYPE_MASK) { /* OAM cell ? */ |
| oam_print(p,length); |
| return 12; |
| } |
| |
| if (EXTRACT_24BITS(p) == 0xfefe03 || /* NLPID encaps ? */ |
| EXTRACT_24BITS(p) == 0xaaaa03) { /* SNAP encaps ? */ |
| |
| if (llc_print(p, length, caplen, NULL, NULL, |
| &extracted_ethertype) != 0) |
| return 12; |
| } |
| |
| if (direction != JUNIPER_BPF_PKT_IN && /* ether-over-1483 encaps ? */ |
| (cookie1 & ATM2_GAP_COUNT_MASK)) { |
| ether_print(p, length, caplen); |
| return 12; |
| } |
| |
| if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */ |
| isoclns_print(p + 1, length - 1, caplen - 1); |
| /* FIXME check if frame was recognized */ |
| return 12; |
| } |
| |
| if(juniper_ppp_heuristic_guess(p, length) != 0) /* PPPoA vcmux encaps ? */ |
| return 12; |
| |
| if(ip_heuristic_guess(p, length) != 0) /* last try - vcmux encaps ? */ |
| return 12; |
| |
| return (12); |
| } |
| |
| |
| /* try to guess, based on all PPP protos that are supported in |
| * a juniper router if the payload data is encapsulated using PPP */ |
| int |
| juniper_ppp_heuristic_guess(register const u_char *p, u_int length) { |
| |
| switch(EXTRACT_16BITS(p)) { |
| case PPP_IP : |
| case PPP_OSI : |
| case PPP_MPLS_UCAST : |
| case PPP_MPLS_MCAST : |
| case PPP_IPCP : |
| case PPP_OSICP : |
| case PPP_MPLSCP : |
| case PPP_LCP : |
| case PPP_PAP : |
| case PPP_CHAP : |
| case PPP_ML : |
| #ifdef INET6 |
| case PPP_IPV6 : |
| case PPP_IPV6CP : |
| #endif |
| ppp_print(p, length); |
| break; |
| |
| default: |
| return 0; /* did not find a ppp header */ |
| break; |
| } |
| return 1; /* we printed a ppp packet */ |
| } |
| |
| int |
| ip_heuristic_guess(register const u_char *p, u_int length) { |
| |
| switch(p[0]) { |
| case 0x45: |
| case 0x46: |
| case 0x47: |
| case 0x48: |
| case 0x49: |
| case 0x4a: |
| case 0x4b: |
| case 0x4c: |
| case 0x4d: |
| case 0x4e: |
| case 0x4f: |
| ip_print(gndo, p, length); |
| break; |
| #ifdef INET6 |
| case 0x60: |
| case 0x61: |
| case 0x62: |
| case 0x63: |
| case 0x64: |
| case 0x65: |
| case 0x66: |
| case 0x67: |
| case 0x68: |
| case 0x69: |
| case 0x6a: |
| case 0x6b: |
| case 0x6c: |
| case 0x6d: |
| case 0x6e: |
| case 0x6f: |
| ip6_print(p, length); |
| break; |
| #endif |
| default: |
| return 0; /* did not find a ip header */ |
| break; |
| } |
| return 1; /* we printed an v4/v6 packet */ |
| } |
| |
| static int |
| juniper_parse_header (const u_char *p, u_int8_t *direction, u_int length) { |
| |
| *direction = p[3]&JUNIPER_BPF_PKT_IN; |
| |
| if (EXTRACT_24BITS(p) != 0x4d4743) /* magic number found ? */ |
| return -1; |
| |
| if (*direction == JUNIPER_BPF_PKT_IN) { |
| if (eflag) |
| printf("%3s ", "In"); |
| } |
| else { |
| if (eflag) |
| printf("%3s ", "Out"); |
| } |
| |
| if ((p[3] & JUNIPER_BPF_NO_L2 ) == JUNIPER_BPF_NO_L2 ) { |
| if (eflag) |
| printf("no-L2-hdr, "); |
| |
| /* there is no link-layer present - |
| * perform the v4/v6 heuristics |
| * to figure out what it is |
| */ |
| if(ip_heuristic_guess(p+8,length-8) == 0) |
| printf("no IP-hdr found!"); |
| |
| return 0; /* stop parsing the output further */ |
| |
| } |
| return 1; /* everything went ok so far. continue parsing */ |
| } |
| |
| |
| /* |
| * Local Variables: |
| * c-style: whitesmith |
| * c-basic-offset: 8 |
| * End: |
| */ |