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