2 * Routines for IAPP dissection
3 * Copyright 2002, Alfred Arnold <aarnold@elsa.de>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/expert.h>
17 #include <wsutil/array.h>
19 void proto_register_iapp(void);
20 void proto_reg_handoff_iapp(void);
22 static dissector_handle_t iapp_handle
;
24 /* Initialize the protocol and registered fields */
25 static int proto_iapp
;
26 static int hf_iapp_version
;
27 static int hf_iapp_type
;
28 static int hf_iapp_cap_forwarding
;
29 static int hf_iapp_cap_wep
;
30 static int hf_iapp_auth_status
;
31 static int hf_iapp_auth_string
;
32 static int hf_iapp_auth_uint
;
33 static int hf_iapp_auth_ipaddr
;
34 static int hf_iapp_auth_trailer
;
35 static int hf_iapp_pdu_ssid
;
36 static int hf_iapp_pdu_bytes
;
37 static int hf_iapp_pdu_uint
;
38 static int hf_iapp_pdu_phytype
;
39 static int hf_iapp_pdu_regdomain
;
40 static int hf_iapp_pdu_oui_ident
;
42 /* Initialize the subtree pointers */
44 static int ett_iapp_pdu
;
45 static int ett_iapp_subpdu
;
46 static int ett_iapp_cap
;
47 static int ett_iapp_auth
;
48 static int ett_iapp_authinfo
;
50 static expert_field ei_iapp_no_pdus
;
52 #define UDP_PORT_IAPP 2313
54 #define IAPP_ANNOUNCE_REQUEST 0
55 #define IAPP_ANNOUNCE_RESPONSE 1
56 #define IAPP_HANDOVER_REQUEST 2
57 #define IAPP_HANDOVER_RESPONSE 3
59 #define IAPP_PDU_SSID 0
60 #define IAPP_PDU_BSSID 1
61 #define IAPP_PDU_OLDBSSID 2
62 #define IAPP_PDU_MSADDR 3
63 #define IAPP_PDU_CAPABILITY 4
64 #define IAPP_PDU_ANNOUNCEINT 5
65 #define IAPP_PDU_HOTIMEOUT 6
66 #define IAPP_PDU_MESSAGEID 7
67 #define IAPP_PDU_PHYTYPE 0x10
68 #define IAPP_PDU_REGDOMAIN 0x11
69 #define IAPP_PDU_CHANNEL 0x12
70 #define IAPP_PDU_BEACONINT 0x13
71 #define IAPP_PDU_OUIIDENT 0x80
72 #define IAPP_PDU_AUTHINFO 0x81
74 #define IAPP_CAP_FORWARDING 0x40
75 #define IAPP_CAP_WEP 0x20
77 #define IAPP_PHY_PROP 0x00
78 #define IAPP_PHY_FHSS 0x01
79 #define IAPP_PHY_DSSS 0x02
80 #define IAPP_PHY_IR 0x03
81 #define IAPP_PHY_OFDM 0x04
83 #define IAPP_DOM_FCC 0x10
84 #define IAPP_DOM_IC 0x20
85 #define IAPP_DOM_ETSI 0x30
86 #define IAPP_DOM_SPAIN 0x31
87 #define IAPP_DOM_FRANCE 0x32
88 #define IAPP_DOM_MKK 0x40
90 #define IAPP_AUTH_STATUS 0x01
91 #define IAPP_AUTH_USERNAME 0x02
92 #define IAPP_AUTH_PROVNAME 0x03
93 #define IAPP_AUTH_RXPKTS 0x04
94 #define IAPP_AUTH_TXPKTS 0x05
95 #define IAPP_AUTH_RXBYTES 0x06
96 #define IAPP_AUTH_TXBYTES 0x07
97 #define IAPP_AUTH_LOGINTIME 0x08
98 #define IAPP_AUTH_TIMELIMIT 0x09
99 #define IAPP_AUTH_VOLLIMIT 0x0a
100 #define IAPP_AUTH_ACCCYCLE 0x0b
101 #define IAPP_AUTH_RXGWORDS 0x0c
102 #define IAPP_AUTH_TXGWORDS 0x0d
103 #define IAPP_AUTH_IPADDR 0x0e
104 #define IAPP_AUTH_TRAILER 0xff
106 static const value_string iapp_vals
[] = {
107 {IAPP_ANNOUNCE_REQUEST
, "Announce Request"},
108 {IAPP_ANNOUNCE_RESPONSE
, "Announce Response"},
109 {IAPP_HANDOVER_REQUEST
, "Handover Request"},
110 {IAPP_HANDOVER_RESPONSE
, "Handover Response"},
114 static const value_string iapp_pdu_type_vals
[] = {
115 {IAPP_PDU_SSID
, "Network Name"},
116 {IAPP_PDU_BSSID
, "BSSID"},
117 {IAPP_PDU_OLDBSSID
, "Old BSSID"},
118 {IAPP_PDU_MSADDR
, "Mobile Station Address"},
119 {IAPP_PDU_CAPABILITY
, "Capabilities"},
120 {IAPP_PDU_ANNOUNCEINT
, "Announce Interval"},
121 {IAPP_PDU_HOTIMEOUT
, "Handover Timeout"},
122 {IAPP_PDU_MESSAGEID
, "Message ID"},
123 {IAPP_PDU_PHYTYPE
, "PHY Type"},
124 {IAPP_PDU_REGDOMAIN
, "Regulatory Domain"},
125 {IAPP_PDU_CHANNEL
, "Radio Channel"},
126 {IAPP_PDU_BEACONINT
, "Beacon Interval"},
127 {IAPP_PDU_OUIIDENT
, "OUI Identifier"},
128 {IAPP_PDU_AUTHINFO
, "ELSA Authentication Info"},
132 static const value_string iapp_phy_vals
[] = {
133 {IAPP_PHY_PROP
, "Proprietary"},
134 {IAPP_PHY_FHSS
, "FHSS"},
135 {IAPP_PHY_DSSS
, "DSSS"},
136 {IAPP_PHY_IR
, "Infrared"},
137 {IAPP_PHY_OFDM
, "OFDM"},
141 static const value_string iapp_dom_vals
[] = {
142 {IAPP_DOM_FCC
, "FCC (USA)"},
143 {IAPP_DOM_IC
, "IC (Canada)"},
144 {IAPP_DOM_ETSI
, "ETSI (Europe)"},
145 {IAPP_DOM_SPAIN
, "Spain"},
146 {IAPP_DOM_FRANCE
, "France"},
147 {IAPP_DOM_MKK
, "MKK (Japan)"},
151 static const value_string iapp_auth_type_vals
[] = {
152 {IAPP_AUTH_STATUS
, "Status"},
153 {IAPP_AUTH_USERNAME
, "User Name"},
154 {IAPP_AUTH_PROVNAME
, "Provider Name"},
155 {IAPP_AUTH_RXPKTS
, "Received Packets"},
156 {IAPP_AUTH_TXPKTS
, "Transmitted Packets"},
157 {IAPP_AUTH_RXBYTES
, "Received Octets"},
158 {IAPP_AUTH_TXBYTES
, "Transmitted Octets"},
159 {IAPP_AUTH_LOGINTIME
, "Session Time"},
160 {IAPP_AUTH_TIMELIMIT
, "Time Limit"},
161 {IAPP_AUTH_VOLLIMIT
, "Volume Limit"},
162 {IAPP_AUTH_ACCCYCLE
, "Accounting Cycle"},
163 {IAPP_AUTH_TRAILER
, "Authenticator"},
164 {IAPP_AUTH_RXGWORDS
, "Received Gigawords"},
165 {IAPP_AUTH_TXGWORDS
, "Transmitted Gigawords"},
166 {IAPP_AUTH_IPADDR
, "Client IP Address"},
171 /* dissect a capability bit field */
173 static void dissect_caps(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
)
177 captree
= proto_tree_add_subtree(tree
, tvb
, offset
, 1, ett_iapp_cap
, NULL
, "Capabilities");
178 proto_tree_add_item(captree
, hf_iapp_cap_forwarding
, tvb
, offset
, 1, ENC_NA
);
179 proto_tree_add_item(captree
, hf_iapp_cap_wep
, tvb
, offset
, 1, ENC_NA
);
183 add_authval_str(proto_tree
*tree
, int type
, int len
, tvbuff_t
*tvb
, int offset
)
189 case IAPP_AUTH_STATUS
:
190 val
= tvb_get_uint8(tvb
, offset
);
191 proto_tree_add_uint_format_value(tree
, hf_iapp_auth_status
, tvb
, offset
, 1, val
, "%s", val
? "Authenticated" : "Not authenticated");
193 case IAPP_AUTH_USERNAME
:
194 case IAPP_AUTH_PROVNAME
:
195 proto_tree_add_item(tree
, hf_iapp_auth_string
, tvb
, offset
, 1, ENC_ASCII
);
197 case IAPP_AUTH_RXPKTS
:
198 case IAPP_AUTH_TXPKTS
:
199 case IAPP_AUTH_RXBYTES
:
200 case IAPP_AUTH_TXBYTES
:
201 case IAPP_AUTH_RXGWORDS
:
202 case IAPP_AUTH_TXGWORDS
:
203 case IAPP_AUTH_VOLLIMIT
:
204 proto_tree_add_item(tree
, hf_iapp_auth_uint
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
206 case IAPP_AUTH_LOGINTIME
:
207 case IAPP_AUTH_TIMELIMIT
:
208 case IAPP_AUTH_ACCCYCLE
:
209 val
= tvb_get_ntohl(tvb
, offset
);
210 proto_tree_add_uint_format_value(tree
, hf_iapp_auth_uint
, tvb
, offset
, 4, val
, "%d seconds", val
);
212 case IAPP_AUTH_IPADDR
:
213 proto_tree_add_item(tree
, hf_iapp_auth_ipaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
215 case IAPP_AUTH_TRAILER
:
216 proto_tree_add_item(tree
, hf_iapp_auth_trailer
, tvb
, offset
, len
, ENC_NA
);
221 /* dissect authentication info */
223 static void dissect_authinfo(proto_item
*pitem
, tvbuff_t
*tvb
, int offset
, int sumlen
)
225 proto_tree
*authtree
, *value_tree
;
229 authtree
= proto_item_add_subtree(pitem
, ett_iapp_auth
);
233 pdu_type
= tvb_get_uint8(tvb
, offset
);
234 len
= tvb_get_ntohs(tvb
, offset
+1);
236 value_tree
= proto_tree_add_subtree_format(authtree
, tvb
, offset
, len
+ 3,
237 ett_iapp_authinfo
, NULL
, "%s (%d)",
238 val_to_str_const(pdu_type
, iapp_auth_type_vals
, "Unknown PDU Type"),
240 add_authval_str(value_tree
, pdu_type
, len
, tvb
, offset
+3);
247 /* get displayable values of PDU contents */
250 append_pduval_str(proto_tree
*tree
, int type
, int len
, tvbuff_t
*tvb
, int offset
,
258 proto_tree_add_item(tree
, hf_iapp_pdu_ssid
, tvb
, offset
, len
, ENC_ASCII
);
261 case IAPP_PDU_OLDBSSID
:
262 case IAPP_PDU_MSADDR
:
263 proto_tree_add_item(tree
, hf_iapp_pdu_bytes
, tvb
, offset
, len
, ENC_NA
);
265 case IAPP_PDU_CAPABILITY
:
266 dissect_caps(tree
, tvb
, offset
);
268 case IAPP_PDU_ANNOUNCEINT
:
269 val
= tvb_get_ntohs(tvb
, offset
);
270 proto_tree_add_uint_format_value(tree
, hf_iapp_pdu_uint
, tvb
, offset
, 2, val
, "%d seconds", val
);
272 case IAPP_PDU_HOTIMEOUT
:
273 case IAPP_PDU_BEACONINT
:
274 val
= tvb_get_ntohs(tvb
, offset
);
275 proto_tree_add_uint_format_value(tree
, hf_iapp_pdu_uint
, tvb
, offset
, 2, val
, "%d Kus", val
);
277 case IAPP_PDU_MESSAGEID
:
278 proto_tree_add_item(tree
, hf_iapp_pdu_uint
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
280 case IAPP_PDU_PHYTYPE
:
281 proto_tree_add_item(tree
, hf_iapp_pdu_phytype
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
282 is_fhss
= (tvb_get_uint8(tvb
, offset
) == IAPP_PHY_FHSS
);
284 case IAPP_PDU_REGDOMAIN
:
285 proto_tree_add_item(tree
, hf_iapp_pdu_regdomain
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
287 case IAPP_PDU_CHANNEL
:
290 val
= tvb_get_uint8(tvb
, offset
);
291 proto_tree_add_uint_format(tree
, hf_iapp_pdu_uint
, tvb
, offset
, 1, val
,
292 "Pattern set %d, sequence %d", ((val
>> 6) & 3) + 1, (val
& 31) + 1);
295 proto_tree_add_item(tree
, hf_iapp_pdu_uint
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
297 case IAPP_PDU_OUIIDENT
:
298 proto_tree_add_item(tree
, hf_iapp_pdu_oui_ident
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
304 /* code to dissect a list of PDUs */
307 dissect_pdus(tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, proto_tree
*pdutree
, proto_item
*pduitem
, int pdulen
)
317 expert_add_info(pinfo
, pduitem
, &ei_iapp_no_pdus
);
324 pdu_type
= tvb_get_uint8(tvb
, offset
);
325 len
= tvb_get_ntohs(tvb
, offset
+1);
327 subtree
= proto_tree_add_subtree_format(pdutree
, tvb
, offset
, len
+ 3,
328 ett_iapp_subpdu
, &ti
, "%s (%d)",
329 val_to_str_const(pdu_type
, iapp_pdu_type_vals
, "Unknown PDU Type"),
331 is_fhss
= append_pduval_str(subtree
, pdu_type
, len
, tvb
,
334 if (pdu_type
== IAPP_PDU_AUTHINFO
)
335 dissect_authinfo(ti
, tvb
, offset
+ 3, len
);
342 /* code to dissect an IAPP packet */
344 dissect_iapp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
346 proto_item
*ti
, *pduitem
;
347 proto_tree
*iapp_tree
, *pdutree
;
350 const char *codestrval
;
352 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IAPP");
354 col_clear(pinfo
->cinfo
, COL_INFO
);
356 ia_version
= tvb_get_uint8(tvb
, 0);
357 ia_type
= tvb_get_uint8(tvb
, 1);
359 codestrval
= val_to_str_const(ia_type
, iapp_vals
, "Unknown Packet");
360 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s(%d) (version=%d)", codestrval
, ia_type
, ia_version
);
362 ti
= proto_tree_add_item(tree
, proto_iapp
, tvb
, 0, -1, ENC_NA
);
363 iapp_tree
= proto_item_add_subtree(ti
, ett_iapp
);
365 /* common header for all IAPP frames */
367 proto_tree_add_item(iapp_tree
, hf_iapp_version
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
368 proto_tree_add_item(iapp_tree
, hf_iapp_type
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
370 pdutree
= proto_tree_add_subtree(iapp_tree
, tvb
, 2, -1,
371 ett_iapp_pdu
, &pduitem
, "Protocol data units");
373 dissect_pdus(tvb
, pinfo
, 2, pdutree
, pduitem
,
374 tvb_captured_length_remaining(tvb
, 2));
376 return tvb_captured_length(tvb
);
380 /* Register the protocol with Wireshark */
382 /* this format is require because a script is used to build the C function
383 that calls all the protocol registration.
387 proto_register_iapp(void)
390 static hf_register_info hf
[] = {
392 { "Version", "iapp.version", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
395 { "Type", "iapp.type", FT_UINT8
, BASE_DEC
, VALS(iapp_vals
), 0x00, NULL
, HFILL
}
397 { &hf_iapp_cap_forwarding
,
398 { "Forwarding", "iapp.cap.forwarding", FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), IAPP_CAP_FORWARDING
, NULL
, HFILL
}
401 { "WEP", "iapp.cap.wep", FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), IAPP_CAP_WEP
, NULL
, HFILL
}
403 { &hf_iapp_auth_status
,
404 { "Status", "iapp.auth.status", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
406 { &hf_iapp_auth_uint
,
407 { "Value", "iapp.auth.uint", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
409 { &hf_iapp_auth_string
,
410 { "Value", "iapp.auth.string", FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
412 { &hf_iapp_auth_ipaddr
,
413 { "IP Address", "iapp.auth.ipaddr", FT_IPv4
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
415 { &hf_iapp_auth_trailer
,
416 { "Trailer", "iapp.auth.trailer", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
419 { "SSID", "iapp.pdu.ssid", FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
421 { &hf_iapp_pdu_bytes
,
422 { "Value", "iapp.pdu.bytes", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
425 { "Value", "iapp.pdu.uint", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
427 { &hf_iapp_pdu_phytype
,
428 { "PHY Type", "iapp.pdu.phytype", FT_UINT8
, BASE_DEC
, VALS(iapp_phy_vals
), 0x00, NULL
, HFILL
}
430 { &hf_iapp_pdu_regdomain
,
431 { "Reg domain", "iapp.pdu.regdomain", FT_UINT8
, BASE_DEC
, VALS(iapp_dom_vals
), 0x00, NULL
, HFILL
}
433 { &hf_iapp_pdu_oui_ident
,
434 { "OUI", "iapp.pdu.oui_ident", FT_UINT24
, BASE_OUI
, NULL
, 0x00, NULL
, HFILL
}
438 static int *ett
[] = {
447 static ei_register_info ei
[] = {
448 { &ei_iapp_no_pdus
, { "iapp.no_pdus", PI_PROTOCOL
, PI_NOTE
, "No PDUs found", EXPFILL
}},
451 expert_module_t
* expert_iapp
;
453 /* Register the protocol name and description */
454 proto_iapp
= proto_register_protocol("Inter-Access-Point Protocol", "IAPP", "iapp");
456 /* Required function calls to register the header fields and subtrees used */
457 proto_register_field_array(proto_iapp
, hf
, array_length(hf
));
458 proto_register_subtree_array(ett
, array_length(ett
));
459 expert_iapp
= expert_register_protocol(proto_iapp
);
460 expert_register_field_array(expert_iapp
, ei
, array_length(ei
));
462 iapp_handle
= register_dissector("iapp", dissect_iapp
, proto_iapp
);
466 /* If this dissector uses sub-dissector registration add a registration routine.
467 This format is required because a script is used to find these routines and
468 create the code that calls these routines.
471 proto_reg_handoff_iapp(void)
473 dissector_add_uint_with_preference("udp.port", UDP_PORT_IAPP
, iapp_handle
);
476 * Editor modelines - https://www.wireshark.org/tools/modelines.html
481 * indent-tabs-mode: nil
484 * vi: set shiftwidth=4 tabstop=8 expandtab:
485 * :indentSize=4:tabSize=8:noTabs=true: