Frame numbers are unsigned.
[obnox/wireshark/wip.git] / packet-ieee80211.c
index ac361d1695f7c459bbcb0f91094edc08d7d76482..8bf2295675028afba907c52cfc516027dbba2243 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2000, Axis Communications AB
  * Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com
  *
- * $Id: packet-ieee80211.c,v 1.81 2003/01/22 19:39:25 guy Exp $
+ * $Id: packet-ieee80211.c,v 1.91 2003/06/05 22:10:49 gerald Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -222,8 +222,12 @@ static char *wep_keystr[] = {NULL, NULL, NULL, NULL};
 #define TAG_TIM            0x05
 #define TAG_IBSS_PARAMETER 0x06
 #define TAG_CHALLENGE_TEXT 0x10
-#define TAG_ERP_INFO       0x2F
+#define TAG_ERP_INFO       0x2A
+#define TAG_ERP_INFO_OLD   0x2F        /* IEEE Std 802.11g/D4.0 */
 #define TAG_EXT_SUPP_RATES 0x32
+#define TAG_VENDOR_SPECIFIC_IE    0xDD
+
+#define WPA_OUI        "\x00\x50\xF2"
 
 /* ************************************************************************* */
 /*                         Frame types, and their names                      */
@@ -328,6 +332,7 @@ static int hf_fragment_overlap_conflict = -1;
 static int hf_fragment_multiple_tails = -1;
 static int hf_fragment_too_long_fragment = -1;
 static int hf_fragment_error = -1;
+static int hf_reassembled_in = -1;
 
 
 static int proto_wlan_mgt = -1;
@@ -399,6 +404,7 @@ static const fragment_items frag_items = {
        &hf_fragment_multiple_tails,
        &hf_fragment_too_long_fragment,
        &hf_fragment_error,
+       &hf_reassembled_in,
        "fragments"
 };
 
@@ -663,6 +669,126 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
     }
 }
 
+static char *wpa_cipher_str[] = 
+{
+  "NONE",
+  "WEP (40-bit)",
+  "TKIP",
+  "AES (OCB)",
+  "AES (CCM)",
+  "WEP (104-bit)",
+};
+
+static char *
+wpa_cipher_idx2str(guint idx)
+{
+  if (idx < sizeof(wpa_cipher_str)/sizeof(wpa_cipher_str[0]))
+    return wpa_cipher_str[idx];
+  return "UNKNOWN";
+}
+
+static char *wpa_keymgmt_str[] = 
+{
+  "NONE",
+  "WPA",
+  "PSK",
+};
+
+static char *
+wpa_keymgmt_idx2str(guint idx)
+{
+  if (idx < sizeof(wpa_keymgmt_str)/sizeof(wpa_keymgmt_str[0]))
+    return wpa_keymgmt_str[idx];
+  return "UNKNOWN";
+}
+
+void 
+dissect_vendor_specific_ie(proto_tree * tree, tvbuff_t * tvb, int offset,
+               int tag_number, int tag_length, int tag_interpretation)
+{
+      guint8 tag_no;
+      guint32 tag_len;
+      const guint8 *tag_val;
+      guint32 tag_val_off = 0;
+      char out_buff[SHORT_STR];
+      int i;
+       
+      tag_no = tvb_get_guint8(tvb, offset);
+      tag_len = tvb_get_guint8(tvb, offset + 1);
+      tag_val = tvb_get_ptr(tvb, offset + 2, tag_len);
+  
+      proto_tree_add_uint(tree, tag_number, tvb, offset, 1, tag_no);
+      offset += 1;
+      
+      proto_tree_add_uint(tree, tag_length, tvb, offset, 1, tag_len);
+      offset += 1;
+
+      if (tag_val_off + 6 <= tag_len && !memcmp(tag_val, WPA_OUI"\x01", 4)) {
+        snprintf(out_buff, SHORT_STR, "WPA IE, type %u, version %u",
+                  tag_val[tag_val_off + 3], pletohs(&tag_val[tag_val_off + 4]));
+        proto_tree_add_string(tree, tag_interpretation, tvb, offset, 6, out_buff);
+        offset += 6;
+        tag_val_off += 6;
+        if (tag_val_off + 4 <= tag_len) {
+          /* multicast cipher suite */
+          if (!memcmp(&tag_val[tag_val_off], WPA_OUI, 3)) {
+            snprintf(out_buff, SHORT_STR, "Multicast cipher suite: %s", 
+                      wpa_cipher_idx2str(tag_val[tag_val_off + 3]));
+            proto_tree_add_string(tree, tag_interpretation, tvb, offset, 4, out_buff);
+            offset += 4;
+            tag_val_off += 4;
+            /* unicast cipher suites */
+            if (tag_val_off + 2 <= tag_len) {
+              snprintf(out_buff, SHORT_STR, "# of unicast cipher suites: %u",
+                        pletohs(tag_val + tag_val_off));
+              proto_tree_add_string(tree, tag_interpretation, tvb, offset, 2, out_buff);
+              offset += 2;
+              tag_val_off += 2;
+              i = 1;
+              while (tag_val_off + 4 <= tag_len) {
+                if (!memcmp(&tag_val[tag_val_off], WPA_OUI, 3)) {
+                  snprintf(out_buff, SHORT_STR, "Unicast cipher suite %u: %s", 
+                            i, wpa_cipher_idx2str(tag_val[tag_val_off + 3]));
+                  proto_tree_add_string(tree, tag_interpretation, tvb, offset, 4, out_buff);
+                  offset += 4;
+                  tag_val_off += 4;
+                  i ++;
+                }
+                else
+                  break;
+              }
+             /* authenticated key management suites */
+              if (tag_val_off + 2 <= tag_len) {
+                snprintf(out_buff, SHORT_STR, "# of auth key management suites: %u",
+                          pletohs(tag_val + tag_val_off));
+                proto_tree_add_string(tree, tag_interpretation, tvb, offset, 2, out_buff);
+                offset += 2;
+                tag_val_off += 2;
+                i = 1;
+                while (tag_val_off + 4 <= tag_len) {
+                  if (!memcmp(&tag_val[tag_val_off], WPA_OUI, 3)) {
+                    snprintf(out_buff, SHORT_STR, "auth key management suite %u: %s", 
+                              i, wpa_keymgmt_idx2str(tag_val[tag_val_off + 3]));
+                    proto_tree_add_string(tree, tag_interpretation, tvb, offset, 4, out_buff);
+                    offset += 4;
+                    tag_val_off += 4;
+                    i ++;
+                  }
+                  else
+                    break;
+                }
+              }
+            }
+          }
+        }
+        if (tag_val_off < tag_len)
+          proto_tree_add_string(tree, tag_interpretation, tvb,
+                                 offset, tag_len - tag_val_off, "Not interpreted");
+      }
+      else
+        proto_tree_add_string(tree, tag_interpretation, 
+                       tvb, offset, tag_len, "Not interpreted");
+}
 
 /* ************************************************************************* */
 /*           Dissect and add tagged (optional) fields to proto tree          */
@@ -698,7 +824,8 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
   /* Next See if tag is reserved - if true, skip it! */
   if (((tag_no >= 7) && (tag_no <= 15))
       || ((tag_no >= 32) && (tag_no <= 255) && (tag_no != TAG_ERP_INFO) &&
-         (tag_no != TAG_EXT_SUPP_RATES)))
+         (tag_no != TAG_EXT_SUPP_RATES) &&
+         (tag_no != TAG_ERP_INFO_OLD) && (tag_no != TAG_VENDOR_SPECIFIC_IE)))
     {
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
                                  "Tag Number: %u (Reserved tag number)",
@@ -753,9 +880,9 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
            ret = snprintf (out_buff + n, SHORT_STR - n, "%2.1f%s ",
                           (tag_data_ptr[i] & 0x7F) * 0.5,
                           (tag_data_ptr[i] & 0x80) ? "(B)" : "");
-           if (ret == -1) {
+           if (ret == -1 || ret >= SHORT_STR - n) {
              /* Some versions of snprintf return -1 if they'd truncate
-                the output. */
+                the output. Others return <buf_size> or greater.  */
              break;
            }
            n += ret;
@@ -763,6 +890,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
       if (n < SHORT_STR)
        snprintf (out_buff + n, SHORT_STR - n, "[Mbit/sec]");
 
+      out_buff[SHORT_STR-1] = '\0';
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
       break;
@@ -868,6 +996,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_ERP_INFO:
+    case TAG_ERP_INFO_OLD:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
                                  "Tag Number: %u (ERP Information)",
                                  tag_no);
@@ -876,14 +1005,19 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
       memset (out_buff, 0, SHORT_STR);
 
       snprintf (out_buff, SHORT_STR,
-               "ERP info: 0x%x (%sNon-ERP STAs, %suse protection)",
+               "ERP info: 0x%x (%sNon-ERP STAs, %suse protection, %s preambles)",
                tag_data_ptr[0],
                tag_data_ptr[0] & 0x01 ? "" : "no ",
-               tag_data_ptr[0] & 0x02 ? "" : "do not ");
+               tag_data_ptr[0] & 0x02 ? "" : "do not ",
+               tag_data_ptr[0] & 0x04 ? "short or long": "long");
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
+
       break;
 
+    case TAG_VENDOR_SPECIFIC_IE:
+      dissect_vendor_specific_ie(tree, tvb, offset, tag_number, tag_length, tag_interpretation);
+      break;
 
 
     default:
@@ -1759,7 +1893,7 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
                                     wlan_fragment_table,
                                     wlan_reassembled_table,
                                     frag_number,
-                                    len,
+                                    reported_len,
                                     more_frags);
     if (fd_head != NULL) {
       /*
@@ -1774,12 +1908,8 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
        * a non-fragmented frame.
        */
       if (fd_head->next != NULL) {
-        next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
-        tvb_set_child_real_data_tvbuff(tvb, next_tvb);
-        add_new_data_source(pinfo, next_tvb, "Reassembled 802.11");
-
-        /* Show all fragments. */
-        show_fragment_seq_tree(fd_head, &frag_items, hdr_tree, pinfo, next_tvb);
+        next_tvb = process_reassembled_data(tvb, pinfo, "Reassembled 802.11",
+                fd_head, &frag_items, NULL, hdr_tree);
       } else {
        /*
         * Not fragmented, really.
@@ -2070,6 +2200,16 @@ proto_register_ieee80211 (void)
      "associated stations"},
     {0x12, "Association denied due to requesting station not supporting all "
      "of the datarates in the BSSBasicServiceSet Parameter"},
+    {0x13, "Association denied due to requesting station not supporting "
+     "short preamble operation"},
+    {0x14, "Association denied due to requesting station not supporting "
+     "PBCC encoding"},
+    {0x15, "Association denied due to requesting station not supporting "
+     "channel agility"},
+    {0x19, "Association denied due to requesting station not supporting "
+     "short slot operation"},
+    {0x1A, "Association denied due to requesting station not supporting "
+     "DSSS-OFDM operation"},
     {0x00, NULL}
   };
 
@@ -2222,6 +2362,10 @@ proto_register_ieee80211 (void)
       {"802.11 Fragments", "wlan.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
        "802.11 Fragments", HFILL }},
 
+    {&hf_reassembled_in,
+      {"Reassembled 802.11 in frame", "wlan.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+       "This 802.11 packet is reassembled in this frame", HFILL }},
+
     {&hf_wep_iv,
      {"Initialization Vector", "wlan.wep.iv", FT_UINT24, BASE_HEX, NULL, 0,
       "Initialization Vector", HFILL }},
@@ -2531,7 +2675,7 @@ static tvbuff_t *try_decrypt_wep(tvbuff_t *tvb, guint32 offset, guint32 len) {
   }
 
  done:
-  if ((!decr_tvb) && (tmp))    free(tmp);
+  if ((!decr_tvb) && (tmp))    g_free(tmp);
 
 #if 0
   printf("de-wep %p\n", decr_tvb);
@@ -2628,8 +2772,6 @@ static int wep_decrypt(guint8 *buf, guint32 len, int key_override) {
   return 0;
 }
 
-/* XXX need to verify these malloc()s succeed */
-
 static void init_wepkeys(void) {
   char *tmp, *tmp2;
   guint8 *tmp3;
@@ -2655,8 +2797,8 @@ static void init_wepkeys(void) {
   if (wep_keylens != NULL)
     return;
 
-  wep_keys = malloc(num_wepkeys * sizeof(guint8*));
-  wep_keylens = malloc(num_wepkeys * sizeof(int));
+  wep_keys = g_malloc(num_wepkeys * sizeof(guint8*));
+  wep_keylens = g_malloc(num_wepkeys * sizeof(int));
 
   for (i = 0 ; i < num_wepkeys; i++) {
     wep_keys[i] = NULL;
@@ -2679,7 +2821,7 @@ static void init_wepkeys(void) {
 #endif
 #endif
 
-      wep_keys[i] = malloc(32 * sizeof(guint8));
+      wep_keys[i] = g_malloc(32 * sizeof(guint8));
       memset(wep_keys[i], 0, 32 * sizeof(guint8));
       tmp3 = wep_keys[i];
       while ((tmp != NULL) && (*tmp != 0)) {