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