xref: /netbsd-src/external/bsd/tcpdump/dist/print-lwapp.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
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  * Original code by Carles Kishimoto <carles.kishimoto@gmail.com>
16  */
17 
18 /* \summary: Light Weight Access Point Protocol (LWAPP) printer */
19 
20 /* specification: RFC 5412 */
21 
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-lwapp.c,v 1.8 2023/08/17 20:19:40 christos Exp $");
25 #endif
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include "netdissect-stdinc.h"
32 
33 #include "netdissect.h"
34 #include "extract.h"
35 #include "addrtoname.h"
36 
37 
38 /*
39  * LWAPP transport (common) header
40  *      0                   1                   2                   3
41  *     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
42  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43  *    |VER| RID |C|F|L|    Frag ID    |            Length             |
44  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45  *    |          Status/WLANs         |   Payload...  |
46  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47  *
48  */
49 
50 struct lwapp_transport_header {
51     nd_uint8_t  version;
52     nd_uint8_t  frag_id;
53     nd_uint16_t length;
54     nd_uint16_t status;
55 };
56 
57 /*
58  * LWAPP control header
59  *      0                   1                   2                   3
60  *      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
61  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62  *     |  Message Type |    Seq Num    |      Msg Element Length       |
63  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64  *     |                           Session ID                          |
65  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66  *     |      Msg Element [0..N]       |
67  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68  */
69 
70 struct lwapp_control_header {
71     nd_uint8_t  msg_type;
72     nd_uint8_t  seq_num;
73     nd_uint16_t len;
74     nd_uint32_t session_id;
75 };
76 
77 #define LWAPP_VERSION 0
78 #define	LWAPP_EXTRACT_VERSION(x) (((x)&0xC0)>>6)
79 #define	LWAPP_EXTRACT_RID(x) (((x)&0x38)>>3)
80 #define LWAPP_EXTRACT_CONTROL_BIT(x) (((x)&0x04)>>2)
81 
82 static const struct tok lwapp_header_bits_values[] = {
83     { 0x01, "Last Fragment Bit"},
84     { 0x02, "Fragment Bit"},
85     { 0x04, "Control Bit"},
86     { 0, NULL}
87 };
88 
89 #define	LWAPP_MSGTYPE_DISCOVERY_REQUEST			1
90 #define	LWAPP_MSGTYPE_DISCOVERY_RESPONSE		2
91 #define	LWAPP_MSGTYPE_JOIN_REQUEST			3
92 #define LWAPP_MSGTYPE_JOIN_RESPONSE			4
93 #define LWAPP_MSGTYPE_JOIN_ACK				5
94 #define LWAPP_MSGTYPE_JOIN_CONFIRM			6
95 #define LWAPP_MSGTYPE_CONFIGURE_REQUEST			10
96 #define LWAPP_MSGTYPE_CONFIGURE_RESPONSE		11
97 #define LWAPP_MSGTYPE_CONF_UPDATE_REQUEST		12
98 #define LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE		13
99 #define LWAPP_MSGTYPE_WTP_EVENT_REQUEST			14
100 #define LWAPP_MSGTYPE_WTP_EVENT_RESPONSE		15
101 #define LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST	16
102 #define LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE	17
103 #define LWAPP_MSGTYPE_ECHO_REQUEST			22
104 #define LWAPP_MSGTYPE_ECHO_RESPONSE			23
105 #define LWAPP_MSGTYPE_IMAGE_DATA_REQUEST		24
106 #define LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE		25
107 #define LWAPP_MSGTYPE_RESET_REQUEST			26
108 #define LWAPP_MSGTYPE_RESET_RESPONSE			27
109 #define LWAPP_MSGTYPE_KEY_UPDATE_REQUEST		30
110 #define LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE		31
111 #define LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST		32
112 #define LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE	33
113 #define LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST		34
114 #define LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE		35
115 #define LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION		36
116 #define LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST		37
117 #define LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE		38
118 #define LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST		39
119 #define LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE		40
120 
121 static const struct tok lwapp_msg_type_values[] = {
122     { LWAPP_MSGTYPE_DISCOVERY_REQUEST, "Discovery req"},
123     { LWAPP_MSGTYPE_DISCOVERY_RESPONSE, "Discovery resp"},
124     { LWAPP_MSGTYPE_JOIN_REQUEST, "Join req"},
125     { LWAPP_MSGTYPE_JOIN_RESPONSE, "Join resp"},
126     { LWAPP_MSGTYPE_JOIN_ACK, "Join ack"},
127     { LWAPP_MSGTYPE_JOIN_CONFIRM, "Join confirm"},
128     { LWAPP_MSGTYPE_CONFIGURE_REQUEST, "Configure req"},
129     { LWAPP_MSGTYPE_CONFIGURE_RESPONSE, "Configure resp"},
130     { LWAPP_MSGTYPE_CONF_UPDATE_REQUEST, "Update req"},
131     { LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE, "Update resp"},
132     { LWAPP_MSGTYPE_WTP_EVENT_REQUEST, "WTP event req"},
133     { LWAPP_MSGTYPE_WTP_EVENT_RESPONSE, "WTP event resp"},
134     { LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST, "Change state event req"},
135     { LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE, "Change state event resp"},
136     { LWAPP_MSGTYPE_ECHO_REQUEST, "Echo req"},
137     { LWAPP_MSGTYPE_ECHO_RESPONSE, "Echo resp"},
138     { LWAPP_MSGTYPE_IMAGE_DATA_REQUEST, "Image data req"},
139     { LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE, "Image data resp"},
140     { LWAPP_MSGTYPE_RESET_REQUEST, "Channel status req"},
141     { LWAPP_MSGTYPE_RESET_RESPONSE, "Channel status resp"},
142     { LWAPP_MSGTYPE_KEY_UPDATE_REQUEST, "Key update req"},
143     { LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE, "Key update resp"},
144     { LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST, "Primary discovery req"},
145     { LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE, "Primary discovery resp"},
146     { LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST, "Data transfer req"},
147     { LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE, "Data transfer resp"},
148     { LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION, "Clear config ind"},
149     { LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST, "Wlan config req"},
150     { LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE, "Wlan config resp"},
151     { LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST, "Mobile config req"},
152     { LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE, "Mobile config resp"},
153     { 0, NULL}
154 };
155 
156 /*
157  * LWAPP message elements
158  *
159  * 0                   1                   2                   3
160  * 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
161  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162  * |      Type     |             Length            |   Value ...   |
163  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164  */
165 struct lwapp_message_header {
166     nd_uint8_t  type;
167     nd_uint16_t length;
168 };
169 
170 void
171 lwapp_control_print(netdissect_options *ndo,
172                     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     uint8_t version;
178     u_int tlen;
179     u_int msg_type, msg_tlen;
180 
181     ndo->ndo_protocol = "lwapp_control";
182     tptr=pptr;
183 
184     if (has_ap_ident) {
185         /* check if enough bytes for AP identity */
186         ND_TCHECK_6(tptr);
187         lwapp_trans_header = (const struct lwapp_transport_header *)(pptr+6);
188     } else {
189         lwapp_trans_header = (const struct lwapp_transport_header *)pptr;
190     }
191     ND_TCHECK_SIZE(lwapp_trans_header);
192     version = GET_U_1(lwapp_trans_header->version);
193 
194     /*
195      * Sanity checking of the header.
196      */
197     if (LWAPP_EXTRACT_VERSION(version) != LWAPP_VERSION) {
198 	ND_PRINT("LWAPP version %u packet not supported",
199                LWAPP_EXTRACT_VERSION(version));
200 	return;
201     }
202 
203     /* non-verbose */
204     if (ndo->ndo_vflag < 1) {
205         ND_PRINT("LWAPPv%u, %s frame, Flags [%s], length %u",
206                LWAPP_EXTRACT_VERSION(version),
207                LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data",
208                bittok2str(lwapp_header_bits_values,"none",version&0x07),
209                len);
210         return;
211     }
212 
213     /* ok they seem to want to know everything - lets fully decode it */
214     tlen=GET_BE_U_2(lwapp_trans_header->length);
215 
216     ND_PRINT("LWAPPv%u, %s frame, Radio-id %u, Flags [%s], Frag-id %u, length %u",
217            LWAPP_EXTRACT_VERSION(version),
218            LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data",
219            LWAPP_EXTRACT_RID(version),
220            bittok2str(lwapp_header_bits_values,"none",version&0x07),
221 	   GET_U_1(lwapp_trans_header->frag_id),
222 	   tlen);
223 
224     if (has_ap_ident) {
225         ND_PRINT("\n\tAP identity: %s", GET_ETHERADDR_STRING(tptr));
226         tptr+=sizeof(struct lwapp_transport_header)+6;
227     } else {
228         tptr+=sizeof(struct lwapp_transport_header);
229     }
230 
231     while(tlen!=0) {
232 
233         /* did we capture enough for fully decoding the object header ? */
234         ND_TCHECK_LEN(tptr, sizeof(struct lwapp_control_header));
235         if (tlen < sizeof(struct lwapp_control_header)) {
236             ND_PRINT("\n\t  Msg goes past end of PDU");
237             break;
238         }
239 
240         lwapp_control_header = (const struct lwapp_control_header *)tptr;
241 	msg_tlen = GET_BE_U_2(lwapp_control_header->len);
242         if (tlen < sizeof(struct lwapp_control_header) + msg_tlen) {
243             ND_PRINT("\n\t  Msg goes past end of PDU");
244             break;
245         }
246 
247 	/* print message header */
248 	msg_type = GET_U_1(lwapp_control_header->msg_type);
249         ND_PRINT("\n\t  Msg type: %s (%u), Seqnum: %u, Msg len: %u, Session: 0x%08x",
250                tok2str(lwapp_msg_type_values,"Unknown",msg_type),
251                msg_type,
252                GET_U_1(lwapp_control_header->seq_num),
253                msg_tlen,
254                GET_BE_U_4(lwapp_control_header->session_id));
255 
256         /* did we capture enough for fully decoding the message */
257         ND_TCHECK_LEN(tptr, msg_tlen);
258 
259 	/* XXX - Decode sub messages for each message */
260         switch(msg_type) {
261         case LWAPP_MSGTYPE_DISCOVERY_REQUEST:
262         case LWAPP_MSGTYPE_DISCOVERY_RESPONSE:
263         case LWAPP_MSGTYPE_JOIN_REQUEST:
264         case LWAPP_MSGTYPE_JOIN_RESPONSE:
265         case LWAPP_MSGTYPE_JOIN_ACK:
266         case LWAPP_MSGTYPE_JOIN_CONFIRM:
267         case LWAPP_MSGTYPE_CONFIGURE_REQUEST:
268         case LWAPP_MSGTYPE_CONFIGURE_RESPONSE:
269         case LWAPP_MSGTYPE_CONF_UPDATE_REQUEST:
270         case LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE:
271         case LWAPP_MSGTYPE_WTP_EVENT_REQUEST:
272         case LWAPP_MSGTYPE_WTP_EVENT_RESPONSE:
273         case LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST:
274         case LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE:
275         case LWAPP_MSGTYPE_ECHO_REQUEST:
276         case LWAPP_MSGTYPE_ECHO_RESPONSE:
277         case LWAPP_MSGTYPE_IMAGE_DATA_REQUEST:
278         case LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE:
279         case LWAPP_MSGTYPE_RESET_REQUEST:
280         case LWAPP_MSGTYPE_RESET_RESPONSE:
281         case LWAPP_MSGTYPE_KEY_UPDATE_REQUEST:
282         case LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE:
283         case LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST:
284         case LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE:
285         case LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST:
286         case LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE:
287         case LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION:
288         case LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST:
289         case LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE:
290         case LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST:
291         case LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE:
292         default:
293             break;
294         }
295 
296         tptr += sizeof(struct lwapp_control_header) + msg_tlen;
297         tlen -= sizeof(struct lwapp_control_header) + msg_tlen;
298     }
299     return;
300 
301 trunc:
302     nd_print_trunc(ndo);
303 }
304 
305 void
306 lwapp_data_print(netdissect_options *ndo,
307                  const u_char *pptr, u_int len)
308 {
309     const struct lwapp_transport_header *lwapp_trans_header;
310     const u_char *tptr;
311     u_int tlen;
312     u_int version;
313 
314     ndo->ndo_protocol = "lwapp_data";
315     tptr=pptr;
316 
317     /* check if enough bytes for AP identity */
318     ND_TCHECK_6(tptr);
319     lwapp_trans_header = (const struct lwapp_transport_header *)pptr;
320     ND_TCHECK_SIZE(lwapp_trans_header);
321     version = GET_U_1(lwapp_trans_header->version);
322 
323     /*
324      * Sanity checking of the header.
325      */
326     if (LWAPP_EXTRACT_VERSION(version) != LWAPP_VERSION) {
327         ND_PRINT("LWAPP version %u packet not supported",
328                LWAPP_EXTRACT_VERSION(version));
329         return;
330     }
331 
332     /* non-verbose */
333     if (ndo->ndo_vflag < 1) {
334         ND_PRINT("LWAPPv%u, %s frame, Flags [%s], length %u",
335                LWAPP_EXTRACT_VERSION(version),
336                LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data",
337                bittok2str(lwapp_header_bits_values,"none",version&0x07),
338                len);
339         return;
340     }
341 
342     /* ok they seem to want to know everything - lets fully decode it */
343     tlen=GET_BE_U_2(lwapp_trans_header->length);
344     if (tlen < sizeof(struct lwapp_transport_header)) {
345         ND_PRINT("LWAPPv%u, %s frame, Radio-id  %u, Flags [%s], length %u < transport header length",
346                LWAPP_EXTRACT_VERSION(version),
347                LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data",
348                LWAPP_EXTRACT_RID(version),
349                bittok2str(lwapp_header_bits_values,"none",version&0x07),
350                tlen);
351         return;
352     }
353 
354     ND_PRINT("LWAPPv%u, %s frame, Radio-id  %u, Flags [%s], Frag-id  %u, length %u",
355            LWAPP_EXTRACT_VERSION(version),
356            LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data",
357            LWAPP_EXTRACT_RID(version),
358            bittok2str(lwapp_header_bits_values,"none",version&0x07),
359            GET_U_1(lwapp_trans_header->frag_id),
360            tlen);
361 
362     tptr+=sizeof(struct lwapp_transport_header);
363     tlen-=sizeof(struct lwapp_transport_header);
364 
365     /* FIX - An IEEE 802.11 frame follows - hexdump for now */
366     print_unknown_data(ndo, tptr, "\n\t", tlen);
367 
368     return;
369 
370 trunc:
371     nd_print_trunc(ndo);
372 }
373