From Stephen Fisher:
[obnox/wireshark/wip.git] / epan / dissectors / packet-wlccp.c
1 /* packet-wlccp.c
2  * Routines for Cisco Wireless LAN Context Control Protocol dissection
3  *
4  * Copyright 2005, Joerg Mayer (see AUTHORS file)
5  * Copyright 2006, Stephen Fisher <stephentfisher@yahoo.com>
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * The CISCOWL dissector was merged into this one.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28  */
29
30 /* Version 0x00 was reverse engineered */
31 /* Version 0xC1 Protocol reference: US Patent Application 0050220054 */
32
33 /* More clues to version 0x00 of the protocol:
34  *
35  * Header (Eth V2 or SNAP)
36  * Length (2 bytes)
37  * Type (2 bytes)
38  *      0202: Unknown, Length 36 (14 + 20 + 2)
39  *      4001: Unknown, Length 48 (14 + 32 + 2)
40  *      4601: Unknown, Length 34 (14 + 18 + 2)
41  *      4081 on Eth V2: Name, Version Length 84 (14 + 48 + 20 + 2)
42  *      4081 on 802.3: Name Length 72 (14 + 56 + 2)
43  * Dst MAC (6 bytes)
44  * Src MAC (6 bytes)
45  * Unknown1 (2 bytes)  Unknown19 + Unknown2 may be a MAC address on type 0202
46  * Unknown2 (4 bytes)   see Unknown19
47  * 0 (17 bytes)
48  * Device IP (4 bytes)
49  * 0 (2 bytes)
50  * Device name (8 bytes)
51  * 0 (20 bytes)
52  * Unknown3 (2 bytes)
53  * Unknown4 (4 bytes)
54  * Version string (10 bytes)
55  * 0 (4 bytes)
56  * 0 (2 bytes)
57  */
58
59 #ifdef HAVE_CONFIG_H
60 # include "config.h"
61 #endif
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66
67 #include <glib.h>
68
69 #include <epan/packet.h>
70 #include <epan/prefs.h>
71 #include <epan/etypes.h>
72 #include <epan/oui.h>
73 #include "packet-llc.h"
74
75 static const value_string wlccp_sap_vs[] = {
76         { 0, "Context Management"        },
77         { 2, "Radio Resource Management" },
78         { 0, NULL                        }
79 };
80
81 static const value_string wlccp_subtype_vs[] = {
82         { 0, "Request" },
83         { 1, "Reply"   },
84         { 2, "Confirm" },
85         { 3, "Ack"     },
86         { 0, NULL      }
87 };
88
89 static const value_string wlccp_node_type_vs[] = {
90         { 0, "None"                         },
91         { 1, "Access Point (AP)"            },
92         { 2, "Subnet Context Manager (SCM)" },
93         { 4, "Local Context Manager (LCM)"  },
94         { 8, "Campus Context Manager (CCM)" },
95         { 0x10, "Infrastructure (ICN)"      },
96         { 0x40, "Client"                    },
97         { 0, NULL                           }
98 };
99
100 static const value_string cisco_pid_vals[] = {
101         { 0x0000, "WLCCP" },
102         { 0, NULL         }
103 };
104
105 /* Bit fields in message type */
106 #define MT_SUBTYPE         (0xC0)
107 #define MT_BASE_MSG_TYPE   (0x3F)
108
109 /* Bit fields in flags */
110 #define F_RETRY            (1<<15)
111 #define F_RESPONSE_REQUEST (1<<14)
112 #define F_TLV              (1<<13)
113 #define F_INBOUND          (1<<12)
114 #define F_OUTBOUND         (1<<11)
115 #define F_HOPWISE_ROUTING  (1<<10)
116 #define F_ROOT_CM          (1<<9)
117 #define F_RELAY            (1<<8)
118 #define F_MIC              (1<<7)
119
120 #define WLCCP_UDP_PORT 2887
121 /* WLCCP also uses an LLC OUI type and an ethertype */
122
123 /* Forward declaration we need below */
124 void proto_reg_handoff_wlccp(void);
125
126 /* Initialize the protocol and registered fields */
127 static int proto_wlccp = -1;
128
129 static int hf_llc_wlccp_pid = -1;
130
131 static int hf_wlccp_version = -1;
132
133 static int hf_wlccp_dstmac = -1;
134 static int hf_wlccp_srcmac = -1;
135 static int hf_wlccp_hostname = -1;
136
137 static int hf_wlccp_sap = -1;
138 static int hf_wlccp_destination_node_type = -1;
139 static int hf_wlccp_length = -1;
140 static int hf_wlccp_type = -1;
141 static int hf_wlccp_subtype = -1;
142 static int hf_wlccp_base_message_type = -1;
143 static int hf_wlccp_hops = -1;
144 static int hf_wlccp_msg_id = -1;
145 static int hf_wlccp_flags = -1;
146 static int hf_wlccp_retry_flag = -1;
147 static int hf_wlccp_response_request_flag = -1;
148 static int hf_wlccp_tlv_flag = -1;
149 static int hf_wlccp_inbound_flag = -1;
150 static int hf_wlccp_outbound_flag = -1;
151 static int hf_wlccp_hopwise_routing_flag = -1;
152 static int hf_wlccp_root_cm_flag = -1;
153 static int hf_wlccp_relay_flag = -1;
154 static int hf_wlccp_mic_flag = -1;
155 static int hf_wlccp_originator_node_type = -1;
156 static int hf_wlccp_originator = -1;
157 static int hf_wlccp_responder_node_type = -1;
158 static int hf_wlccp_responder = -1;
159 static int hf_wlccp_relay_node_type = -1;
160 static int hf_wlccp_relay_node_id = -1;
161 static int hf_wlccp_priority = -1;
162 static int hf_wlccp_age = -1;
163 static int hf_wlccp_period = -1;
164 static int hf_wlccp_ipv4_address = -1;
165
166
167 /* Initialize the subtree pointers */
168 static gint ett_wlccp = -1;
169 static gint ett_wlccp_type = -1;
170 static gint ett_wlccp_flags = -1;
171
172 /* Code to actually dissect the packets */
173 static void
174 dissect_wlccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
175 {
176         /* Set up structures needed to add the protocol subtree and manage it */
177         proto_item *ti;
178         proto_tree *wlccp_tree, *wlccp_type_tree, *wlccp_flags_tree;
179         gboolean relay_flag;
180         guint8 version;
181         guint16 type, flags;
182         guint offset = 0;
183
184         /* Make entries in Protocol column and Info column on summary display */
185         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
186                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLCCP");
187
188         if (check_col(pinfo->cinfo, COL_INFO)) {
189                 if(tvb_get_guint8(tvb, 0) == 0xC1) { /* Get the version number */
190                         col_add_fstr(pinfo->cinfo, COL_INFO, "Message subtype: %s",
191                                      match_strval((tvb_get_guint8(tvb, 6)>>6) & 3,
192                                                   wlccp_subtype_vs));
193                 } else {
194                         col_add_str(pinfo->cinfo, COL_INFO, "WLCCP frame");
195                 }
196         }
197
198         if (tree) {
199                 /* create display subtree for the protocol */
200                 ti = proto_tree_add_item(tree, proto_wlccp, tvb, 0, -1, FALSE);
201                 wlccp_tree = proto_item_add_subtree(ti, ett_wlccp);
202
203                 proto_tree_add_item(wlccp_tree, hf_wlccp_version,
204                                     tvb, offset, 1, FALSE);
205                 version = tvb_get_guint8(tvb, 0);
206                 offset += 1;
207
208                 if(version == 0x0) {
209                         proto_tree_add_item(wlccp_tree, hf_wlccp_length,
210                                             tvb, 1, 1, FALSE);
211
212                         proto_tree_add_item(wlccp_tree, hf_wlccp_type,
213                                             tvb, 2, 2, FALSE);
214                         type = tvb_get_ntohs(tvb, 2);
215                 
216                         proto_tree_add_item(wlccp_tree, hf_wlccp_dstmac,
217                                             tvb, 4, 6, FALSE);
218
219                         proto_tree_add_item(wlccp_tree, hf_wlccp_srcmac,
220                                             tvb, 10, 6, FALSE);
221
222                         if(type == 0x4081) {
223                                 proto_tree_add_item(wlccp_tree, hf_wlccp_ipv4_address,
224                                                     tvb, 38, 4, FALSE);
225
226                                 proto_tree_add_item(wlccp_tree, hf_wlccp_hostname,
227                                                     tvb, 44, 28, FALSE);
228                         }
229                 }
230
231                 if(version == 0xC1) {
232                         proto_tree_add_item(wlccp_tree, hf_wlccp_sap,
233                                             tvb, offset, 1, FALSE);
234                         offset += 1;
235
236                         proto_tree_add_item(wlccp_tree, hf_wlccp_destination_node_type,
237                                             tvb, offset, 2, FALSE);
238                         offset += 2;
239                         
240                         proto_tree_add_item(wlccp_tree, hf_wlccp_length,
241                                             tvb, offset, 2, FALSE);
242                         offset += 2;
243                         
244                         ti = proto_tree_add_item(wlccp_tree, hf_wlccp_type,
245                                                  tvb, offset, 1, FALSE);
246                         wlccp_type_tree = proto_item_add_subtree(ti, ett_wlccp_type);
247
248                         proto_tree_add_item(wlccp_type_tree, hf_wlccp_subtype,
249                                             tvb, offset, 1, FALSE);
250                         proto_tree_add_item(wlccp_type_tree, hf_wlccp_base_message_type,
251                                             tvb, offset, 1, FALSE);
252                         offset += 1;
253                         
254                         proto_tree_add_item(wlccp_tree, hf_wlccp_hops,
255                                             tvb, offset, 1, FALSE);
256                         offset += 1;
257                         
258                         proto_tree_add_item(wlccp_tree, hf_wlccp_msg_id,
259                                             tvb, offset, 2, FALSE);
260                         offset += 2;
261                         
262                         ti = proto_tree_add_item(wlccp_tree, hf_wlccp_flags,
263                                                  tvb, offset, 2, FALSE);
264                         flags = tvb_get_ntohs(tvb, offset);
265                         wlccp_flags_tree = proto_item_add_subtree(ti, ett_wlccp_flags);
266
267                         proto_tree_add_item(wlccp_flags_tree, hf_wlccp_retry_flag,
268                                             tvb, offset, 2, FALSE);
269                         
270                         proto_tree_add_item(wlccp_flags_tree,
271                                             hf_wlccp_response_request_flag,
272                                             tvb, offset, 2, FALSE);
273
274                         proto_tree_add_item(wlccp_flags_tree,
275                                             hf_wlccp_tlv_flag,
276                                             tvb, offset, 2, FALSE);
277                         
278                         proto_tree_add_item(wlccp_flags_tree,
279                                             hf_wlccp_inbound_flag,
280                                             tvb, offset, 2, FALSE);
281                         
282                         proto_tree_add_item(wlccp_flags_tree,
283                                             hf_wlccp_outbound_flag,
284                                             tvb, offset, 2, FALSE);
285                         
286                         proto_tree_add_item(wlccp_flags_tree,
287                                             hf_wlccp_hopwise_routing_flag,
288                                             tvb, offset, 2, FALSE);
289                         
290                         proto_tree_add_item(wlccp_flags_tree,
291                                             hf_wlccp_root_cm_flag,
292                                             tvb, offset, 2, FALSE);
293                         
294                         proto_tree_add_item(wlccp_flags_tree,
295                                             hf_wlccp_relay_flag,
296                                             tvb, offset, 2, FALSE);
297                         relay_flag = (tvb_get_ntohs(tvb, offset)>>8) & 1;
298                         
299                         proto_tree_add_item(wlccp_flags_tree,
300                                             hf_wlccp_mic_flag,
301                                             tvb, offset, 2, FALSE);
302                         offset += 2;
303                         
304                         proto_tree_add_item(wlccp_tree, hf_wlccp_originator_node_type,
305                                             tvb, offset, 2, FALSE);
306                         offset += 2;
307                         
308                         proto_tree_add_item(wlccp_tree, hf_wlccp_originator,
309                                             tvb, offset, 6, FALSE);
310                         offset += 6;
311                         
312                         proto_tree_add_item(wlccp_tree, hf_wlccp_responder_node_type,
313                                             tvb, offset, 2, FALSE);
314                         offset += 2;
315
316                         proto_tree_add_item(wlccp_tree, hf_wlccp_responder,
317                                             tvb, offset, 6, FALSE);
318                         offset += 6;
319
320                         offset += 6; /* Skip over MAC address of sender again */
321                         
322                         if(relay_flag) {
323                                 proto_tree_add_item(wlccp_tree, hf_wlccp_relay_node_type,
324                                                     tvb, offset, 2, FALSE);
325                                 offset += 2;
326
327                                 proto_tree_add_item(wlccp_tree, hf_wlccp_relay_node_id,
328                                                     tvb, offset, 6, FALSE);
329                                 offset += 6;
330                         }
331
332                         if(flags == 0x2800) { /* We have extra information at the end of the frame */
333                                 proto_tree_add_item(wlccp_tree, hf_wlccp_priority,
334                                                     tvb, 38, 1, FALSE);
335
336                                 proto_tree_add_item(wlccp_tree, hf_wlccp_age,
337                                                     tvb, 48, 4, FALSE);
338
339                                 proto_tree_add_item(wlccp_tree, hf_wlccp_period,
340                                                     tvb, 55, 1, FALSE);
341
342                                 proto_tree_add_item(wlccp_tree, hf_wlccp_ipv4_address,
343                                                     tvb, 76, 4, FALSE);
344                                 
345                         }
346                 }
347         }
348 }
349
350
351 /* Register the protocol with Wireshark */
352 void
353 proto_register_wlccp(void)
354 {                 
355         /* Setup list of header fields  See Section 1.6.1 for details*/
356         static hf_register_info hf[] = {
357                 { &hf_wlccp_version,
358                   { "Version", "wlccp.version",
359                     FT_UINT8, BASE_HEX, NULL,
360                     0x0, "Protocol ID/Version", HFILL }
361                 },
362
363                 { &hf_wlccp_srcmac,
364                   { "Src MAC", "wlccp.srcmac",
365                     FT_ETHER, BASE_NONE, NULL,
366                     0x0, "Source MAC address", HFILL }
367                 },
368
369                 { &hf_wlccp_dstmac,
370                   { "Dst MAC", "wlccp.dstmac",
371                     FT_ETHER, BASE_NONE, NULL,
372                     0x0, "Destination MAC address", HFILL }
373                 },
374
375                 { &hf_wlccp_hostname,
376                   { "Hostname", "wlccp.hostname",
377                     FT_STRING, BASE_NONE, NULL,
378                     0x0, "Hostname of device", HFILL }
379                 },
380
381                 { &hf_wlccp_sap,
382                   { "SAP", "wlccp.sap",
383                     FT_UINT8, BASE_DEC, VALS(wlccp_sap_vs),
384                     0x0, "Service Access Point ID", HFILL }
385                 },
386
387                 { &hf_wlccp_destination_node_type,
388                   { "Destination node type", "wlccp.destination_node_type",
389                     FT_UINT8, BASE_DEC, VALS(wlccp_node_type_vs),
390                     0x0, "Node type of the hop destination", HFILL }
391                 },
392
393                 { &hf_wlccp_length,
394                   { "Length", "wlccp.length",
395                     FT_UINT16, BASE_DEC, NULL,
396                     0x0, "Length of WLCCP payload (bytes)", HFILL }
397                 },
398
399
400                 { &hf_wlccp_type,
401                   { "Message Type", "wlccp.type",
402                     FT_UINT8, BASE_HEX, NULL,
403                     0x0, "Message Type", HFILL }
404                 },
405
406                 { &hf_wlccp_subtype,
407                   { "Subtype", "wlccp.subtype",
408                     FT_UINT8, BASE_DEC, VALS(wlccp_subtype_vs),
409                     MT_SUBTYPE, "Message Subtype", HFILL }
410                 },
411
412                 { &hf_wlccp_base_message_type,
413                   { "Base message type", "wlccp.base_message_type",
414                     FT_UINT8, BASE_HEX_DEC, NULL,
415                     MT_BASE_MSG_TYPE, "Base message type", HFILL }
416                 },
417
418
419                 { &hf_wlccp_hops,
420                   { "Hops", "wlccp.hops",
421                     FT_UINT8, BASE_DEC, NULL,
422                     0x0, "Number of WLCCP hops", HFILL }
423                 },
424
425                 { &hf_wlccp_msg_id,
426                   { "Message ID", "wlccp.msg_id",
427                     FT_UINT16, BASE_DEC, NULL,
428                     0x0, "Sequence number used to match request/reply pairs",
429                     HFILL }
430                 },
431
432
433                 { &hf_wlccp_flags,
434                   { "Flags", "wlccp.flags",
435                     FT_UINT16, BASE_HEX, NULL,
436                     0x0, "Flags", HFILL }
437                 },
438
439                 { &hf_wlccp_retry_flag,
440                   { "Retry flag", "wlccp.retry_flag",
441                     FT_UINT16, BASE_DEC, NULL,
442                     F_RETRY, "Set on for retransmissions", HFILL }
443                 },
444
445                 { &hf_wlccp_response_request_flag,
446                   { "Response request flag", "wlccp.response_request_flag",
447                     FT_UINT16, BASE_DEC, NULL,
448                     F_RESPONSE_REQUEST, "Set on to request a reply", HFILL }
449                 },
450
451                 { &hf_wlccp_tlv_flag,
452                   { "TLV flag", "wlccp.tlv_flag",
453                     FT_UINT16, BASE_DEC, NULL,
454                     F_TLV, "Set to indicate that optional TLVs follow the fixed fields", HFILL }
455                 },
456
457                 { &hf_wlccp_inbound_flag,
458                   { "Inbound flag", "wlccp.inbound_flag",
459                     FT_UINT16, BASE_DEC, NULL,
460                     F_INBOUND, "Message is inbound to the top of the topology tree", HFILL }
461                 },
462
463                 { &hf_wlccp_outbound_flag,
464                   { "Outbound flag", "wlccp.outbound_flag",
465                     FT_UINT16, BASE_DEC, NULL,
466                     F_OUTBOUND, "Message is outbound from the top of the topology tree", HFILL }
467                 },
468
469                 { &hf_wlccp_hopwise_routing_flag,
470                   { "Hopwise-routing flag", "wlccp.hopwise_routing_flag",
471                     FT_UINT16, BASE_DEC, NULL,
472                     F_HOPWISE_ROUTING, "On to force intermediate access points to process the message also", HFILL }
473                 },
474
475                 { &hf_wlccp_root_cm_flag,
476                   { "Root context manager flag", "wlccp.root_cm_flag",
477                     FT_UINT16, BASE_DEC, NULL,
478                     F_ROOT_CM, "Set to on to send message to the root context manager of the topology tree", HFILL }
479                 },
480
481                 { &hf_wlccp_relay_flag,
482                   { "Relay flag", "wlccp.relay_flag",
483                     FT_UINT16, BASE_DEC, NULL,
484                     F_RELAY, "Signifies that this header is immediately followed by a relay node field", HFILL }
485                 },
486
487                 { &hf_wlccp_mic_flag,
488                   { "MIC flag", "wlccp.mic_flag",
489                     FT_UINT16, BASE_DEC, NULL,
490                     F_MIC, "On in a message that must be authenticated and has an authentication TLV", HFILL }
491                 },
492
493                 { &hf_wlccp_originator_node_type,
494                   { "Originator node type", "wlccp.originator_node_type",
495                     FT_UINT8, BASE_DEC, VALS(wlccp_node_type_vs),
496                     0x0, "Originating device's node type", HFILL }
497                 },
498
499                 { &hf_wlccp_originator,
500                   { "Originator", "wlccp.originator",
501                     FT_ETHER, BASE_NONE, NULL,
502                     0x0, "Originating device's MAC address", HFILL }
503                 },
504
505                 { &hf_wlccp_responder_node_type,
506                   { "Responder node type", "wlccp.responder_node_type",
507                     FT_UINT8, BASE_DEC, VALS(wlccp_node_type_vs),
508                     0x0, "Responding device's node type", HFILL }
509                 },
510
511                 { &hf_wlccp_responder,
512                   { "Responder", "wlccp.responder",
513                     FT_ETHER, BASE_NONE, NULL,
514                     0x0, "Responding device's MAC address", HFILL }
515                 },
516
517                 { &hf_wlccp_relay_node_type,
518                   { "Relay node type", "wlccp.relay_node_type",
519                     FT_UINT8, BASE_DEC, VALS(wlccp_node_type_vs),
520                     0x0, "Type of node which relayed this message", HFILL }
521                 },
522
523                 { &hf_wlccp_relay_node_id,
524                   { "Relay node ID", "wlccp.relay_node_id",
525                     FT_ETHER, BASE_NONE, NULL,
526                     0x0, "Node which relayed this message", HFILL }
527                 },
528
529                 { &hf_wlccp_priority,
530                   { "WDS priority", "wlccp.priority",
531                     FT_UINT8, BASE_DEC, NULL, 0,
532                     "WDS priority of this access point", HFILL }
533                 },
534
535                 { &hf_wlccp_age,
536                   { "Age", "wlccp.age",
537                     FT_UINT32, BASE_DEC, NULL, 0,
538                     "Time since AP became a WDS master", HFILL }
539                 },
540
541                 { &hf_wlccp_period,
542                   { "Period", "wlccp.period",
543                     FT_UINT8, BASE_DEC, NULL, 0,
544                     "Interval between announcements (seconds)", HFILL }
545                 },
546
547                 { &hf_wlccp_ipv4_address,
548                   { "IPv4 Address", "wlccp.ipv4_address",
549                     FT_IPv4, BASE_NONE, NULL, 0,
550                     "IPv4 address of this access point", HFILL }
551                 }
552
553         };
554         
555         /* Setup protocol subtree array */
556         static gint *ett[] = {
557                 &ett_wlccp,
558                 &ett_wlccp_type,
559                 &ett_wlccp_flags
560         };
561
562         /* Register the protocol name and description */
563         proto_wlccp = proto_register_protocol("Cisco Wireless LAN Context Control Protocol", "WLCCP", "wlccp");
564
565         /* Required function calls to register the header fields and subtrees used */
566         proto_register_field_array(proto_wlccp, hf, array_length(hf));
567         proto_register_subtree_array(ett, array_length(ett));
568         
569
570 }
571
572
573 void
574 proto_reg_handoff_wlccp(void)
575 {
576         static gboolean inited = FALSE;
577         
578         if( !inited ) {
579
580                 dissector_handle_t wlccp_handle;
581
582                 wlccp_handle = create_dissector_handle(dissect_wlccp,
583                                                        proto_wlccp);
584
585                 dissector_add("ethertype", ETHERTYPE_WLCCP, wlccp_handle);
586                 dissector_add("udp.port", WLCCP_UDP_PORT, wlccp_handle);
587                 dissector_add("llc.wlccp_pid", 0x0000, wlccp_handle);
588
589                 inited = TRUE;
590         }
591 }
592
593
594 void
595 proto_register_wlccp_oui(void)
596 {
597         static hf_register_info hf[] = {
598                 { &hf_llc_wlccp_pid,
599                   { "PID", "llc.wlccp_pid",
600                     FT_UINT16, BASE_HEX, VALS(cisco_pid_vals),
601                     0x0, "", HFILL }
602                 }
603         };
604         
605         llc_add_oui(OUI_CISCOWL, "llc.wlccp_pid", "Cisco WLCCP OUI PID", hf);
606 }