1 /* 2 * Copyright (c) 2009 3 * Siemens AG, All rights reserved. 4 * Dmitry Eremin-Solenikov (dbaryshkov@gmail.com) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that: (1) source code distributions 8 * retain the above copyright notice and this paragraph in its entirety, (2) 9 * distributions including binary code include the above copyright notice and 10 * this paragraph in its entirety in the documentation or other materials 11 * provided with the distribution, and (3) all advertising materials mentioning 12 * features or use of this software display the following acknowledgement: 13 * ``This product includes software developed by the University of California, 14 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 15 * the University nor the names of its contributors may be used to endorse 16 * or promote products derived from this software without specific prior 17 * written permission. 18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 21 */ 22 23 #ifdef HAVE_CONFIG_H 24 #include "config.h" 25 #endif 26 27 #include <tcpdump-stdinc.h> 28 29 #include <stdio.h> 30 #include <pcap.h> 31 #include <string.h> 32 33 #include "interface.h" 34 #include "addrtoname.h" 35 36 #include "extract.h" 37 38 static const char *ftypes[] = { 39 "Beacon", /* 0 */ 40 "Data", /* 1 */ 41 "ACK", /* 2 */ 42 "Command", /* 3 */ 43 "Reserved", /* 4 */ 44 "Reserved", /* 5 */ 45 "Reserved", /* 6 */ 46 "Reserved", /* 7 */ 47 }; 48 49 static int 50 extract_header_length(u_int16_t fc) 51 { 52 int len = 0; 53 54 switch ((fc >> 10) & 0x3) { 55 case 0x00: 56 if (fc & (1 << 6)) /* intra-PAN with none dest addr */ 57 return -1; 58 break; 59 case 0x01: 60 return -1; 61 case 0x02: 62 len += 4; 63 break; 64 case 0x03: 65 len += 10; 66 break; 67 } 68 69 switch ((fc >> 14) & 0x3) { 70 case 0x00: 71 break; 72 case 0x01: 73 return -1; 74 case 0x02: 75 len += 4; 76 break; 77 case 0x03: 78 len += 10; 79 break; 80 } 81 82 if (fc & (1 << 6)) { 83 if (len < 2) 84 return -1; 85 len -= 2; 86 } 87 88 return len; 89 } 90 91 92 u_int 93 ieee802_15_4_if_print(struct netdissect_options *ndo, 94 const struct pcap_pkthdr *h, const u_char *p) 95 { 96 u_int caplen = h->caplen; 97 int hdrlen; 98 u_int16_t fc; 99 u_int8_t seq; 100 101 if (caplen < 3) { 102 ND_PRINT((ndo, "[|802.15.4] %x", caplen)); 103 return caplen; 104 } 105 106 fc = EXTRACT_LE_16BITS(p); 107 hdrlen = extract_header_length(fc); 108 109 seq = EXTRACT_LE_8BITS(p + 2); 110 111 p += 3; 112 caplen -= 3; 113 114 ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7])); 115 if (vflag) 116 ND_PRINT((ndo,"seq %02x ", seq)); 117 if (hdrlen == -1) { 118 ND_PRINT((ndo,"malformed! ")); 119 return caplen; 120 } 121 122 123 if (!vflag) { 124 p+= hdrlen; 125 caplen -= hdrlen; 126 } else { 127 u_int16_t panid = 0; 128 129 switch ((fc >> 10) & 0x3) { 130 case 0x00: 131 ND_PRINT((ndo,"none ")); 132 break; 133 case 0x01: 134 ND_PRINT((ndo,"reserved destination addressing mode")); 135 return 0; 136 case 0x02: 137 panid = EXTRACT_LE_16BITS(p); 138 p += 2; 139 ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p))); 140 p += 2; 141 break; 142 case 0x03: 143 panid = EXTRACT_LE_16BITS(p); 144 p += 2; 145 ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p))); 146 p += 8; 147 break; 148 } 149 ND_PRINT((ndo,"< "); 150 151 switch ((fc >> 14) & 0x3) { 152 case 0x00: 153 ND_PRINT((ndo,"none ")); 154 break; 155 case 0x01: 156 ND_PRINT((ndo,"reserved source addressing mode")); 157 return 0; 158 case 0x02: 159 if (!(fc & (1 << 6))) { 160 panid = EXTRACT_LE_16BITS(p); 161 p += 2; 162 } 163 ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p))); 164 p += 2; 165 break; 166 case 0x03: 167 if (!(fc & (1 << 6))) { 168 panid = EXTRACT_LE_16BITS(p); 169 p += 2; 170 } 171 ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p)))); 172 p += 8; 173 break; 174 } 175 176 caplen -= hdrlen; 177 } 178 179 if (!suppress_default_print) 180 (ndo->ndo_default_print)(ndo, p, caplen); 181 182 return 0; 183 } 184