1/*
2 * Copyright (c) 1998-2007 The TCPDUMP project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * Support for the Light Weight Access Point Protocol as per draft-ohara-capwap-lwapp-04
16 *
17 * Original code by Carles Kishimoto <carles.kishimoto@gmail.com>
18 */
19
20#ifndef lint
21static const char rcsid[] _U_ =
22"@(#) $Header: /tcpdump/master/tcpdump/print-lwapp.c,v 1.1 2007-07-24 16:07:30 hannes Exp $";
23#endif
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <tcpdump-stdinc.h>
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include "interface.h"
36#include "extract.h"
37#include "addrtoname.h"
38
39/*
40 * LWAPP transport (common) header
41 *      0                   1                   2                   3
42 *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
43 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 *    |VER| RID |C|F|L|    Frag ID    |            Length             |
45 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 *    |          Status/WLANs         |   Payload...  |
47 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 *
49 */
50
51struct lwapp_transport_header {
52    u_int8_t  version;
53    u_int8_t  frag_id;
54    u_int8_t  length[2];
55    u_int16_t status;
56};
57
58/*
59 * LWAPP control header
60 *      0                   1                   2                   3
61 *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
62 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 *     |  Message Type |    Seq Num    |      Msg Element Length       |
64 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 *     |                           Session ID                          |
66 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 *     |      Msg Element [0..N]       |
68 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 */
70
71struct lwapp_control_header {
72    u_int8_t  msg_type;
73    u_int8_t  seq_num;
74    u_int8_t  len[2];
75    u_int8_t  session_id[4];
76};
77
78#define LWAPP_VERSION 0
79#define	LWAPP_EXTRACT_VERSION(x) (((x)&0xC0)>>6)
80#define	LWAPP_EXTRACT_RID(x) (((x)&0x38)>>3)
81#define LWAPP_EXTRACT_CONTROL_BIT(x) (((x)&0x04)>>2)
82
83static const struct tok lwapp_header_bits_values[] = {
84    { 0x01, "Last Fragment Bit"},
85    { 0x02, "Fragment Bit"},
86    { 0x04, "Control Bit"},
87    { 0, NULL}
88};
89
90#define	LWAPP_MSGTYPE_DISCOVERY_REQUEST			1
91#define	LWAPP_MSGTYPE_DISCOVERY_RESPONSE		2
92#define	LWAPP_MSGTYPE_JOIN_REQUEST			3
93#define LWAPP_MSGTYPE_JOIN_RESPONSE			4
94#define LWAPP_MSGTYPE_JOIN_ACK				5
95#define LWAPP_MSGTYPE_JOIN_CONFIRM			6
96#define LWAPP_MSGTYPE_CONFIGURE_REQUEST			10
97#define LWAPP_MSGTYPE_CONFIGURE_RESPONSE		11
98#define LWAPP_MSGTYPE_CONF_UPDATE_REQUEST		12
99#define LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE		13
100#define LWAPP_MSGTYPE_WTP_EVENT_REQUEST			14
101#define LWAPP_MSGTYPE_WTP_EVENT_RESPONSE		15
102#define LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST	16
103#define LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE	17
104#define LWAPP_MSGTYPE_ECHO_REQUEST			22
105#define LWAPP_MSGTYPE_ECHO_RESPONSE			23
106#define LWAPP_MSGTYPE_IMAGE_DATA_REQUEST		24
107#define LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE		25
108#define LWAPP_MSGTYPE_RESET_REQUEST			26
109#define LWAPP_MSGTYPE_RESET_RESPONSE			27
110#define LWAPP_MSGTYPE_KEY_UPDATE_REQUEST		30
111#define LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE		31
112#define LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST		32
113#define LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE	33
114#define LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST		34
115#define LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE		35
116#define LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION		36
117#define LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST		37
118#define LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE		38
119#define LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST		39
120#define LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE		40
121
122static const struct tok lwapp_msg_type_values[] = {
123    { LWAPP_MSGTYPE_DISCOVERY_REQUEST, "Discovery req"},
124    { LWAPP_MSGTYPE_DISCOVERY_RESPONSE, "Discovery resp"},
125    { LWAPP_MSGTYPE_JOIN_REQUEST, "Join req"},
126    { LWAPP_MSGTYPE_JOIN_RESPONSE, "Join resp"},
127    { LWAPP_MSGTYPE_JOIN_ACK, "Join ack"},
128    { LWAPP_MSGTYPE_JOIN_CONFIRM, "Join confirm"},
129    { LWAPP_MSGTYPE_CONFIGURE_REQUEST, "Configure req"},
130    { LWAPP_MSGTYPE_CONFIGURE_RESPONSE, "Configure resp"},
131    { LWAPP_MSGTYPE_CONF_UPDATE_REQUEST, "Update req"},
132    { LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE, "Update resp"},
133    { LWAPP_MSGTYPE_WTP_EVENT_REQUEST, "WTP event req"},
134    { LWAPP_MSGTYPE_WTP_EVENT_RESPONSE, "WTP event resp"},
135    { LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST, "Change state event req"},
136    { LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE, "Change state event resp"},
137    { LWAPP_MSGTYPE_ECHO_REQUEST, "Echo req"},
138    { LWAPP_MSGTYPE_ECHO_RESPONSE, "Echo resp"},
139    { LWAPP_MSGTYPE_IMAGE_DATA_REQUEST, "Image data req"},
140    { LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE, "Image data resp"},
141    { LWAPP_MSGTYPE_RESET_REQUEST, "Channel status req"},
142    { LWAPP_MSGTYPE_RESET_RESPONSE, "Channel status resp"},
143    { LWAPP_MSGTYPE_KEY_UPDATE_REQUEST, "Key update req"},
144    { LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE, "Key update resp"},
145    { LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST, "Primary discovery req"},
146    { LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE, "Primary discovery resp"},
147    { LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST, "Data transfer req"},
148    { LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE, "Data transfer resp"},
149    { LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION, "Clear config ind"},
150    { LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST, "Wlan config req"},
151    { LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE, "Wlan config resp"},
152    { LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST, "Mobile config req"},
153    { LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE, "Mobile config resp"},
154    { 0, NULL}
155};
156
157/*
158 * LWAPP message elements
159 *
160 * 0                   1                   2                   3
161 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
162 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163 * |      Type     |             Length            |   Value ...   |
164 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165 */
166struct lwapp_message_header {
167    u_int8_t type;
168    u_int8_t length[2];
169};
170
171void
172lwapp_control_print(const u_char *pptr, u_int len, int has_ap_ident) {
173
174    const struct lwapp_transport_header *lwapp_trans_header;
175    const struct lwapp_control_header *lwapp_control_header;
176    const u_char *tptr;
177    int  tlen;
178    int  msg_tlen;
179
180    tptr=pptr;
181
182    if (has_ap_ident) {
183        /* check if enough bytes for AP identity */
184        if (!TTEST2(*tptr, 6))
185            goto trunc;
186        lwapp_trans_header = (const struct lwapp_transport_header *)(pptr+6);
187    } else {
188        lwapp_trans_header = (const struct lwapp_transport_header *)pptr;
189    }
190    TCHECK(*lwapp_trans_header);
191
192    /*
193     * Sanity checking of the header.
194     */
195    if (LWAPP_EXTRACT_VERSION(lwapp_trans_header->version) != LWAPP_VERSION) {
196	printf("LWAPP version %u packet not supported",
197               LWAPP_EXTRACT_VERSION(lwapp_trans_header->version));
198	return;
199    }
200
201    /* non-verbose */
202    if (vflag < 1) {
203        printf("LWAPPv%u, %s frame, Flags [%s], length %u",
204               LWAPP_EXTRACT_VERSION(lwapp_trans_header->version),
205               LWAPP_EXTRACT_CONTROL_BIT(lwapp_trans_header->version) ? "Control" : "Data",
206               bittok2str(lwapp_header_bits_values,"none",(lwapp_trans_header->version)&0x07),
207               len);
208        return;
209    }
210
211    /* ok they seem to want to know everything - lets fully decode it */
212    tlen=EXTRACT_16BITS(lwapp_trans_header->length);
213
214    printf("LWAPPv%u, %s frame, Radio-id %u, Flags [%s], Frag-id %u, length %u",
215           LWAPP_EXTRACT_VERSION(lwapp_trans_header->version),
216           LWAPP_EXTRACT_CONTROL_BIT(lwapp_trans_header->version) ? "Control" : "Data",
217           LWAPP_EXTRACT_RID(lwapp_trans_header->version),
218           bittok2str(lwapp_header_bits_values,"none",(lwapp_trans_header->version)&0x07),
219	   lwapp_trans_header->frag_id,
220	   tlen);
221
222    if (has_ap_ident) {
223        printf("\n\tAP identity: %s",
224               etheraddr_string(tptr));
225        tptr+=sizeof(const struct lwapp_transport_header)+6;
226    } else {
227        tptr+=sizeof(const struct lwapp_transport_header);
228    }
229
230    while(tlen>0) {
231
232        /* did we capture enough for fully decoding the object header ? */
233        if (!TTEST2(*tptr, sizeof(struct lwapp_control_header)))
234            goto trunc;
235
236        lwapp_control_header = (const struct lwapp_control_header *)tptr;
237	msg_tlen = EXTRACT_16BITS(lwapp_control_header->len);
238
239	/* print message header */
240        printf("\n\t  Msg type: %s (%u), Seqnum: %u, Msg len: %d, Session: 0x%08x",
241               tok2str(lwapp_msg_type_values,"Unknown",lwapp_control_header->msg_type),
242               lwapp_control_header->msg_type,
243               lwapp_control_header->seq_num,
244               msg_tlen,
245               EXTRACT_32BITS(lwapp_control_header->session_id));
246
247        /* did we capture enough for fully decoding the message */
248        if (!TTEST2(*tptr, msg_tlen))
249            goto trunc;
250
251	/* XXX - Decode sub messages for each message */
252        switch(lwapp_control_header->msg_type) {
253        case LWAPP_MSGTYPE_DISCOVERY_REQUEST:
254        case LWAPP_MSGTYPE_DISCOVERY_RESPONSE:
255        case LWAPP_MSGTYPE_JOIN_REQUEST:
256        case LWAPP_MSGTYPE_JOIN_RESPONSE:
257        case LWAPP_MSGTYPE_JOIN_ACK:
258        case LWAPP_MSGTYPE_JOIN_CONFIRM:
259        case LWAPP_MSGTYPE_CONFIGURE_REQUEST:
260        case LWAPP_MSGTYPE_CONFIGURE_RESPONSE:
261        case LWAPP_MSGTYPE_CONF_UPDATE_REQUEST:
262        case LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE:
263        case LWAPP_MSGTYPE_WTP_EVENT_REQUEST:
264        case LWAPP_MSGTYPE_WTP_EVENT_RESPONSE:
265        case LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST:
266        case LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE:
267        case LWAPP_MSGTYPE_ECHO_REQUEST:
268        case LWAPP_MSGTYPE_ECHO_RESPONSE:
269        case LWAPP_MSGTYPE_IMAGE_DATA_REQUEST:
270        case LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE:
271        case LWAPP_MSGTYPE_RESET_REQUEST:
272        case LWAPP_MSGTYPE_RESET_RESPONSE:
273        case LWAPP_MSGTYPE_KEY_UPDATE_REQUEST:
274        case LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE:
275        case LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST:
276        case LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE:
277        case LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST:
278        case LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE:
279        case LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION:
280        case LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST:
281        case LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE:
282        case LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST:
283        case LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE:
284        default:
285            break;
286        }
287
288        tptr += sizeof(struct lwapp_control_header) + msg_tlen;
289        tlen -= sizeof(struct lwapp_control_header) + msg_tlen;
290    }
291    return;
292
293 trunc:
294    printf("\n\t\t packet exceeded snapshot");
295}
296
297void
298lwapp_data_print(const u_char *pptr, u_int len) {
299
300    const struct lwapp_transport_header *lwapp_trans_header;
301    const u_char *tptr;
302    int tlen;
303
304    tptr=pptr;
305
306    /* check if enough bytes for AP identity */
307    if (!TTEST2(*tptr, 6))
308        goto trunc;
309    lwapp_trans_header = (const struct lwapp_transport_header *)pptr;
310    TCHECK(*lwapp_trans_header);
311
312    /*
313     * Sanity checking of the header.
314     */
315    if (LWAPP_EXTRACT_VERSION(lwapp_trans_header->version) != LWAPP_VERSION) {
316        printf("LWAPP version %u packet not supported",
317               LWAPP_EXTRACT_VERSION(lwapp_trans_header->version));
318        return;
319    }
320
321    /* non-verbose */
322    if (vflag < 1) {
323        printf("LWAPPv%u, %s frame, Flags [%s], length %u",
324               LWAPP_EXTRACT_VERSION(lwapp_trans_header->version),
325               LWAPP_EXTRACT_CONTROL_BIT(lwapp_trans_header->version) ? "Control" : "Data",
326               bittok2str(lwapp_header_bits_values,"none",(lwapp_trans_header->version)&0x07),
327               len);
328        return;
329    }
330
331    /* ok they seem to want to know everything - lets fully decode it */
332    tlen=EXTRACT_16BITS(lwapp_trans_header->length);
333
334    printf("LWAPPv%u, %s frame, Radio-id  %u, Flags [%s], Frag-id  %u, length %u",
335           LWAPP_EXTRACT_VERSION(lwapp_trans_header->version),
336           LWAPP_EXTRACT_CONTROL_BIT(lwapp_trans_header->version) ? "Control" : "Data",
337           LWAPP_EXTRACT_RID(lwapp_trans_header->version),
338           bittok2str(lwapp_header_bits_values,"none",(lwapp_trans_header->version)&0x07),
339           lwapp_trans_header->frag_id,
340           tlen);
341
342    tptr+=sizeof(const struct lwapp_transport_header);
343    tlen-=sizeof(const struct lwapp_transport_header);
344
345    /* FIX - An IEEE 802.11 frame follows - hexdump for now */
346    print_unknown_data(tptr, "\n\t", tlen);
347
348    return;
349
350 trunc:
351    printf("\n\t\t packet exceeded snapshot");
352}
353
354/*
355 * Local Variables:
356 * c-style: whitesmith
357 * c-basic-offset: 8
358 * End:
359 */
360