make dissect_ber_choice take a guint* that will return the
[obnox/wireshark/wip.git] / epan / dissectors / packet-iapp.c
1 /* packet-iapp.c
2  * Routines for IAPP dissection
3  * Copyright 2002, Alfred Arnold <aarnold@elsa.de>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include "oui.h"
39
40 /* Initialize the protocol and registered fields */
41 static int proto_iapp = -1;
42 static int hf_iapp_version = -1;
43 static int hf_iapp_type = -1;
44
45 /* Initialize the subtree pointers */
46 static gint ett_iapp = -1;
47 static gint ett_iapp_pdu = -1;
48 static gint ett_iapp_cap = -1;
49 static gint ett_iapp_auth = -1;
50
51 #define UDP_PORT_IAPP     2313
52
53 #define IAPP_ANNOUNCE_REQUEST  0
54 #define IAPP_ANNOUNCE_RESPONSE 1
55 #define IAPP_HANDOVER_REQUEST 2
56 #define IAPP_HANDOVER_RESPONSE 3
57
58 #define IAPP_PDU_SSID 0
59 #define IAPP_PDU_BSSID 1
60 #define IAPP_PDU_OLDBSSID 2
61 #define IAPP_PDU_MSADDR 3
62 #define IAPP_PDU_CAPABILITY 4
63 #define IAPP_PDU_ANNOUNCEINT 5
64 #define IAPP_PDU_HOTIMEOUT 6
65 #define IAPP_PDU_MESSAGEID 7
66 #define IAPP_PDU_PHYTYPE 0x10
67 #define IAPP_PDU_REGDOMAIN 0x11
68 #define IAPP_PDU_CHANNEL 0x12
69 #define IAPP_PDU_BEACONINT 0x13
70 #define IAPP_PDU_OUIIDENT 0x80
71 #define IAPP_PDU_AUTHINFO 0x81
72
73 #define IAPP_CAP_FORWARDING 0x40
74 #define IAPP_CAP_WEP 0x20
75
76 #define IAPP_PHY_PROP 0x00
77 #define IAPP_PHY_FHSS 0x01
78 #define IAPP_PHY_DSSS 0x02
79 #define IAPP_PHY_IR 0x03
80 #define IAPP_PHY_OFDM 0x04
81
82 #define IAPP_DOM_FCC 0x10
83 #define IAPP_DOM_IC 0x20
84 #define IAPP_DOM_ETSI 0x30
85 #define IAPP_DOM_SPAIN 0x31
86 #define IAPP_DOM_FRANCE 0x32
87 #define IAPP_DOM_MKK 0x40
88
89 #define IAPP_AUTH_STATUS 0x01
90 #define IAPP_AUTH_USERNAME 0x02
91 #define IAPP_AUTH_PROVNAME 0x03
92 #define IAPP_AUTH_RXPKTS 0x04
93 #define IAPP_AUTH_TXPKTS 0x05
94 #define IAPP_AUTH_RXBYTES 0x06
95 #define IAPP_AUTH_TXBYTES 0x07
96 #define IAPP_AUTH_LOGINTIME 0x08
97 #define IAPP_AUTH_TIMELIMIT 0x09
98 #define IAPP_AUTH_VOLLIMIT 0x0a
99 #define IAPP_AUTH_ACCCYCLE 0x0b
100 #define IAPP_AUTH_RXGWORDS 0x0c
101 #define IAPP_AUTH_TXGWORDS 0x0d
102 #define IAPP_AUTH_IPADDR 0x0e
103 #define IAPP_AUTH_TRAILER 0xff
104
105
106 typedef struct _e_iapphdr {
107         guint8 ia_version;
108         guint8 ia_type;
109 } e_iapphdr;
110
111 typedef struct _e_pduhdr {
112         guint8 pdu_type;
113         guint8 pdu_len_h;
114         guint8 pdu_len_l;
115 } e_pduhdr;
116
117 static value_string iapp_vals[] = {
118   {IAPP_ANNOUNCE_REQUEST, "Announce Request"},
119   {IAPP_ANNOUNCE_RESPONSE, "Announce Response"},
120   {IAPP_HANDOVER_REQUEST, "Handover Request"},
121   {IAPP_HANDOVER_RESPONSE, "Handover Response"},
122   {0, NULL}};
123
124 static value_string iapp_pdu_type_vals[] = {
125   {IAPP_PDU_SSID, "Network Name"},
126   {IAPP_PDU_BSSID, "BSSID"},
127   {IAPP_PDU_OLDBSSID, "Old BSSID"},
128   {IAPP_PDU_MSADDR, "Mobile Station Address"},
129   {IAPP_PDU_CAPABILITY, "Capabilities"},
130   {IAPP_PDU_ANNOUNCEINT, "Announce Interval"},
131   {IAPP_PDU_HOTIMEOUT, "Handover Timeout"},
132   {IAPP_PDU_MESSAGEID, "Message ID"},
133   {IAPP_PDU_PHYTYPE, "PHY Type"},
134   {IAPP_PDU_REGDOMAIN, "Regulatory Domain"},
135   {IAPP_PDU_CHANNEL, "Radio Channel"},
136   {IAPP_PDU_BEACONINT, "Beacon Interval"},
137   {IAPP_PDU_OUIIDENT, "OUI Identifier"},
138   {IAPP_PDU_AUTHINFO, "ELSA Authentication Info"},
139   {0, NULL}};
140
141 static value_string iapp_cap_vals[] = {
142   {IAPP_CAP_FORWARDING, "Forwarding"},
143   {IAPP_CAP_WEP, "WEP"},
144   {0, NULL}};
145
146 static value_string iapp_phy_vals[] = {
147   {IAPP_PHY_PROP, "Proprietary"},
148   {IAPP_PHY_FHSS, "FHSS"},
149   {IAPP_PHY_DSSS, "DSSS"},
150   {IAPP_PHY_IR, "Infrared"},
151   {IAPP_PHY_OFDM, "OFDM"},
152   {0, NULL}};
153
154 static value_string iapp_dom_vals[] = {
155   {IAPP_DOM_FCC, "FCC (USA)"},
156   {IAPP_DOM_IC, "IC (Canada)"},
157   {IAPP_DOM_ETSI, "ETSI (Europe)"},
158   {IAPP_DOM_SPAIN, "Spain"},
159   {IAPP_DOM_FRANCE, "France"},
160   {IAPP_DOM_MKK, "MKK (Japan)"},
161   {0, NULL}};
162
163 static value_string iapp_auth_type_vals[] = {
164   {IAPP_AUTH_STATUS, "Status"},
165   {IAPP_AUTH_USERNAME, "User Name"},
166   {IAPP_AUTH_PROVNAME, "Provider Name"},
167   {IAPP_AUTH_RXPKTS, "Received Packets"},
168   {IAPP_AUTH_TXPKTS, "Transmitted Packets"},
169   {IAPP_AUTH_RXBYTES, "Received Octets"},
170   {IAPP_AUTH_TXBYTES, "Transmitted Octets"},
171   {IAPP_AUTH_LOGINTIME, "Session Time"},
172   {IAPP_AUTH_TIMELIMIT, "Time Limit"},
173   {IAPP_AUTH_VOLLIMIT, "Volume Limit"},
174   {IAPP_AUTH_ACCCYCLE, "Accounting Cycle"},
175   {IAPP_AUTH_TRAILER, "Authenticator"},
176   {IAPP_AUTH_RXGWORDS, "Received Gigawords"},
177   {IAPP_AUTH_TXGWORDS, "Transmitted Gigawords"},
178   {IAPP_AUTH_IPADDR, "Client IP Address"},
179   {0, NULL}};
180
181
182 /* dissect a capability bit field */
183
184 static void dissect_caps(proto_item *pitem, tvbuff_t *tvb, int offset)
185 {
186         proto_tree *captree;
187         int bit, val, z, thisbit;
188         gchar *strval, bitval[20];
189
190         captree = proto_item_add_subtree(pitem, ett_iapp_cap);
191         val = tvb_get_guint8(tvb, offset + 3);
192
193         bitval[8] = '\0';
194         for (bit = 7; bit >= 0; bit--)
195         {
196                 strval = match_strval(1 << bit, iapp_cap_vals);
197                 if (strval)
198                 {
199                         thisbit = (val & (1 << bit)) ? 1 : 0;
200                         for (z = 0; z < 7; z++)
201                                 if (z == 7 - bit)
202                                         bitval[z] = thisbit + '0';
203                                 else
204                                         bitval[z] = '.';
205                         proto_tree_add_text(captree, tvb, offset + 3, 1, "%s %s: %s",
206                                 bitval, strval, thisbit ? "Yes" : "No");
207                 }
208         }
209 }
210
211 static void
212 append_authval_str(proto_item *ti, int type, int len, tvbuff_t *tvb, int offset)
213 {
214         int z, val;
215
216         proto_item_append_text(ti, " Value: ");
217
218         switch (type)
219         {
220                 case IAPP_AUTH_STATUS:
221                         proto_item_append_text(ti, "%s", tvb_get_guint8(tvb, offset + 3) ? "Authenticated" : "Not authenticated");
222                         break;
223                 case IAPP_AUTH_USERNAME:
224                 case IAPP_AUTH_PROVNAME:
225                         proto_item_append_text(ti, "\"%s\"",
226                                 tvb_format_text(tvb, offset + 3, len));
227                         break;
228                 case IAPP_AUTH_RXPKTS:
229                 case IAPP_AUTH_TXPKTS:
230                 case IAPP_AUTH_RXBYTES:
231                 case IAPP_AUTH_TXBYTES:
232                 case IAPP_AUTH_RXGWORDS:
233                 case IAPP_AUTH_TXGWORDS:
234                 case IAPP_AUTH_VOLLIMIT:
235                         val = tvb_get_ntohl(tvb, offset + 3);
236                         proto_item_append_text(ti, "%d", val);
237                         break;
238                 case IAPP_AUTH_LOGINTIME:
239                 case IAPP_AUTH_TIMELIMIT:
240                 case IAPP_AUTH_ACCCYCLE:
241                         val = tvb_get_ntohl(tvb, offset + 3);
242                         proto_item_append_text(ti, "%d seconds", val);
243                         break;
244                 case IAPP_AUTH_IPADDR:
245                         proto_item_append_text(ti, "%s",
246                                 ip_to_str(tvb_get_ptr(tvb, offset + 3, 4)));
247                         break;
248                 case IAPP_AUTH_TRAILER:
249                         for (z = 0; z < len; z++)
250                                 proto_item_append_text(ti, "%s%02x", z ? " " : "",
251                                         tvb_get_guint8(tvb, offset + 3 + z));
252                         break;
253         }
254 }
255
256 /* dissect authentication info */
257
258 static void dissect_authinfo(proto_item *pitem, tvbuff_t *tvb, int offset, int sumlen)
259 {
260         proto_tree *authtree;
261         proto_item *ti;
262         e_pduhdr pduhdr;
263         int len;
264
265         authtree = proto_item_add_subtree(pitem, ett_iapp_auth);
266
267         while (sumlen > 0)
268         {
269                 tvb_memcpy(tvb, (guint8 *)&pduhdr, offset, sizeof(e_pduhdr));
270                 len = (((int)pduhdr.pdu_len_h) << 8) + pduhdr.pdu_len_l;
271
272                 ti = proto_tree_add_text(authtree, tvb, offset, len + 3,
273                         "%s(%d)",
274                         val_to_str(pduhdr.pdu_type, iapp_auth_type_vals,
275                                 "Unknown PDU Type"),
276                         pduhdr.pdu_type);
277                 append_authval_str(ti, pduhdr.pdu_type, len, tvb, offset);
278
279                 sumlen -= (len + 3);
280                 offset += (len + 3);
281         }
282 }
283
284 /* get displayable values of PDU contents */
285
286 static gboolean
287 append_pduval_str(proto_item *ti, int type, int len, tvbuff_t *tvb, int offset,
288         gboolean is_fhss)
289 {
290         const guint8 *mac;
291         int z, val;
292         gchar *strval;
293
294         proto_item_append_text(ti, " Value: ");
295
296         switch (type)
297         {
298                 case IAPP_PDU_SSID:
299                         proto_item_append_text(ti, "\"%s\"",
300                                 tvb_format_text(tvb, offset + 3, len));
301                         break;
302                 case IAPP_PDU_BSSID:
303                 case IAPP_PDU_OLDBSSID:
304                 case IAPP_PDU_MSADDR:
305                         mac = tvb_get_ptr(tvb, offset + 3, len);
306                         for (z = 0; z < len; z++)
307                                 proto_item_append_text(ti, "%s%02x", z ? ":" : "", mac[z]);
308                         break;
309                 case IAPP_PDU_CAPABILITY:
310                 {
311                         int mask, first = 1;
312
313                         val = tvb_get_guint8(tvb, offset + 3);
314                         proto_item_append_text(ti, "%02x (", val);
315                         for (mask = 0x80; mask; mask >>= 1)
316                                 if (val & mask)
317                                 {
318                                         strval = match_strval(mask, iapp_cap_vals);
319                                         if (strval)
320                                         {
321                                                 if (!first)
322                                                         proto_item_append_text(ti, " ");
323                                                 proto_item_append_text(ti, "%s", strval);
324                                         }
325                                 }
326                         proto_item_append_text(ti, ")");
327                         break;
328                 }
329                 case IAPP_PDU_ANNOUNCEINT:
330                         val = tvb_get_ntohs(tvb, offset + 3);
331                         proto_item_append_text(ti, "%d seconds", val);
332                         break;
333                 case IAPP_PDU_HOTIMEOUT:
334                 case IAPP_PDU_BEACONINT:
335                         val = tvb_get_ntohs(tvb, offset + 3);
336                         proto_item_append_text(ti, "%d Kus", val);
337                         break;
338                 case IAPP_PDU_MESSAGEID:
339                         val = tvb_get_ntohs(tvb, offset + 3);
340                         proto_item_append_text(ti, "%d", val);
341                         break;
342                 case IAPP_PDU_PHYTYPE:
343                         val = tvb_get_guint8(tvb, offset + 3);
344                         strval = val_to_str(val, iapp_phy_vals, "Unknown");
345                         proto_item_append_text(ti, "%s", strval);
346                         is_fhss = (val == IAPP_PHY_FHSS);
347                         break;
348                 case IAPP_PDU_REGDOMAIN:
349                         val = tvb_get_guint8(tvb, offset + 3);
350                         strval = val_to_str(val, iapp_dom_vals, "Unknown");
351                         proto_item_append_text(ti, "%s", strval);
352                         break;
353                 case IAPP_PDU_CHANNEL:
354                         val = tvb_get_guint8(tvb, offset + 3);
355                         if (is_fhss)
356                                 proto_item_append_text(ti, "Pattern set %d, sequence %d",
357                                                 ((val >> 6) & 3) + 1, (val & 31) + 1);
358                         else
359                                 proto_item_append_text(ti, "%d", val);
360                         break;
361                 case IAPP_PDU_OUIIDENT:
362                         for (val = z = 0; z < 3; z++)
363                                 val = (val << 8) | tvb_get_guint8(tvb, offset + 3 + z);
364                         strval = val_to_str(val, oui_vals, "Unknown");
365                         proto_item_append_text(ti, "%s", strval);
366                         break;
367         }
368         return is_fhss;
369 }
370
371 /* code to dissect a list of PDUs */
372
373 static void
374 dissect_pdus(tvbuff_t *tvb, int offset, proto_tree *pdutree, int pdulen)
375 {
376         e_pduhdr pduhdr;
377         int len;
378         proto_item *ti;
379         gboolean is_fhss;
380
381         if (!pdulen)
382         {
383                 proto_tree_add_text(pdutree, tvb, offset, 0, "No PDUs found");
384                 return;
385         }
386
387         is_fhss = FALSE;
388         while (pdulen > 0)
389         {
390                 tvb_memcpy(tvb, (guint8 *)&pduhdr, offset, sizeof(e_pduhdr));
391                 len = (((int)pduhdr.pdu_len_h) << 8) + pduhdr.pdu_len_l;
392
393                 ti = proto_tree_add_text(pdutree, tvb, offset, len + 3,
394                         "%s(%d)",
395                         val_to_str(pduhdr.pdu_type, iapp_pdu_type_vals,
396                                 "Unknown PDU Type"),
397                         pduhdr.pdu_type);
398                 is_fhss = append_pduval_str(ti, pduhdr.pdu_type, len, tvb,
399                         offset, is_fhss);
400
401                 if (pduhdr.pdu_type == IAPP_PDU_CAPABILITY)
402                         dissect_caps(ti, tvb, offset);
403
404                 if (pduhdr.pdu_type == IAPP_PDU_AUTHINFO)
405                         dissect_authinfo(ti, tvb, offset + 3, len);
406
407                 pdulen -= (len + 3);
408                 offset += (len + 3);
409         }
410 }
411
412 /* code to dissect an IAPP packet */
413 static void
414 dissect_iapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
415 {
416         proto_item *ti, *pdutf;
417         proto_tree *iapp_tree, *pdutree;
418         e_iapphdr ih;
419         int ia_version;
420         int ia_type;
421         gchar *codestrval;
422
423         if (check_col(pinfo->cinfo, COL_PROTOCOL))
424                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAPP");
425
426         if (check_col(pinfo->cinfo, COL_INFO))
427                 col_clear(pinfo->cinfo, COL_INFO);
428
429         tvb_memcpy(tvb, (guint8 *)&ih, 0, sizeof(e_iapphdr));
430
431         ia_version = (int)ih.ia_version;
432         ia_type = (int)ih.ia_type;
433         codestrval = val_to_str(ia_type, iapp_vals,  "Unknown Packet");
434         if (check_col(pinfo->cinfo, COL_INFO))
435         {
436                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s(%d) (version=%d)",
437                              codestrval, ia_type, ia_version);
438         }
439
440         if (tree)
441         {
442                 ti = proto_tree_add_item(tree, proto_iapp, tvb, 0, -1, FALSE);
443                 iapp_tree = proto_item_add_subtree(ti, ett_iapp);
444
445                 /* common header for all IAPP frames */
446
447                 proto_tree_add_uint(iapp_tree, hf_iapp_version, tvb, 0, 1,
448                         ih.ia_version);
449                 proto_tree_add_uint_format(iapp_tree, hf_iapp_type, tvb, 1, 1,
450                         ih.ia_type, "Type: %s(%d)", codestrval, ia_type);
451
452                 pdutf = proto_tree_add_text(iapp_tree, tvb, 2, -1,
453                                 "Protocol data units");
454                 pdutree = proto_item_add_subtree(pdutf, ett_iapp_pdu);
455
456                 if (pdutree)
457                 {
458                         dissect_pdus(tvb, 2, pdutree,
459                                 tvb_length_remaining(tvb, 2));
460                 }
461         }
462 }
463
464
465 /* Register the protocol with Ethereal */
466
467 /* this format is require because a script is used to build the C function
468    that calls all the protocol registration.
469 */
470
471 void
472 proto_register_iapp(void)
473 {
474
475 /* Setup list of header fields  See Section 1.6.1 for details*/
476         static hf_register_info hf[] = {
477                 { &hf_iapp_version,
478                         { "Version", "iapp.version", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }
479                 },
480                 { &hf_iapp_type,
481                         { "type", "iapp.type", FT_UINT8, BASE_DEC, NULL, 0x00, "", HFILL }
482                 },
483         };
484
485 /* Setup protocol subtree array */
486         static gint *ett[] = {
487                 &ett_iapp,
488                 &ett_iapp_pdu,
489                 &ett_iapp_cap,
490                 &ett_iapp_auth
491         };
492
493 /* Register the protocol name and description */
494         proto_iapp = proto_register_protocol("Inter-Access-Point Protocol",
495             "IAPP", "iapp");
496
497 /* Required function calls to register the header fields and subtrees used */
498         proto_register_field_array(proto_iapp, hf, array_length(hf));
499         proto_register_subtree_array(ett, array_length(ett));
500 }
501
502
503 /* If this dissector uses sub-dissector registration add a registration routine.
504    This format is required because a script is used to find these routines and
505    create the code that calls these routines.
506 */
507 void
508 proto_reg_handoff_iapp(void)
509 {
510         dissector_handle_t iapp_handle;
511
512         iapp_handle = create_dissector_handle(dissect_iapp, proto_iapp);
513         dissector_add("udp.port", UDP_PORT_IAPP, iapp_handle);
514 }