ieee80211.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2017 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  5. *
  6. * The Tcpreplay Suite of tools is free software: you can redistribute it
  7. * and/or modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or with the authors permission any later version.
  10. *
  11. * The Tcpreplay Suite is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "tcpedit.h"
  22. #include "common.h"
  23. #include "tcpr.h"
  24. #include "dlt_utils.h"
  25. #include "tcpedit_stub.h"
  26. #include "ieee80211.h"
  27. #include "ieee80211_hdr.h"
  28. /*
  29. * Notes about the ieee80211 plugin:
  30. * 802.11 is a little different from most other L2 protocols:
  31. * - Not all frames are data frames (control, data, management) (data frame == L3 or higher included)
  32. * - Not all data frames have data (QoS frames are "data" frames, but have no L3 header)
  33. * - L2 header is 802.11 + an 802.2/802.2SNAP header
  34. */
  35. static char dlt_name[] = "ieee80211";
  36. _U_ static char dlt_prefix[] = "ieee802_11";
  37. static uint16_t dlt_value = DLT_IEEE802_11;
  38. /*
  39. * Function to register ourselves. This function is always called, regardless
  40. * of what DLT types are being used, so it shouldn't be allocating extra buffers
  41. * or anything like that (use the dlt_ieee80211_init() function below for that).
  42. * Tasks:
  43. * - Create a new plugin struct
  44. * - Fill out the provides/requires bit masks. Note: Only specify which fields are
  45. * actually in the header.
  46. * - Add the plugin to the context's plugin chain
  47. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  48. */
  49. int
  50. dlt_ieee80211_register(tcpeditdlt_t *ctx)
  51. {
  52. tcpeditdlt_plugin_t *plugin;
  53. assert(ctx);
  54. /* create a new plugin structure */
  55. plugin = tcpedit_dlt_newplugin();
  56. /* we're a decoder only plugin */
  57. plugin->provides += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR + PLUGIN_MASK_DSTADDR;
  58. plugin->requires += 0;
  59. /* what is our DLT value? */
  60. plugin->dlt = dlt_value;
  61. /* set the prefix name of our plugin. This is also used as the prefix for our options */
  62. plugin->name = safe_strdup(dlt_name);
  63. /*
  64. * Point to our functions, note, you need a function for EVERY method.
  65. * Even if it is only an empty stub returning success.
  66. */
  67. plugin->plugin_init = dlt_ieee80211_init;
  68. plugin->plugin_cleanup = dlt_ieee80211_cleanup;
  69. plugin->plugin_parse_opts = dlt_ieee80211_parse_opts;
  70. plugin->plugin_decode = dlt_ieee80211_decode;
  71. plugin->plugin_encode = dlt_ieee80211_encode;
  72. plugin->plugin_proto = dlt_ieee80211_proto;
  73. plugin->plugin_l2addr_type = dlt_ieee80211_l2addr_type;
  74. plugin->plugin_l2len = dlt_ieee80211_l2len;
  75. plugin->plugin_get_layer3 = dlt_ieee80211_get_layer3;
  76. plugin->plugin_merge_layer3 = dlt_ieee80211_merge_layer3;
  77. plugin->plugin_get_mac = dlt_ieee80211_get_mac;
  78. /* add it to the available plugin list */
  79. return tcpedit_dlt_addplugin(ctx, plugin);
  80. }
  81. /*
  82. * Initializer function. This function is called only once, if and only iif
  83. * this plugin will be utilized. Remember, if you need to keep track of any state,
  84. * store it in your plugin->config, not a global!
  85. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  86. */
  87. int
  88. dlt_ieee80211_init(tcpeditdlt_t *ctx)
  89. {
  90. tcpeditdlt_plugin_t *plugin;
  91. assert(ctx);
  92. if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) {
  93. tcpedit_seterr(ctx->tcpedit, "Unable to initialize unregistered plugin %s", dlt_name);
  94. return TCPEDIT_ERROR;
  95. }
  96. /* allocate memory for our deocde extra data */
  97. if (sizeof(ieee80211_extra_t) > 0)
  98. ctx->decoded_extra = safe_malloc(sizeof(ieee80211_extra_t));
  99. /* allocate memory for our config data */
  100. if (sizeof(ieee80211_config_t) > 0)
  101. plugin->config = safe_malloc(sizeof(ieee80211_config_t));
  102. /* FIXME: set default config values here */
  103. return TCPEDIT_OK; /* success */
  104. }
  105. /*
  106. * Since this is used in a library, we should manually clean up after ourselves
  107. * Unless you allocated some memory in dlt_ieee80211_init(), this is just an stub.
  108. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  109. */
  110. int
  111. dlt_ieee80211_cleanup(tcpeditdlt_t *ctx)
  112. {
  113. tcpeditdlt_plugin_t *plugin;
  114. assert(ctx);
  115. if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) {
  116. tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name);
  117. return TCPEDIT_ERROR;
  118. }
  119. if (ctx->decoded_extra != NULL) {
  120. safe_free(ctx->decoded_extra);
  121. ctx->decoded_extra = NULL;
  122. }
  123. if (plugin->config != NULL) {
  124. safe_free(plugin->config);
  125. plugin->config = NULL;
  126. }
  127. return TCPEDIT_OK; /* success */
  128. }
  129. /*
  130. * This is where you should define all your AutoGen AutoOpts option parsing.
  131. * Any user specified option should have it's bit turned on in the 'provides'
  132. * bit mask.
  133. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  134. */
  135. int
  136. dlt_ieee80211_parse_opts(tcpeditdlt_t *ctx)
  137. {
  138. assert(ctx);
  139. /* we have none */
  140. return TCPEDIT_OK; /* success */
  141. }
  142. /*
  143. * Function to decode the layer 2 header in the packet.
  144. * You need to fill out:
  145. * - ctx->l2len
  146. * - ctx->srcaddr
  147. * - ctx->dstaddr
  148. * - ctx->proto
  149. * - ctx->decoded_extra
  150. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  151. */
  152. int
  153. dlt_ieee80211_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
  154. {
  155. int l2len;
  156. assert(ctx);
  157. assert(packet);
  158. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  159. if (pktlen < l2len)
  160. return TCPEDIT_ERROR;
  161. dbgx(3, "Decoding 802.11 packet " COUNTER_SPEC, ctx->tcpedit->runtime.packetnum);
  162. if (! ieee80211_is_data(ctx, packet, pktlen)) {
  163. tcpedit_seterr(ctx->tcpedit, "Packet " COUNTER_SPEC " is not a normal 802.11 data frame",
  164. ctx->tcpedit->runtime.packetnum);
  165. return TCPEDIT_SOFT_ERROR;
  166. }
  167. if (ieee80211_is_encrypted(ctx, packet, pktlen)) {
  168. tcpedit_seterr(ctx->tcpedit, "Packet " COUNTER_SPEC " is encrypted. Unable to decode frame.",
  169. ctx->tcpedit->runtime.packetnum);
  170. return TCPEDIT_SOFT_ERROR;
  171. }
  172. ctx->l2len = l2len;
  173. memcpy(&(ctx->srcaddr), ieee80211_get_src((ieee80211_hdr_t *)packet), ETHER_ADDR_LEN);
  174. memcpy(&(ctx->dstaddr), ieee80211_get_dst((ieee80211_hdr_t *)packet), ETHER_ADDR_LEN);
  175. ctx->proto = dlt_ieee80211_proto(ctx, packet, pktlen);
  176. return TCPEDIT_OK; /* success */
  177. }
  178. /*
  179. * Function to encode the layer 2 header back into the packet.
  180. * Returns: total packet len or TCPEDIT_ERROR
  181. */
  182. int
  183. dlt_ieee80211_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, _U_ tcpr_dir_t dir)
  184. {
  185. assert(ctx);
  186. assert(packet);
  187. tcpedit_seterr(ctx->tcpedit, "%s", "DLT_IEEE802_11 plugin does not support packet encoding");
  188. return TCPEDIT_ERROR;
  189. }
  190. /*
  191. * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error
  192. */
  193. int
  194. dlt_ieee80211_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
  195. {
  196. int l2len;
  197. int hdrlen = 0;
  198. uint16_t *frame_control, fc;
  199. struct tcpr_802_2snap_hdr *hdr;
  200. assert(ctx);
  201. assert(packet);
  202. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  203. if (pktlen < l2len)
  204. return TCPEDIT_ERROR;
  205. /* check 802.11 frame control field */
  206. frame_control = (uint16_t *)packet;
  207. fc = ntohs(*frame_control);
  208. /* Not all 802.11 frames have data */
  209. if ((fc & ieee80211_FC_TYPE_MASK) != ieee80211_FC_TYPE_DATA)
  210. return TCPEDIT_SOFT_ERROR;
  211. /* Some data frames are QoS and have no data
  212. if (((fc & ieee80211_FC_SUBTYPE_MASK) & ieee80211_FC_SUBTYPE_QOS) == ieee80211_FC_SUBTYPE_QOS)
  213. return TCPEDIT_SOFT_ERROR;
  214. */
  215. if ((fc & ieee80211_FC_SUBTYPE_QOS) == ieee80211_FC_SUBTYPE_QOS) {
  216. hdrlen += 2;
  217. }
  218. /* figure out the actual header length */
  219. if (ieee80211_USE_4(fc)) {
  220. hdrlen += sizeof(ieee80211_addr4_hdr_t);
  221. } else {
  222. hdrlen += sizeof(ieee80211_hdr_t);
  223. }
  224. hdr = (struct tcpr_802_2snap_hdr *)&packet[hdrlen];
  225. /* verify the header is 802.2SNAP (8 bytes) not 802.2 (3 bytes) */
  226. if (hdr->snap_dsap == 0xAA && hdr->snap_ssap == 0xAA)
  227. return hdr->snap_type;
  228. return TCPEDIT_SOFT_ERROR; /* 802.2 has no type field */
  229. }
  230. /*
  231. * Function returns a pointer to the layer 3 protocol header or NULL on error
  232. */
  233. u_char *
  234. dlt_ieee80211_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen)
  235. {
  236. int l2len;
  237. assert(ctx);
  238. assert(packet);
  239. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  240. if (pktlen < l2len)
  241. return NULL;
  242. dbgx(1, "Getting data for packet " COUNTER_SPEC " from offset: %d", ctx->tcpedit->runtime.packetnum, l2len);
  243. return tcpedit_dlt_l3data_copy(ctx, packet, pktlen, l2len);
  244. }
  245. /*
  246. * function merges the packet (containing L2 and old L3) with the l3data buffer
  247. * containing the new l3 data. Note, if L2 % 4 == 0, then they're pointing to the
  248. * same buffer, otherwise there was a memcpy involved on strictly aligned architectures
  249. * like SPARC
  250. */
  251. u_char *
  252. dlt_ieee80211_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen, u_char *l3data)
  253. {
  254. int l2len;
  255. assert(ctx);
  256. assert(packet);
  257. assert(l3data);
  258. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  259. if (pktlen < l2len)
  260. return NULL;
  261. return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, l3data, l2len);
  262. }
  263. /*
  264. * return the length of the L2 header of the current packet
  265. * based on: http://www.tcpdump.org/lists/workers/2004/07/msg00121.html
  266. */
  267. int
  268. dlt_ieee80211_l2len(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
  269. {
  270. uint16_t *frame_control, fc;
  271. struct tcpr_802_2snap_hdr *hdr;
  272. int hdrlen = 0;
  273. assert(ctx);
  274. assert(packet);
  275. if (pktlen < (int)sizeof(uint16_t))
  276. return 0;
  277. dbgx(2, "packet = %p\t\tplen = %d", packet, pktlen);
  278. frame_control = (uint16_t *)packet;
  279. fc = ntohs(*frame_control);
  280. if (ieee80211_USE_4(fc)) {
  281. hdrlen = sizeof(ieee80211_addr4_hdr_t);
  282. } else {
  283. hdrlen = sizeof(ieee80211_hdr_t);
  284. }
  285. /* if Data/QoS, then L2 len is + 2 bytes */
  286. if ((fc & ieee80211_FC_SUBTYPE_QOS) == ieee80211_FC_SUBTYPE_QOS) {
  287. dbgx(2, "total header length (fc %04x) (802.11 + QoS data): %d", fc, hdrlen + 2);
  288. hdrlen += 2;
  289. }
  290. if (pktlen >= (hdrlen + (int)sizeof(struct tcpr_802_2snap_hdr))) {
  291. hdr = (struct tcpr_802_2snap_hdr *)&packet[hdrlen];
  292. /* verify the header is 802.2SNAP (8 bytes) not 802.2 (3 bytes) */
  293. if (hdr->snap_dsap == 0xAA && hdr->snap_ssap == 0xAA) {
  294. hdrlen += (int)sizeof(struct tcpr_802_2snap_hdr);
  295. dbgx(2, "total header length (802.11 + 802.2SNAP): %d", hdrlen);
  296. } else {
  297. hdrlen += (int)sizeof(struct tcpr_802_2_hdr);
  298. dbgx(2, "total header length (802.11 + 802.2): %d (%02x/%02x)", hdrlen, hdr->snap_dsap, hdr->snap_ssap);
  299. }
  300. }
  301. if (pktlen < hdrlen)
  302. return 0;
  303. dbgx(2, "header length: %d", hdrlen);
  304. return hdrlen;
  305. }
  306. /*
  307. * return a static pointer to the source/destination MAC address
  308. * return NULL on error/address doesn't exist
  309. */
  310. u_char *
  311. dlt_ieee80211_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, const int pktlen)
  312. {
  313. assert(ctx);
  314. assert(packet);
  315. u_char *macaddr;
  316. if (pktlen < 14)
  317. return NULL;
  318. switch(mac) {
  319. case SRC_MAC:
  320. macaddr = ieee80211_get_src(packet);
  321. memcpy(ctx->srcmac, macaddr, ETHER_ADDR_LEN);
  322. return(ctx->srcmac);
  323. break;
  324. case DST_MAC:
  325. macaddr = ieee80211_get_dst(packet);
  326. memcpy(ctx->dstmac, macaddr, ETHER_ADDR_LEN);
  327. return(ctx->dstmac);
  328. break;
  329. default:
  330. errx(1, "Invalid tcpeditdlt_mac_type_t: %d", mac);
  331. }
  332. return(NULL);
  333. }
  334. tcpeditdlt_l2addr_type_t
  335. dlt_ieee80211_l2addr_type(void)
  336. {
  337. return ETHERNET;
  338. }