ieee80211.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2018 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 if
  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 decode extra data */
  97. if (ctx->decoded_extra_size > 0) {
  98. if (ctx->decoded_extra_size < sizeof(ieee80211_extra_t)) {
  99. ctx->decoded_extra_size = sizeof(ieee80211_extra_t);
  100. ctx->decoded_extra = safe_realloc(ctx->decoded_extra,
  101. ctx->decoded_extra_size);
  102. }
  103. } else {
  104. ctx->decoded_extra_size = sizeof(ieee80211_extra_t);
  105. ctx->decoded_extra = safe_malloc(ctx->decoded_extra_size);
  106. }
  107. /* allocate memory for our config data */
  108. plugin->config_size = sizeof(ieee80211_config_t);
  109. plugin->config = safe_malloc(plugin->config_size);
  110. /* FIXME: set default config values here */
  111. return TCPEDIT_OK; /* success */
  112. }
  113. /*
  114. * Since this is used in a library, we should manually clean up after ourselves
  115. * Unless you allocated some memory in dlt_ieee80211_init(), this is just an stub.
  116. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  117. */
  118. int
  119. dlt_ieee80211_cleanup(tcpeditdlt_t *ctx)
  120. {
  121. tcpeditdlt_plugin_t *plugin;
  122. assert(ctx);
  123. if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) {
  124. tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name);
  125. return TCPEDIT_ERROR;
  126. }
  127. safe_free(plugin->name);
  128. plugin->name = NULL;
  129. safe_free(plugin->config);
  130. plugin->config = NULL;
  131. plugin->config_size = 0;
  132. return TCPEDIT_OK; /* success */
  133. }
  134. /*
  135. * This is where you should define all your AutoGen AutoOpts option parsing.
  136. * Any user specified option should have it's bit turned on in the 'provides'
  137. * bit mask.
  138. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  139. */
  140. int
  141. dlt_ieee80211_parse_opts(tcpeditdlt_t *ctx)
  142. {
  143. assert(ctx);
  144. /* we have none */
  145. return TCPEDIT_OK; /* success */
  146. }
  147. /*
  148. * Function to decode the layer 2 header in the packet.
  149. * You need to fill out:
  150. * - ctx->l2len
  151. * - ctx->srcaddr
  152. * - ctx->dstaddr
  153. * - ctx->proto
  154. * - ctx->decoded_extra
  155. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  156. */
  157. int
  158. dlt_ieee80211_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
  159. {
  160. int l2len;
  161. assert(ctx);
  162. assert(packet);
  163. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  164. if (l2len == -1 || pktlen < l2len)
  165. return TCPEDIT_ERROR;
  166. dbgx(3, "Decoding 802.11 packet " COUNTER_SPEC, ctx->tcpedit->runtime.packetnum);
  167. if (! ieee80211_is_data(ctx, packet, pktlen)) {
  168. tcpedit_seterr(ctx->tcpedit, "Packet " COUNTER_SPEC " is not a normal 802.11 data frame",
  169. ctx->tcpedit->runtime.packetnum);
  170. return TCPEDIT_SOFT_ERROR;
  171. }
  172. if (ieee80211_is_encrypted(ctx, packet, pktlen)) {
  173. tcpedit_seterr(ctx->tcpedit, "Packet " COUNTER_SPEC " is encrypted. Unable to decode frame.",
  174. ctx->tcpedit->runtime.packetnum);
  175. return TCPEDIT_SOFT_ERROR;
  176. }
  177. ctx->l2len = l2len;
  178. memcpy(&(ctx->srcaddr), ieee80211_get_src((ieee80211_hdr_t *)packet), ETHER_ADDR_LEN);
  179. memcpy(&(ctx->dstaddr), ieee80211_get_dst((ieee80211_hdr_t *)packet), ETHER_ADDR_LEN);
  180. ctx->proto = dlt_ieee80211_proto(ctx, packet, pktlen);
  181. return TCPEDIT_OK; /* success */
  182. }
  183. /*
  184. * Function to encode the layer 2 header back into the packet.
  185. * Returns: total packet len or TCPEDIT_ERROR
  186. */
  187. int
  188. dlt_ieee80211_encode(tcpeditdlt_t *ctx, u_char *packet, _U_ int pktlen,
  189. _U_ tcpr_dir_t dir)
  190. {
  191. assert(ctx);
  192. assert(packet);
  193. tcpedit_seterr(ctx->tcpedit, "%s", "DLT_IEEE802_11 plugin does not support packet encoding");
  194. return TCPEDIT_ERROR;
  195. }
  196. /*
  197. * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error
  198. */
  199. int
  200. dlt_ieee80211_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
  201. {
  202. int l2len;
  203. int hdrlen = 0;
  204. uint16_t *frame_control, fc;
  205. struct tcpr_802_2snap_hdr *hdr;
  206. assert(ctx);
  207. assert(packet);
  208. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  209. if (l2len == -1 || pktlen < l2len)
  210. return TCPEDIT_ERROR;
  211. /* check 802.11 frame control field */
  212. frame_control = (uint16_t *)packet;
  213. fc = ntohs(*frame_control);
  214. /* Not all 802.11 frames have data */
  215. if ((fc & ieee80211_FC_TYPE_MASK) != ieee80211_FC_TYPE_DATA)
  216. return TCPEDIT_SOFT_ERROR;
  217. /* Some data frames are QoS and have no data
  218. if (((fc & ieee80211_FC_SUBTYPE_MASK) & ieee80211_FC_SUBTYPE_QOS) == ieee80211_FC_SUBTYPE_QOS)
  219. return TCPEDIT_SOFT_ERROR;
  220. */
  221. if ((fc & ieee80211_FC_SUBTYPE_QOS) == ieee80211_FC_SUBTYPE_QOS) {
  222. hdrlen += 2;
  223. }
  224. /* figure out the actual header length */
  225. if (ieee80211_USE_4(fc)) {
  226. hdrlen += sizeof(ieee80211_addr4_hdr_t);
  227. } else {
  228. hdrlen += sizeof(ieee80211_hdr_t);
  229. }
  230. hdr = (struct tcpr_802_2snap_hdr *)&packet[hdrlen];
  231. /* verify the header is 802.2SNAP (8 bytes) not 802.2 (3 bytes) */
  232. if (hdr->snap_dsap == 0xAA && hdr->snap_ssap == 0xAA)
  233. return hdr->snap_type;
  234. return TCPEDIT_SOFT_ERROR; /* 802.2 has no type field */
  235. }
  236. /*
  237. * Function returns a pointer to the layer 3 protocol header or NULL on error
  238. */
  239. u_char *
  240. dlt_ieee80211_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen)
  241. {
  242. int l2len;
  243. assert(ctx);
  244. assert(packet);
  245. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  246. if (l2len == -1 || pktlen < l2len)
  247. return NULL;
  248. dbgx(1, "Getting data for packet " COUNTER_SPEC " from offset: %d", ctx->tcpedit->runtime.packetnum, l2len);
  249. return tcpedit_dlt_l3data_copy(ctx, packet, pktlen, l2len);
  250. }
  251. /*
  252. * function merges the packet (containing L2 and old L3) with the l3data buffer
  253. * containing the new l3 data. Note, if L2 % 4 == 0, then they're pointing to the
  254. * same buffer, otherwise there was a memcpy involved on strictly aligned architectures
  255. * like SPARC
  256. */
  257. u_char *
  258. dlt_ieee80211_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen, u_char *l3data)
  259. {
  260. int l2len;
  261. assert(ctx);
  262. assert(packet);
  263. assert(l3data);
  264. l2len = dlt_ieee80211_l2len(ctx, packet, pktlen);
  265. if (l2len == -1 || pktlen < l2len)
  266. return NULL;
  267. return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, l3data, l2len);
  268. }
  269. /*
  270. * return the length of the L2 header of the current packet
  271. * based on: http://www.tcpdump.org/lists/workers/2004/07/msg00121.html
  272. */
  273. int
  274. dlt_ieee80211_l2len(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen)
  275. {
  276. uint16_t *frame_control, fc;
  277. int hdrlen = 0;
  278. assert(ctx);
  279. assert(packet);
  280. if (pktlen < (int)sizeof(uint16_t))
  281. return 0;
  282. dbgx(2, "packet = %p\t\tplen = %d", packet, pktlen);
  283. frame_control = (uint16_t *)packet;
  284. fc = ntohs(*frame_control);
  285. if (ieee80211_USE_4(fc)) {
  286. hdrlen = sizeof(ieee80211_addr4_hdr_t);
  287. } else {
  288. hdrlen = sizeof(ieee80211_hdr_t);
  289. }
  290. /* if Data/QoS, then L2 len is + 2 bytes */
  291. if ((fc & ieee80211_FC_SUBTYPE_QOS) == ieee80211_FC_SUBTYPE_QOS) {
  292. dbgx(2, "total header length (fc %04x) (802.11 + QoS data): %d", fc, hdrlen + 2);
  293. hdrlen += 2;
  294. }
  295. if (pktlen >= (hdrlen + (int)sizeof(struct tcpr_802_2snap_hdr))) {
  296. struct tcpr_802_2snap_hdr *hdr;
  297. hdr = (struct tcpr_802_2snap_hdr *)&packet[hdrlen];
  298. /* verify the header is 802.2SNAP (8 bytes) not 802.2 (3 bytes) */
  299. if (hdr->snap_dsap == 0xAA && hdr->snap_ssap == 0xAA) {
  300. hdrlen += (int)sizeof(struct tcpr_802_2snap_hdr);
  301. dbgx(2, "total header length (802.11 + 802.2SNAP): %d", hdrlen);
  302. } else {
  303. hdrlen += (int)sizeof(struct tcpr_802_2_hdr);
  304. dbgx(2, "total header length (802.11 + 802.2): %d (%02x/%02x)", hdrlen, hdr->snap_dsap, hdr->snap_ssap);
  305. }
  306. }
  307. if (pktlen < hdrlen)
  308. return 0;
  309. dbgx(2, "header length: %d", hdrlen);
  310. return hdrlen;
  311. }
  312. /*
  313. * return a static pointer to the source/destination MAC address
  314. * return NULL on error/address doesn't exist
  315. */
  316. u_char *
  317. dlt_ieee80211_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, const int pktlen)
  318. {
  319. assert(ctx);
  320. assert(packet);
  321. u_char *macaddr;
  322. if (pktlen < 14)
  323. return NULL;
  324. switch(mac) {
  325. case SRC_MAC:
  326. macaddr = ieee80211_get_src(packet);
  327. memcpy(ctx->srcmac, macaddr, ETHER_ADDR_LEN);
  328. return(ctx->srcmac);
  329. break;
  330. case DST_MAC:
  331. macaddr = ieee80211_get_dst(packet);
  332. memcpy(ctx->dstmac, macaddr, ETHER_ADDR_LEN);
  333. return(ctx->dstmac);
  334. break;
  335. default:
  336. errx(1, "Invalid tcpeditdlt_mac_type_t: %d", mac);
  337. }
  338. return(NULL);
  339. }
  340. tcpeditdlt_l2addr_type_t
  341. dlt_ieee80211_l2addr_type(void)
  342. {
  343. return ETHERNET;
  344. }