| /* |
| * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * 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, (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, and (3) all advertising materials mentioning |
| * features or use of this software display the following acknowledgement: |
| * ``This product includes software developed by the University of California, |
| * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
| * the University nor the names of its contributors may be used to endorse |
| * or promote products derived from this software without specific prior |
| * written permission. |
| * 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. |
| */ |
| |
| #ifndef lint |
| static const char rcsid[] = |
| "@(#)$Header: /tcpdump/master/tcpdump/print-fr.c,v 1.14 2003-08-13 02:28:21 itojun Exp $ (LBL)"; |
| #endif |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <tcpdump-stdinc.h> |
| |
| struct mbuf; |
| struct rtentry; |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <pcap.h> |
| |
| #include "interface.h" |
| #include "addrtoname.h" |
| #include "ethertype.h" |
| #include "extract.h" |
| |
| static void q933_print(const u_char *, int); |
| |
| #define FR_CR_BIT 0x02 |
| #define FR_EA_BIT(p) ((p)&0x01) |
| #define FR_FECN 0x08 |
| #define FR_BECN 0x04 |
| #define FR_DE 0x02 |
| #define FR_DLCI(b0, b1) ((((b0)&0xFC)<<2)+(((b1)&0xF0)>>4)) |
| |
| /* find out how many bytes are there in a frame */ |
| static u_int |
| fr_addr_len(const u_char *p) |
| { |
| u_int i=0; |
| |
| while (!FR_EA_BIT(p[i]) && i++ && !FR_EA_BIT(p[i+1])) i++; |
| return (i+1); |
| } |
| |
| /* the following is for framerelay */ |
| #define NLPID_LEN 1 /* NLPID is one byte long */ |
| #define NLPID_Q933 0x08 |
| #define NLPID_LMI 0x09 |
| #define NLPID_SNAP 0x80 |
| #define NLPID_CLNP 0x81 |
| #define NLPID_ESIS 0x82 |
| #define NLPID_ISIS 0x83 |
| #define NLPID_CONS 0x84 |
| #define NLPID_IDRP 0x85 |
| #define NLPID_X25_ESIS 0x8a |
| #define NLPID_IP 0xcc |
| |
| |
| static const char *fr_nlpids[256]; |
| |
| static void |
| init_fr_nlpids(void) |
| { |
| int i; |
| static int fr_nlpid_flag = 0; |
| |
| if (!fr_nlpid_flag) { |
| for (i=0; i < 256; i++) |
| fr_nlpids[i] = NULL; |
| fr_nlpids[NLPID_Q933] = "Q.933"; |
| fr_nlpids[NLPID_LMI] = "LMI"; |
| fr_nlpids[NLPID_SNAP] = "SNAP"; |
| fr_nlpids[NLPID_CLNP] = "CLNP"; |
| fr_nlpids[NLPID_ESIS] = "ESIS"; |
| fr_nlpids[NLPID_ISIS] = "ISIS"; |
| fr_nlpids[NLPID_CONS] = "CONS"; |
| fr_nlpids[NLPID_IDRP] = "IDRP"; |
| fr_nlpids[NLPID_X25_ESIS] = "X25_ESIS"; |
| fr_nlpids[NLPID_IP] = "IP"; |
| } |
| fr_nlpid_flag = 1; |
| } |
| |
| /* Framerelay packet structure */ |
| |
| /* |
| +---------------------------+ |
| | flag (7E hexadecimal) | |
| +---------------------------+ |
| | Q.922 Address* | |
| +-- --+ |
| | | |
| +---------------------------+ |
| | Control (UI = 0x03) | |
| +---------------------------+ |
| | Optional Pad (0x00) | |
| +---------------------------+ |
| | NLPID | |
| +---------------------------+ |
| | . | |
| | . | |
| | . | |
| | Data | |
| | . | |
| | . | |
| +---------------------------+ |
| | Frame Check Sequence | |
| +-- . --+ |
| | (two octets) | |
| +---------------------------+ |
| | flag (7E hexadecimal) | |
| +---------------------------+ |
| |
| * Q.922 addresses, as presently defined, are two octets and |
| contain a 10-bit DLCI. In some networks Q.922 addresses |
| may optionally be increased to three or four octets. |
| |
| */ |
| |
| #define FR_PROTOCOL(p) fr_protocol((p)) |
| |
| static u_int |
| fr_hdrlen(const u_char *p) |
| { |
| u_int hlen; |
| hlen = fr_addr_len(p)+1; /* addr_len + 0x03 + padding */ |
| if (p[hlen]) |
| return hlen; |
| else |
| return hlen+1; |
| } |
| |
| #define LAYER2_LEN(p) (fr_hdrlen((p))+NLPID_LEN) |
| |
| static int |
| fr_protocol(const u_char *p) |
| { |
| int hlen; |
| |
| hlen = fr_addr_len(p) + 1; |
| if (p[hlen]) /* check for padding */ |
| return p[hlen]; |
| else |
| return p[hlen+1]; |
| } |
| |
| static char * |
| fr_flags(const u_char *p) |
| { |
| static char flags[1+1+4+1+4+1+2+1]; |
| |
| if (p[0] & FR_CR_BIT) |
| strlcpy(flags, "C", sizeof(flags)); |
| else |
| strlcpy(flags, "R", sizeof(flags)); |
| if (p[1] & FR_FECN) |
| strlcat(flags, ",FECN", sizeof(flags)); |
| if (p[1] & FR_BECN) |
| strlcat(flags, ",BECN", sizeof(flags)); |
| if (p[1] & FR_DE) |
| strlcat(flags, ",DE", sizeof(flags)); |
| return flags; |
| } |
| |
| static const char * |
| fr_protostring(u_int8_t proto) |
| { |
| static char buf[5+1+2+1]; |
| |
| if (nflag || fr_nlpids[proto] == NULL) { |
| snprintf(buf, sizeof(buf), "proto-%02x", proto); |
| return buf; |
| } |
| return fr_nlpids[proto]; |
| } |
| |
| static void |
| fr_hdr_print(const u_char *p, int length) |
| { |
| u_int8_t proto; |
| |
| proto = FR_PROTOCOL(p); |
| |
| init_fr_nlpids(); |
| /* this is kinda kludge since it assumed that DLCI is two bytes. */ |
| if (qflag) |
| (void)printf("DLCI-%u-%s %d: ", |
| FR_DLCI(p[0], p[1]), fr_flags(p), length); |
| else |
| (void)printf("DLCI-%u-%s %s %d: ", |
| FR_DLCI(p[0], p[1]), fr_flags(p), |
| fr_protostring(proto), length); |
| } |
| |
| u_int |
| fr_if_print(const struct pcap_pkthdr *h, register const u_char *p) |
| { |
| register u_int length = h->len; |
| register u_int caplen = h->caplen; |
| u_char protocol; |
| int layer2_len; |
| u_short extracted_ethertype; |
| u_int32_t orgcode; |
| register u_short et; |
| |
| if (caplen < fr_hdrlen(p)) { |
| printf("[|fr]"); |
| return (caplen); |
| } |
| |
| if (eflag) |
| fr_hdr_print(p, length); |
| |
| protocol = FR_PROTOCOL(p); |
| layer2_len = LAYER2_LEN(p); |
| p += layer2_len; |
| length -= layer2_len; |
| caplen -= layer2_len; |
| |
| switch (protocol) { |
| |
| case NLPID_IP: |
| ip_print(p, length); |
| break; |
| |
| case NLPID_CLNP: |
| case NLPID_ESIS: |
| case NLPID_ISIS: |
| isoclns_print(p, length, caplen); |
| break; |
| |
| case NLPID_SNAP: |
| orgcode = EXTRACT_24BITS(p); |
| et = EXTRACT_16BITS(p + 3); |
| if (snap_print((const u_char *)(p + 5), length - 5, |
| caplen - 5, &extracted_ethertype, orgcode, et, |
| 0) == 0) { |
| /* ether_type not known, print raw packet */ |
| if (!eflag) |
| fr_hdr_print(p - layer2_len, length + layer2_len); |
| if (extracted_ethertype) { |
| printf("(SNAP %s) ", |
| etherproto_string(htons(extracted_ethertype))); |
| } |
| if (!xflag && !qflag) |
| default_print(p - layer2_len, caplen + layer2_len); |
| } |
| break; |
| |
| case NLPID_Q933: |
| q933_print(p, length); |
| break; |
| |
| default: |
| if (!eflag) |
| fr_hdr_print(p - layer2_len, length + layer2_len); |
| if (!xflag) |
| default_print(p, caplen); |
| } |
| |
| return (layer2_len); |
| } |
| |
| /* |
| * Q.933 decoding portion for framerelay specific. |
| */ |
| |
| /* Q.933 packet format |
| Format of Other Protocols |
| using Q.933 NLPID |
| +-------------------------------+ |
| | Q.922 Address | |
| +---------------+---------------+ |
| |Control 0x03 | NLPID 0x08 | |
| +---------------+---------------+ |
| | L2 Protocol ID | |
| | octet 1 | octet 2 | |
| +-------------------------------+ |
| | L3 Protocol ID | |
| | octet 2 | octet 2 | |
| +-------------------------------+ |
| | Protocol Data | |
| +-------------------------------+ |
| | FCS | |
| +-------------------------------+ |
| */ |
| |
| /* L2 (Octet 1)- Call Reference Usually is 0x0 */ |
| |
| /* |
| * L2 (Octet 2)- Message Types definition 1 byte long. |
| */ |
| /* Call Establish */ |
| #define MSG_TYPE_ESC_TO_NATIONAL 0x00 |
| #define MSG_TYPE_ALERT 0x01 |
| #define MSG_TYPE_CALL_PROCEEDING 0x02 |
| #define MSG_TYPE_CONNECT 0x07 |
| #define MSG_TYPE_CONNECT_ACK 0x0F |
| #define MSG_TYPE_PROGRESS 0x03 |
| #define MSG_TYPE_SETUP 0x05 |
| /* Call Clear */ |
| #define MSG_TYPE_DISCONNECT 0x45 |
| #define MSG_TYPE_RELEASE 0x4D |
| #define MSG_TYPE_RELEASE_COMPLETE 0x5A |
| #define MSG_TYPE_RESTART 0x46 |
| #define MSG_TYPE_RESTART_ACK 0x4E |
| /* Status */ |
| #define MSG_TYPE_STATUS 0x7D |
| #define MSG_TYPE_STATUS_ENQ 0x75 |
| |
| #define ONE_BYTE_IE_MASK 0xF0 |
| |
| /* See L2 protocol ID picture above */ |
| struct q933_header { |
| u_int8_t call_ref; /* usually is 0 for framerelay PVC */ |
| u_int8_t msg_type; |
| }; |
| |
| #define REPORT_TYPE_IE 0x01 |
| #define LINK_VERIFY_IE_91 0x19 |
| #define LINK_VERIFY_IE_94 0x03 |
| #define PVC_STATUS_IE 0x07 |
| |
| #define MAX_IE_SIZE |
| |
| struct common_ie_header { |
| u_int8_t ie_id; |
| u_int8_t ie_len; |
| }; |
| |
| #define FULL_STATUS 0 |
| #define LINK_VERIFY 1 |
| #define ASYNC_PVC 2 |
| |
| static void |
| q933_print(const u_char *p, int length) |
| { |
| struct q933_header *header = (struct q933_header *)(p+1); |
| const u_char *ptemp = p; |
| int ie_len; |
| const char *decode_str; |
| char temp_str[255]; |
| struct common_ie_header *ie_p; |
| |
| /* printing out header part */ |
| printf("Call Ref: %02x, MSG Type: %02x", |
| header->call_ref, header->msg_type); |
| switch(header->msg_type) { |
| case MSG_TYPE_STATUS: |
| decode_str = "STATUS REPLY"; |
| break; |
| case MSG_TYPE_STATUS_ENQ: |
| decode_str = "STATUS ENQUIRY"; |
| break; |
| default: |
| decode_str = "UNKNOWN MSG Type"; |
| } |
| printf(" %s\n", decode_str); |
| |
| length = length - 3; |
| ptemp = ptemp + 3; |
| |
| /* Loop through the rest of IE */ |
| while( length > 0 ) { |
| if (ptemp[0] & ONE_BYTE_IE_MASK) { |
| ie_len = 1; |
| printf("\t\tOne byte IE: %02x, Content %02x\n", |
| (*ptemp & 0x70)>>4, (*ptemp & 0x0F)); |
| length--; |
| ptemp++; |
| } |
| else { /* Multi-byte IE */ |
| ie_p = (struct common_ie_header *)ptemp; |
| switch (ie_p->ie_id) { |
| case REPORT_TYPE_IE: |
| switch(ptemp[2]) { |
| case FULL_STATUS: |
| decode_str = "FULL STATUS"; |
| break; |
| case LINK_VERIFY: |
| decode_str = "LINK VERIFY"; |
| break; |
| case ASYNC_PVC: |
| decode_str = "Async PVC Status"; |
| break; |
| default: |
| decode_str = "Reserved Value"; |
| } |
| break; |
| case LINK_VERIFY_IE_91: |
| case LINK_VERIFY_IE_94: |
| snprintf(temp_str, sizeof (temp_str), "TX Seq: %3d, RX Seq: %3d", |
| ptemp[2], ptemp[3]); |
| decode_str = temp_str; |
| break; |
| case PVC_STATUS_IE: |
| snprintf(temp_str, sizeof (temp_str), "DLCI %d: status %s %s", |
| ((ptemp[2]&0x3f)<<4)+ ((ptemp[3]&0x78)>>3), |
| ptemp[4] & 0x8 ?"new,":" ", |
| ptemp[4] & 0x2 ?"Active":"Inactive"); |
| break; |
| default: |
| decode_str = "Non-decoded Value"; |
| } |
| printf("\t\tIE: %02X Len: %d, %s\n", |
| ie_p->ie_id, ie_p->ie_len, decode_str); |
| length = length - ie_p->ie_len - 2; |
| ptemp = ptemp + ie_p->ie_len + 2; |
| } |
| } |
| } |