/* Compare this utility with atmdump, tcpdump or ethereal */ /* Clive Nicolson clive@baby.bedroom.gen.nz 20040623 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* NLPID for packet encapsulation (ISO/IEC TR 9577) */ #define NLPID_0 0x00 /* SNAP too? */ #define NLPID_LMI 0x08 /* ANSI T1.617 Annex D, ITU-T Q.933 Annex A */ #define NLPID_CISCO_LMI 0x09 /* */ #define NLPID_SNAP 0x80 /* IEEE Subnetwork Access Protocol */ #define NLPID_CLNP 0x81 /* ISO/IEC 8473 */ #define NLPID_ESIS 0x82 /* ISO/IEC 9542 */ #define NLPID_ISIS 0x83 /* ISO/IEC ISIS */ #define NLPID_CONS 0x84 /* */ #define NLPID_IDRP 0x85 /* */ #define NLPID_X25_ESIS 0x8A /* */ #define NLPID_IPV6 0x8E /* */ #define NLPID_IP 0xCC /* Internet Protocol Datagram */ #define NLPID_ETHERTYPE 0xCE /* */ #define NLPID_PPP 0xCF /* */ #include #define default_addr "0.0.101" #define MAX_SDU 1500 /*1524*/ /* ::= LOOP| PUP| PUPAT| IP| X25| ARP| BPQ| IEEEPUP| IEEEPUPAT| DEC| DNA_DL| DNA_RC| DNA_RT| LAT| DIAG| CUST| SCA| RARP| ATALK| AARP| IPX| IPV6| PPP_DISC| PPP_SES| ATMMPOA| ATMFATE ::= ROUTED BRIDGED [VPN] {802.3|...|BPDU} [FCS] ::= NULL|SNAP |CLNP|ESIS|ISIS|IP|PPP|ETHERTYPE |... ::= [AAL5] {LLC|VC} NLPID SNAP ::= [[[]]] */ /* Examples: The main ones that work! Defaults=>ping,pppoe discovery and ppp config. ./pokeatm -e"LLC SNAP ROUTED IP" -sbaby.bedroom.gen.nz -d2.3.4.5 0.1.101 ./pokeatm -e"LLC SNAP BRIDGED 802.3 PPP_DISC" -S1.2.3.4.5.6 0.2.40 ./pokeatm -e"LLC NLPID PPP" ./pokeatm -e"VC SNAP ROUTED IP" -sbaby.bedroom.gen.nz -d2.3.4.5 ./pokeatm -e"VC SNAP BRIDGED 802.3 PPP_DISC" ./pokeatm -e"VC NLPID PPP" Ie: [clive@gateway adsl]$ ./pokeatm -e"LLC NLPID PPP" 0.100 Communicating AAL5 over ATM 0.0.100 "LLC NLPID PPP" writing stuff fe fe 03 cf c0 21 01 01 00 11 05 06 00 cd 3c a2 07 02 08 02 0d 03 06 sent 23 (padded to 48) reading stuff revcd 24 fe fe 03 cf c0 21 01 94 00 12 01 04 23 da 03 04 c0 23 05 06 73 0e e2 ae [clive@gateway adsl]$ ./pokeatm -e"VC NLPID PPP" 0.100 Communicating AAL5 over ATM 0.0.100 "VC NLPID PPP" writing stuff c0 21 01 01 00 11 05 06 00 cd 3c a2 07 02 08 02 0d 03 06 sent 19 (padded to 48) reading stuff revcd 20 c0 21 01 19 00 12 01 04 23 da 03 04 c0 23 05 06 48 f6 1a b9 */ /* NLPID Q922 (=>A,A,[A,A]$03), ;PDU FR (=>$04$01$03), ;PDU,CRC LLC,NLPID (=>$FE$FE$03),0x00 (Null) ;PDU 0x80 (SNAP) 0x81 (ISO CLNP) 0x82 (ISO ESIS) 0x83 (ISO ISIS) 0xCC (IP) 0xCE (Ethertype) 0xXX 0xXX 0xCF (PPP) SNAP (=>$AA$AA$03),Routed EtherType (=>$00$00$00),$08$00 (IP);PDU $08$06 (ARP) $60$03 (DecNet) $81$37 (IPX) $80$9B (AppleTalk) Bridged 802.1 (=>$00$80$C2),$00$01 (802.3-FCS) $00$07 (802.3) $00$02 (802.4-FCS) $00$08 (802.4) $00$03 (802.5-FCS) $00$09 (802.5) $00$04 (FDDI-FCS) $00$0A (FDDI) $00$05 (802.6-FCS) $00$0B (802.6) $00$06 (-FCS) $00$0C (-) $00$0D (Frags) $00$0E (BPDU's) VPN Bridged (=>$00$00$5E),$00$01 (802.3-FCS) (=>$08$00$07),$80$9b (AppleTalk) VC ;PDU VC-FUNI (=>$84$01),------------------;PDU,CRC */ /* Spanning tree hello: VCD:0x3 VPI:0x1 VCI:0x32 DM:0x0 SAP:AAAA CTL:03 OUI:0080C2 TYPE:000E Length:0x2F 0000 0000 0080 0000 000C 99F7 1800 0000 0080 0000 000C 99F7 1880 1200 0014 0002 000F 0043 */ /* Use a PPP Configure-Request packet to trigger PPP traffic */ static const char ppp_config[] = { 0xc0, 0x21, /* Protocol, =>LCP */ 0x01, /* Code, 1=>Configure-Request */ 0x01, /* ID */ 0x00, 0x11, /* Length */ 0x05, /* Type, option 5 (Magic Number) for protocol C021 */ 0x06, /* Len */ 0x00, 0xcd, 0x3c, 0xa2, /* The Magic Number */ 0x07, /* Protocol Field Compression */ 0x02, /* Len */ 0x08, /* Address and Control Field Compression */ 0x02, /* Len */ 0x0d, /* Callback */ 0x03, /* Len */ 0x06, /* Operation, 6=>Use Microsoft CBCP */ /* Len = 0x00 0x11, to here */ #if 0 0x00, 0x00, 0x00, 0x00, 0x00 #endif }; static const char *D_opt,*d_opt,*S_opt,*s_opt,*V_opt,*v_opt; // CRC32 Lookup Table generated from Charles Michael // Heard's CRC-32 code static u_int32_t crc32_tbl[256] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; /****************************************************************************** FUNCTION NAME: FrameALAALCalcCRC32 ABSTRACT: Calculates a CRC32 value on the data referenced by the Buffer Descriptor DETAILS: This function is called to calculate a CRC32 value on the data passed to this function. The CRC32 value is calculated using an algorithm developed by Charles Michael Heard. The original source code for this algorithm was found at the following URL: http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/32bitCRC.c.html ******************************************************************************/ static u_int32_t CalcCRC32( const u_int8_t *pData, u_int32_t Length, u_int32_t InitialValue ) { const u_int8_t *buffer_data_ptr = pData; u_int32_t buffer_data_len = Length; u_int32_t crc32_val = InitialValue; // Calculate a CRC32 value while (buffer_data_len--) { crc32_val = (crc32_val << 8) ^ crc32_tbl[((crc32_val >> 24) ^ *buffer_data_ptr++) & 0xff]; } return crc32_val; } struct sockaddr_atmpvc addr; struct atm_qos qos; static int pti = -1,gfc = 0,clp = 0; static size_t get_len(const struct iovec *vec, int count) { int i; size_t len = 0; for (i = 0; i < count; i++) len += vec[i].iov_len; return len; } static u_int32_t build_hdr(void) { return (gfc << ATM_HDR_GFC_SHIFT) | (addr.sap_addr.vpi << ATM_HDR_VPI_SHIFT) | (addr.sap_addr.vci << ATM_HDR_VCI_SHIFT) | (pti << ATM_HDR_PTI_SHIFT) | clp; } typedef u_int32_t sdu53[(ATM_CELL_SIZE-1)/sizeof(u_int32_t)]; static ssize_t my_writev(int fd, const struct iovec *vec, int count, int sdu1) { ssize_t res; size_t len; u_int8_t *s; if (count > 1) { int i; u_int8_t *my_s; len = get_len(vec, count); s = malloc(len); my_s = s; for (i = 0; i < count; i++) { memcpy(my_s, vec[i].iov_base, vec[i].iov_len); my_s += vec[i].iov_len; } } else { len = (count <= 0) ? 0 : vec[0].iov_len; s = vec[0].iov_base; } if (qos.aal == ATM_AAL0) { size_t my_len = ATM_CELL_PAYLOAD; u_int8_t *my_s = s; sdu53 b; b[0] = build_hdr(); for (; len; len -= my_len) { if (len <= ATM_CELL_PAYLOAD) { if (sdu1) b[0] |= ATM_PTI_US1 << ATM_HDR_PTI_SHIFT; my_len = len; if (0) memset(((u_int8_t *)(b+1))+my_len, 0x56, ATM_CELL_PAYLOAD-my_len); } memcpy(b+1, my_s, my_len); my_s += my_len; res = write(fd, b, ATM_CELL_SIZE-1); if (res < 0) break; } } else res = write(fd, s, len); if (s != vec[0].iov_base) free(s); return res; } static u_int16_t csum_partial(void *buffer, unsigned int len, u_int16_t prevsum) { u_int32_t sum = prevsum; u_int16_t *ptr = buffer; while (len > 1) { sum += *ptr++; len -= 2; } if (len) { union { u_int8_t byte; u_int16_t wyde; } odd; odd.wyde = 0; odd.byte = *((u_int8_t *)ptr); sum += odd.wyde; } sum = (sum >> 16) + (sum & 0xFFFF); return sum + (sum >> 16); } static int setxxx(void *d,int nn,const char *cp) { u_int8_t *a = d; int i; for (i = 0; (i < nn) && isdigit(*cp);) { u_int32_t val = 0; int base = 10; if (*cp == '0') { cp++; if (*cp == 'x' || *cp == 'X') cp++, base = 16; else base = 8; } for (;;) { if (isascii(*cp) && isdigit(*cp)) { val = (val * base) + (*cp - '0'); cp++; } else if (base == 16 && isascii(*cp) && isxdigit(*cp)) { val = (val << 4) | (*cp + 10 - (islower(*cp) ? 'a' : 'A')); cp++; } else break; } a[i++] = val; if (*cp == '.') cp++; else break; } for (;isa_family = hp->h_addrtype; if (hp->h_length > (int)sizeof(a->sa_data)) hp->h_length = sizeof(a->sa_data); memcpy(&a->sa_data, hp->h_addr, hp->h_length); return 1; } return setxxx(a->sa_data,sizeof(a->sa_data),cp); } static void my_setsockaddr(struct sockaddr *a,sa_family_t af,const char *cp) { if (!setsockaddr(a,af,cp)) { fprintf(stderr, "pokeatm: bad address %s\n", cp); exit(2); } } static void my_setxxx(void *d,int nn,const char *cp) { if (!setxxx(d,nn,cp)) { fprintf(stderr, "pokeatm: bad number %s\n", cp); exit(2); } } /* dsap and ssap: (Link Service Access Point) LSAP Description --- ----------- 0x00 Null LSAP 0x02 Indiv LLC Sublayer Mgt 0x03 Group LLC Sublayer Mgt 0x04 SNA Path Control 0x06 Reserved (DOD IP) 0x0e PROWAY-LAN 0x4e EIA-RS 511 0x5e ISI IP 0x8e PROWAY-LAN 0xaa SNAP 0xfe ISO DIS 8473 0xff Global DSAP */ struct llc { u_int8_t dsap; u_int8_t ssap; u_int8_t ctrl; }; typedef u_int8_t two[2]; typedef u_int8_t oui[3]; static const char *l0[] = {"AAL5",NULL}; static const char *l1[] = {"LLC","VC",NULL}; static enum p1e {LLC,VC,MAX_P1} p1; static const char *l2[] = {"NLPID","SNAP",NULL}; static enum p2e {NLPID,SNAP,MAX_P2} p2; static struct llc nlpid = {0xFE,0xFE,0x03}; static struct llc snap = {0xAA,0xAA,0x03}; static const char *ll3[] = {"ROUTED","BRIDGED",NULL}; static enum pp3e {ROUTED,BRIDGED,MAX_PP3} pp3; static const char *l7[] = {"VPN",NULL}; static enum p7e {VPN,MAX_P7} p7; static oui oui_atm = {0x00,0xa0,0x3e}; static oui oui_epfl = {0x00,0x60,0xd7}; static oui snap_routed = {0x00,0x00,0x00}; static oui snap_bridged = {0x00,0x80,0xC2}; static oui snap_bridged_vpn = {0x00,0x00,0x5E}; static const char *nlpid_types[] = {"NULL","SNAP","CLNP","ESIS","ISIS","IP", "ETHERTYPE","PPP","LMI",NULL}; static enum p3e {NULL_1,SNAP_2,CLNP,ESIS,ISIS,IP_1, ETHERTYPE,PPP,LMI,MAX_P3} p3; static u_int8_t nlpid_[] = {NLPID_0, NLPID_SNAP, NLPID_CLNP, NLPID_ESIS, NLPID_ISIS, NLPID_IP, NLPID_ETHERTYPE, NLPID_PPP, NLPID_LMI}; /* Note some of these are routed, others are bridged */ static const char *ether_types[] = {"LOOP", "PUP", "PUPAT", "IP", "X25", "ARP", "BPQ", "IEEEPUP", "IEEEPUPAT", "DEC", "DNA_DL", "DNA_RC", "DNA_RT", "LAT", "DIAG", "CUST", "SCA", "RARP", "ATALK", "AARP", "IPX", "IPV6", "PPP_DISC", "PPP_SES", "ATMMPOA", "ATMFATE", NULL}; static enum p4e {LOOP, PUP, PUPAT, IP, X25, ARP, BPQ, IEEEPUP, IEEEPUPAT, DEC, DNA_DL, DNA_RC, DNA_RT, LAT, DIAG, CUST, SCA, RARP, ATALK, AARP, IPX, IPV6, PPP_DISC, PPP_SES, ATMMPOA, ATMFATE, MAX_P4 } p4; #define SPLIT(x) {(x >> 8) & 0xff,x & 0xff} static two eth_p_[] = { SPLIT(ETH_P_LOOP), /* Ethernet Loopback packet */ SPLIT(ETH_P_PUP), /* Xerox PUP packet */ SPLIT(ETH_P_PUPAT), /* Xerox PUP Addr Trans packet */ SPLIT(ETH_P_IP), /* Internet Protocol packet */ SPLIT(ETH_P_X25), /* CCITT X.25 */ SPLIT(ETH_P_ARP), /* Address Resolution packet */ SPLIT(ETH_P_BPQ), /* G8BPQ AX.25 Ethernet Packet [NOT OFFICIAL]*/ SPLIT(ETH_P_IEEEPUP), /* Xerox IEEE802.3 PUP packet */ SPLIT(ETH_P_IEEEPUPAT), /* Xerox IEEE802.3 PUP Addr Trans packet */ SPLIT(ETH_P_DEC), /* DEC Assigned proto */ SPLIT(ETH_P_DNA_DL), /* DEC DNA Dump/Load */ SPLIT(ETH_P_DNA_RC), /* DEC DNA Remote Console */ SPLIT(ETH_P_DNA_RT), /* DEC DNA Routing */ SPLIT(ETH_P_LAT), /* DEC LAT */ SPLIT(ETH_P_DIAG), /* DEC Diagnostics */ SPLIT(ETH_P_CUST), /* DEC Customer use */ SPLIT(ETH_P_SCA), /* DEC Systems Comms Arch */ SPLIT(ETH_P_RARP), /* Reverse Addr Res packet */ SPLIT(ETH_P_ATALK), /* Appletalk DDP */ SPLIT(ETH_P_AARP), /* Appletalk AARP */ SPLIT(ETH_P_IPX), /* IPX over DIX */ SPLIT(ETH_P_IPV6), /* IPv6 over bluebook */ SPLIT(ETH_P_PPP_DISC), /* PPPoE discovery messages */ SPLIT(ETH_P_PPP_SES), /* PPPoE session messages */ SPLIT(ETH_P_ATMMPOA), /* MultiProtocol Over ATM */ SPLIT(ETH_P_ATMFATE), /* Frame-based ATM Transport */ }; static const char *l5[] = { "802.3-FCS","802.4-FCS","802.5-FCS","FDDI-FCS","802.6-FCS","-FCS", "802.3", "802.4", "802.5", "FDDI", "802.6", "", "FRAGS","BPDU",NULL}; static enum p5e { I802_3_FCS,I802_4_FCS,I802_5_FCS,FDDI_FCS,I802_6_FCS,X_FCS, I802_3, I802_4, I802_5, FDDI, I802_6, X, FRAGS,BPDU,MAX_P5 } p5; static two p5_pid[] = { {0x00,0x01}, {0x00,0x02}, {0x00,0x03}, {0x00,0x04}, {0x00,0x05}, {0x00,0x06}, {0x00,0x07}, {0x00,0x08}, {0x00,0x09}, {0x00,0x0A}, {0x00,0x0B}, {0x00,0x0C}, {0x00,0x0D}, {0x00,0x0E}}; static const char *l6[] = {"FCS",NULL}; static enum p6e {FCS,MAX_P6} p6; static u_int8_t zeros[] = {0x00,0x00,0x00,0x00,0x45}; static u_int8_t ctlr[1] = {0x67}; static u_int8_t ResBEtagBAsize[] = {0x00}; static oui vpn_oui = {0x00,0x00,0x00}; static struct sockaddr vpn_index = {0,{0x00,0x00,0x00,0x00}}; static struct sockaddr Dest = {0,{0x01,0x80,0xC2,0x00,0x00,0x00}}; /* MAC */ static struct sockaddr dest = {0,{0xca,0x06,0x05,0x06}}; static struct sockaddr Source = {0,{0x00,0x80,0xad,0xb1,0xa0,0xa0}}; /* MAC */ static struct sockaddr source = {0,{0xce,0xe0,0x60,0xf3}}; static struct sockaddr EtherBCast = {0,{0xff,0xff,0xff,0xff,0xff,0xff}}; static char aal5_padding[ATM_CELL_PAYLOAD-1]; typedef struct { u_int8_t UserToUserIndication; u_int8_t CommonPartIndicator; u_int16_t Payload_Len; u_int32_t Crc32; } AAL5_TRLR; static AAL5_TRLR aal5_trailer; static struct iovec iovec[10]; static int count = 0; /* IP IPPROTO_ICMP {ICMP_ECHO|ICMP_ECHOREPLY} IPPROTO_TCP IPPROTO_UDP */ static u_int8_t work[1500]; /* Ping */ /* Use a ping packet to trigger IP traffic */ static void build_ip_ping(void) { static struct iphdr *ip = (void *)work; struct icmphdr *icmp; struct tcphdr *tcp; int payloadlen = 64; /* IP Header */ ip->ihl = sizeof(*ip)/4; ip->version = 4; ip->tos = 0xa0; ip->tot_len = htons(sizeof(*ip)+sizeof(*icmp)+payloadlen); ip->id = htons(54142); ip->frag_off = 0; ip->ttl = 110; ip->protocol = IPPROTO_ICMP; ip->check = 0; if (s_opt) my_setsockaddr(&source,AF_INET,s_opt); memcpy(&ip->saddr,source.sa_data,sizeof(ip->saddr)); if (d_opt) my_setsockaddr(&dest,AF_INET,d_opt); memcpy(&ip->daddr,dest.sa_data,sizeof(ip->daddr)); ip->check = ~csum_partial(ip, ip->ihl*4, 0);/*0x79a2*/ icmp = (void *)((u_int32_t *)ip + ip->ihl); tcp = (void *)icmp; /* ICMP message */ icmp->type = ICMP_ECHO; icmp->code = 0; icmp->checksum = 0; icmp->un.echo.id = htons(0x4bf5); icmp->un.echo.sequence = htons(0xce17); memset((u_int8_t *)icmp+sizeof(*icmp),0xaa,payloadlen); icmp->checksum = ~csum_partial(icmp,ntohs(ip->tot_len)-ip->ihl*4,0);/*0x889d*/ iovec[count].iov_base = ip; iovec[count].iov_len = sizeof(*ip)+sizeof(*icmp)+payloadlen; count++; } static void build_ppp_disc(void) { /* PPPoE Discovery */ /* Use a PADI packet to trigger PPPoE traffic */ /* A PADI packet: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0xffffffff | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0xffff | Host_mac_addr | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Host_mac_addr (cont) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x09 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SESSION_ID = 0x0000 | LENGTH = 0x0004 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static u_int8_t padi[] = {0x11,0x09, 0x00,0x00, 0x00,0x04, /*Length of following*/ 0x01,0x01, 0x00,0x00};/*Length of tag data*/ iovec[count].iov_base = padi; iovec[count].iov_len = sizeof(padi); count++; } static void build_ppp(void) { iovec[count].iov_base = (void *)&ppp_config; iovec[count].iov_len = sizeof(ppp_config); count++; } static void build_802(u_int8_t *Destination, two *etype, void (*payload)(void)) { if (p1 == LLC) { iovec[count].iov_base = (p7 == VPN) ? snap_bridged_vpn : snap_bridged; iovec[count].iov_len = 3; count++; iovec[count].iov_base = p5_pid[p5]; iovec[count].iov_len = 2; count++; } switch(p5) { case I802_3_FCS: case I802_3: iovec[count].iov_base = zeros; iovec[count].iov_len = 2; count++; break; case I802_4_FCS: case I802_4: iovec[count].iov_base = zeros; iovec[count].iov_len = 3; count++; iovec[count].iov_base = ctlr; iovec[count].iov_len = 1; count++; break; case I802_5_FCS: case I802_5: iovec[count].iov_base = zeros+2; iovec[count].iov_len = 3; count++; iovec[count].iov_base = ctlr; iovec[count].iov_len = 1; count++; break; case FDDI_FCS: case FDDI: iovec[count].iov_base = zeros; iovec[count].iov_len = 3; count++; iovec[count].iov_base = ctlr; iovec[count].iov_len = 1; count++; break; case I802_6_FCS: case I802_6: iovec[count].iov_base = ResBEtagBAsize; iovec[count].iov_len = sizeof(ResBEtagBAsize); count++; break; case FRAGS: case BPDU: default: break; } if (p7 == VPN) { if (V_opt) my_setxxx(&vpn_oui,3,s_opt); iovec[count].iov_base = vpn_oui; iovec[count].iov_len = 3; count++; if (v_opt) my_setxxx(&vpn_index,4,s_opt); iovec[count].iov_base = vpn_index.sa_data; iovec[count].iov_len = 4; count++; } iovec[count].iov_base = Destination; iovec[count].iov_len = 6; count++; if (S_opt) my_setsockaddr(&Source,AF_BRIDGE,S_opt); iovec[count].iov_base = Source.sa_data; iovec[count].iov_len = 6; count++; iovec[count].iov_base = etype; iovec[count].iov_len = 2; count++; /* build PDU */ if (payload) (*payload)(); if (p6 == FCS) { ; /* Calc FCS */ } } static struct toks { enum stat {nothing,has,used} stat; char *tok; char *sx; } toks; static void tok_init(struct toks *t,char *sx) { t->stat = nothing; t->tok = NULL; t->sx = sx; } static int getwhich(struct toks *t, const char **l, int def) { int res = 0; switch (t->stat) { case nothing: case used: t->tok = strtok(t->sx, " ,"); t->sx = NULL; t->stat = has; break; case has: default: break; } if (!t->tok) res = def; else while (*l) { if (!strcmp(t->tok,*l)) { t->stat = used; break; } l++; res++; } return res; } static int sdu_aal5; static int parse(char *encap) { tok_init(&toks, encap); sdu_aal5 = getwhich(&toks,l0,1) == 0; p1 = getwhich(&toks,l1,VC); if (p1 == MAX_P1) { printf("%s not valid P1\n", toks.tok); return 1; } p2 = getwhich(&toks,l2,NLPID); if (p2 == MAX_P2) { printf("%s not valid P2\n", toks.tok); return 1; } if (p1 == LLC) { iovec[count].iov_base = p2 ? &snap : &nlpid; iovec[count].iov_len = 3; count++; } switch(p2) { case MAX_P2: break; case NLPID: p3 = getwhich(&toks,nlpid_types,PPP); if (p3 == MAX_P3) { printf("%s not valid P3\n", toks.tok); return 1; } if (p3 == ETHERTYPE) { p4 = getwhich(&toks,ether_types,IP); if (p4 == MAX_P4) { printf("%s not valid P4\n", toks.tok); return 1; } } if (p1 == LLC) { iovec[count].iov_base = &nlpid_[p3]; iovec[count].iov_len = 1; count++; if (p3 == ETHERTYPE) { iovec[count].iov_base = eth_p_[p4]; iovec[count].iov_len = 2; count++; } } if (p3 == SNAP) goto L_SNAP; /* build PDU */ if (p3 == ETHERTYPE) { /* p4 */ } else switch (p3) { case PPP: build_ppp(); break; default: break; } break; case SNAP: L_SNAP: pp3 = getwhich(&toks,ll3,ROUTED); if (pp3 == MAX_PP3) { printf("%s not valid PP3\n", toks.tok); return 1; } switch(pp3) { case MAX_PP3: break; case ROUTED: p4 = getwhich(&toks,ether_types,IP); if (p4 == MAX_P4) { printf("%s not valid P4\n", toks.tok); return 1; } if (p1 == LLC) { iovec[count].iov_base = snap_routed; iovec[count].iov_len = 3; count++; iovec[count].iov_base = eth_p_[p4]; iovec[count].iov_len = 2; count++; } /* build PDU */ switch (p4) { case IP: build_ip_ping(); break; default: break; } break; case BRIDGED: p7 = getwhich(&toks,l7,MAX_P7); p5 = getwhich(&toks,l5,I802_3); if (p5 == MAX_P5) { printf("%s not valid P5\n", toks.tok); return 1; } p6 = getwhich(&toks,l6,MAX_P6); if (p6 == FCS) { if (p5 >= I802_3 && p5 <= X) { p5 -= I802_3-I802_3_FCS; } else { printf("%s not valid P6\n", toks.tok); return 1; } } else { if (p5 >= I802_3_FCS && p5 <= X_FCS) p6 = FCS; } p4 = getwhich(&toks,ether_types,IP); if (p4 == MAX_P4) { printf("%s not valid P4\n", toks.tok); return 1; } switch(p4) { case IP: if (D_opt) my_setsockaddr(&Dest,AF_BRIDGE,D_opt); build_802(Dest.sa_data,ð_p_[p4],&build_ip_ping); break; case PPP_DISC: build_802(EtherBCast.sa_data,ð_p_[p4],&build_ppp_disc); break; default: break; } } break; } if (sdu_aal5) { int i; size_t payload_len, padding_len; payload_len = get_len(iovec, count); padding_len = (ATM_CELL_PAYLOAD-1)-(payload_len+(ATM_AAL5_TRAILER-1)) % ATM_CELL_PAYLOAD; if (padding_len) { iovec[count].iov_base = aal5_padding; iovec[count].iov_len = padding_len; count++; } aal5_trailer.UserToUserIndication = 0; aal5_trailer.CommonPartIndicator = 0; aal5_trailer.Payload_Len = htons(payload_len); aal5_trailer.Crc32 = 0; iovec[count].iov_base = &aal5_trailer; iovec[count].iov_len = ATM_AAL5_TRAILER-4; count++; #define INITIAL_CRC_VAL 0xffffffff // negative one #define CRC_COMPLEMENT_MASK 0xffffffff // negative one aal5_trailer.Crc32 = INITIAL_CRC_VAL; for (i = 0; i < count; i++) aal5_trailer.Crc32 = CalcCRC32(iovec[i].iov_base, iovec[i].iov_len, aal5_trailer.Crc32); aal5_trailer.Crc32 = htonl(aal5_trailer.Crc32 ^ CRC_COMPLEMENT_MASK); iovec[count-1].iov_len += 4; } return 0; } static void dump_it(const void *buf, size_t len) { const u_int8_t *b = buf; size_t i; for (i = 0; i < len; i++, b++) { if (!(i & 15)) printf(" "); printf("%02x ", *b); if ((i & 0xf) == 0xf) printf("\n"); } if ((i & 0xf) != 0) printf("\n"); } static const char *pti_str[] = { /*0*/"Data SDU 0", /*1*/"Data SDU 1", /*2*/"Data SDU 0, CE", /*3*/"Data SDU 1, CE", /*4*/"Segment OAM F5", /*5*/"End-to-end OAM F5", /*6*/"Reserved (RM)", /*7*/"Reserved" }; static int interval = 0; /* display absolute time by default */ static void stampit(struct timeval stamp) { static struct timeval last; static int first = 1; if (first || !interval) { printf("%2d:%02d:%02d.%06ld", (int) ((stamp.tv_sec / 3600) % 24), (int) ((stamp.tv_sec / 60) % 60), (int) (stamp.tv_sec % 60), (long) stamp.tv_usec); if (interval) { first = 0; last = stamp; } } else { struct timeval diff; diff.tv_sec = stamp.tv_sec-last.tv_sec; diff.tv_usec = stamp.tv_usec-last.tv_usec; while (diff.tv_usec < 0) { diff.tv_usec += 1000000; diff.tv_sec--; } last = stamp; printf("%8ld.%06ld", (long) diff.tv_sec, (long) stamp.tv_usec); } } static void print_hdr(u_int32_t hdr) { #define ATM_HDR_CLP_MASK 1 #define ATM_HDR_CLP_SHIFT 0 #define GET(item) ((hdr & ATM_HDR_##item##_MASK) >> ATM_HDR_##item##_SHIFT) printf(": VPI=%d VCI=%d, GFC=0x%x, CLP=%u, %s (PTI %u)\n", GET(VPI),GET(VCI),GET(GFC),GET(CLP), pti_str[GET(PTI)],GET(PTI)); #undef GET } static void analyze(const u_int32_t *cell, size_t len, struct timeval stamp) { stampit(stamp); if (qos.aal == ATM_AAL0) { print_hdr(*cell); cell++; len -= 4; } else printf("\n"); dump_it(cell, len); } static void usage(const char *s) { printf("usage: %s [[-e encap] [-D dest] [-d dest] [-S source] [-s source] [-V vpn_oui] [-v vpn_index] [-b sndbuf] [-q qos] [[itf.]vpi.vci]]\n", s); exit(1); } static const char *aal2str(unsigned int aal) { const char *s = "?"; switch (aal) { case ATM_AAL0: s = "0"; break; case ATM_AAL1: s = "1"; break; case ATM_AAL2: s = "2"; break; case ATM_AAL34: s = "34"; break; case ATM_AAL5: s = "5"; break; default: break; } return s; } int main(int argc, char **argv) { int s; int c; char *encap = NULL; int sndbuf; int err; char *end; while ((c = getopt(argc, argv, "t:g:cid:D:s:S:v:V:e:q:b:?h")) != EOF) switch (c) { case 'i': interval = 1; break; case 't': pti = strtol(optarg,&end,0); if (*end || pti < 0 || pti > 7) usage(argv[0]); break; case 'g': gfc = strtol(optarg,&end,0); if (*end || gfc < 0 || gfc > 15) usage(argv[0]); break; case 'c': clp = 1; break; case 'd': d_opt = optarg; break; case 'D': D_opt = optarg; break; case 's': s_opt = optarg; break; case 'S': S_opt = optarg; break; case 'v': v_opt = optarg; break; case 'V': V_opt = optarg; break; case 'e': encap = optarg; break; case 'q': printf ("optarg : %s\n", optarg); if (text2qos(optarg, &qos, 0)) fprintf(stderr, "QOS parameter invalid\n"); break; case 'b': sndbuf = atoi(optarg); if (sndbuf < 0) { fprintf(stderr, "Invalid sndbuf: %s, using size of 8192 instead\n",optarg); sndbuf = 8192; } break; case '?': case 'h': default: usage(argv[0]); break; } if ((argc - optind) > 1) usage(argv[0]); memset(&addr, 0, sizeof(addr)); err = text2atm(argv[optind] ? argv[optind] : default_addr, (struct sockaddr *) &addr, sizeof(addr), T2A_PVC | T2A_NAME); if (err != 0) { fprintf(stderr, "Could not parse ATM parameters (error=%d)\n", err); return 1; } s = socket(PF_ATMPVC, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return 1; } if (qos.aal == ATM_NO_AAL) { qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = MAX_SDU; qos.txtp.pcr = ATM_MAX_PCR; qos.rxtp = qos.txtp; } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { perror("setsockopt SO_SNDBUF"); return 1; } if (0) { if (pti == -1) { qos.rxtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = 48+4; } else { qos.txtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 48+4; } } if (pti == -1) pti = 0; if (setsockopt(s, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } printf("Communicating AAL%s over ATM %d.%d.%d", aal2str(qos.aal), addr.sap_addr.itf, addr.sap_addr.vpi, addr.sap_addr.vci); if (encap) printf(" \"%s\"", encap); printf("\n"); if (encap) if (parse(encap)) exit(1); if (connect(s, (struct sockaddr*)&addr, sizeof(struct sockaddr_atmpvc)) < 0) { perror("connect"); return 1; } { ssize_t size, len; union { sdu53 l; char b[(ATM_CELL_SIZE-1)+(65535-(ATM_CELL_SIZE-1))]; } buf; struct timeval stamp; if (count) { int i; printf("writing stuff\n"); gettimeofday(&stamp, NULL); stampit(stamp); if (qos.aal == ATM_AAL0) print_hdr(build_hdr()); else printf("\n"); for (i = 0; i < count; i++) dump_it(iovec[i].iov_base, iovec[i].iov_len); size = my_writev(s, iovec, count, sdu_aal5); if (size == -1) { perror("writev"); return 1; } printf("sent %d", size); if (qos.aal == ATM_AAL5) printf(" (padded to %d)", ((size+(ATM_CELL_PAYLOAD-1))/ATM_CELL_PAYLOAD)*ATM_CELL_PAYLOAD); printf("\n"); } printf("reading stuff\n"); len = (qos.aal == ATM_AAL0) ? (ATM_CELL_SIZE-1) : sizeof(buf); do { size = read(s, buf.l, len); if (size < 0) { perror("read"); return 1; } else { if (ioctl(s, SIOCGSTAMP, &stamp) < 0) { perror("ioctl SIOCGSTAMP"); return 1; } printf("read %d\n", size); analyze(buf.l, size, stamp); } } while (size >= 0); } return 0; }