diff options
Diffstat (limited to 'proto_80211_mac_hdr.c')
-rw-r--r-- | proto_80211_mac_hdr.c | 3627 |
1 files changed, 3627 insertions, 0 deletions
diff --git a/proto_80211_mac_hdr.c b/proto_80211_mac_hdr.c new file mode 100644 index 0000000..a496a1e --- /dev/null +++ b/proto_80211_mac_hdr.c @@ -0,0 +1,3627 @@ +/* + * netsniff-ng - the packet sniffing beast + * Copyright 2012, 2013 Markus Amend <markus@netsniff-ng.org> + * Copyright 2012 Daniel Borkmann <daniel@netsniff-ng.org> + * Subject to the GPL, version 2. + */ + +/* TODO + * check all possible frame combinations for their behavior + * with respect to endianess (little / big) + */ + +#include <stdio.h> +#include <stdint.h> +#include <netinet/in.h> /* for ntohs() */ +#include <asm/byteorder.h> +#include <arpa/inet.h> /* for inet_ntop() */ + +#include "proto.h" +#include "protos.h" +#include "dissector_80211.h" +#include "built_in.h" +#include "pkt_buff.h" +#include "oui.h" + +#define TU 0.001024 + +/* Note: Fields are encoded in little-endian! */ +struct ieee80211_frm_ctrl { + union { + u16 frame_control; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + /* Correct order here ... */ + __extension__ u16 proto_version:2, + type:2, + subtype:4, + to_ds:1, + from_ds:1, + more_frags:1, + retry:1, + power_mgmt:1, + more_data:1, + wep:1, + order:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __extension__ u16 subtype:4, + type:2, + proto_version:2, + order:1, + wep:1, + more_data:1, + power_mgmt:1, + retry:1, + more_frags:1, + from_ds:1, + to_ds:1; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + }; + }; +} __packed; + +/* Management Frame start */ +/* Note: Fields are encoded in little-endian! */ +struct ieee80211_mgmt { + u16 duration; + u8 da[6]; + u8 sa[6]; + u8 bssid[6]; + u16 seq_ctrl; +} __packed; + +struct ieee80211_mgmt_auth { + u16 auth_alg; + u16 auth_transaction; + u16 status_code; + /* possibly followed by Challenge text */ + u8 variable[0]; +} __packed; + +struct ieee80211_mgmt_deauth { + u16 reason_code; +} __packed; + +struct ieee80211_mgmt_assoc_req { + u16 capab_info; + u16 listen_interval; + /* followed by SSID and Supported rates */ + u8 variable[0]; +} __packed; + +struct ieee80211_mgmt_assoc_resp { + u16 capab_info; + u16 status_code; + u16 aid; + /* followed by Supported rates */ + u8 variable[0]; +} __packed; + +struct ieee80211_mgmt_reassoc_resp { + u16 capab_info; + u16 status_code; + u16 aid; + /* followed by Supported rates */ + u8 variable[0]; +} __packed; + +struct ieee80211_mgmt_reassoc_req { + u16 capab_info; + u16 listen_interval; + u8 current_ap[6]; + /* followed by SSID and Supported rates */ + u8 variable[0]; +} __packed; + +struct ieee80211_mgmt_disassoc { + u16 reason_code; +} __packed; + +struct ieee80211_mgmt_probe_req { +} __packed; + +struct ieee80211_mgmt_beacon { + u64 timestamp; + u16 beacon_int; + u16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + u8 variable[0]; +} __packed; + +struct ieee80211_mgmt_probe_resp { + u8 timestamp[8]; + u16 beacon_int; + u16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + u8 variable[0]; +} __packed; +/* Management Frame end */ + +/* Control Frame start */ +/* Note: Fields are encoded in little-endian! */ +struct ieee80211_ctrl { +} __packed; + +struct ieee80211_ctrl_rts { + u16 duration; + u8 da[6]; + u8 sa[6]; +} __packed; + +struct ieee80211_ctrl_cts { + u16 duration; + u8 da[6]; +} __packed; + +struct ieee80211_ctrl_ack { + u16 duration; + u8 da[6]; +} __packed; + +struct ieee80211_ctrl_ps_poll { + u16 aid; + u8 bssid[6]; + u8 sa[6]; +} __packed; + +struct ieee80211_ctrl_cf_end { + u16 duration; + u8 bssid[6]; + u8 sa[6]; +} __packed; + +struct ieee80211_ctrl_cf_end_ack { + u16 duration; + u8 bssid[6]; + u8 sa[6]; +} __packed; +/* Control Frame end */ + +/* Data Frame start */ +/* Note: Fields are encoded in little-endian! */ +struct ieee80211_data { +} __packed; + +/* TODO: Extend */ +/* Data Frame end */ + +struct element_reserved { + u8 len; +} __packed; + +struct element_ssid { + u8 len; + u8 SSID[0]; +} __packed; + +struct element_supp_rates { + u8 len; + u8 rates[0]; +} __packed; + +struct element_fh_ps { + u8 len; + u16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct element_dsss_ps { + u8 len; + u8 curr_ch; +} __packed; + +struct element_cf_ps { + u8 len; + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_dur; + u16 cfp_dur_rem; +} __packed; + +struct element_tim { + u8 len; + u8 dtim_cnt; + u8 dtim_period; + u8 bmp_cntrl; + u8 part_virt_bmp[0]; +} __packed; + +struct element_ibss_ps { + u8 len; + u16 atim_win; +} __packed; + +struct element_country_tripled { + u8 frst_ch; + u8 nr_ch; + u8 max_trans; +} __packed; + +struct element_country { + u8 len; +#if defined(__LITTLE_ENDIAN_BITFIELD) + /* Correct order here ... */ + u8 country_first; + u8 country_sec; + u8 country_third; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 country_third; + u8 country_sec; + u8 country_first; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + /* triplet may repeat */ + struct element_country_tripled tripled [0]; + /* end triplet */ + u8 pad[0]; +} __packed; + +struct element_hop_pp { + u8 len; + u8 prime_radix; + u8 nr_ch; +} __packed; + +struct element_hop_pt { + u8 len; + u8 flag; + u8 nr_sets; + u8 modules; + u8 offs; + u8 rand_tabl[0]; +} __packed; + +struct element_req { + u8 len; + u8 req_elem_idl[0]; +} __packed; + +struct element_bss_load { + u8 len; + u16 station_cnt; + u8 ch_util; + u16 avlb_adm_cap; +} __packed; + +struct element_edca_ps { + u8 len; + u8 qos_inf; + u8 res; + u32 ac_be; + u32 ac_bk; + u32 ac_vi; + u32 ac_vo; +} __packed; + +struct element_tspec { + union { + u32 len_ts_info; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + /* Correct order here ... */ + __extension__ u32 len:8, + traffic_type:1, + tsid:4, + direction:2, + access_policy:2, + aggr:1, + apsd:1, + user_prior:3, + tsinfo_ack_pol:2, + schedule:1, + res:7; +#elif defined(__BIG_ENDIAN_BITFIELD) + __extension__ u32 len:8, + res:7, + schedule:1, + tsinfo_ack_pol:2, + user_prior:3, + apsd:1, + aggr:1, + access_policy:2, + direction:2, + tsid:4, + traffic_type:1; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + }; + }; + u16 nom_msdu_size; + u16 max_msdu_size; + u32 min_srv_intv; + u32 max_srv_intv; + u32 inactive_intv; + u32 susp_intv; + u32 srv_start_time; + u32 min_data_rate; + u32 mean_data_rate; + u32 peak_data_rate; + u32 burst_size; + u32 delay_bound; + u32 min_phy_rate; + u16 surplus_bandw_allow; + u16 med_time; +} __packed; + +struct element_tclas { + u8 len; + u8 user_priority; + u8 frm_class[0]; +} __packed; + +struct element_tclas_frm_class { + u8 type; + u8 mask; + u8 param[0]; +} __packed; + +struct element_tclas_type0 { + u8 sa[6]; + u8 da[6]; + u16 type; +} __packed; + +struct element_tclas_type1 { + u8 version; + u8 subparam[0]; +} __packed; + +struct element_tclas_type1_ip4 { + u32 sa; + u32 da; + u16 sp; + u16 dp; + u8 dscp; + u8 proto; + u8 reserved; +} __packed; + +struct element_tclas_type1_ip6 { + struct in6_addr sa; + struct in6_addr da; + u16 sp; + u16 dp; + union { + u8 flow_label[3]; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __extension__ u8 flow_label3:8; + __extension__ u8 flow_label2:8; + __extension__ u8 flow_label1:8; +#elif defined(__BIG_ENDIAN_BITFIELD) + __extension__ u8 flow_label1:8; + __extension__ u8 flow_label2:8; + __extension__ u8 flow_label3:8; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + }; + }; +} __packed; + +struct element_tclas_type2 { + u16 vlan_tci; +} __packed; + +struct element_tclas_type3 { + u16 offs; + u8 value[0]; + u8 mask[0]; +} __packed; + +struct element_tclas_type4 { + u8 version; + u8 subparam[0]; +} __packed; + +struct element_tclas_type4_ip4 { + u32 sa; + u32 da; + u16 sp; + u16 dp; + u8 dscp; + u8 proto; + u8 reserved; +} __packed; + +struct element_tclas_type4_ip6 { + struct in6_addr sa; + struct in6_addr da; + u16 sp; + u16 dp; + u8 dscp; + u8 nxt_hdr; + union { + u8 flow_label[3]; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __extension__ u8 flow_label3:8; + __extension__ u8 flow_label2:8; + __extension__ u8 flow_label1:8; +#elif defined(__BIG_ENDIAN_BITFIELD) + __extension__ u8 flow_label1:8; + __extension__ u8 flow_label2:8; + __extension__ u8 flow_label3:8; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + }; + }; +} __packed; + +struct element_tclas_type5 { + u8 pcp; + u8 cfi; + u8 vid; +} __packed; + +struct element_schedule { + u8 len; + u16 inf; + u32 start; + u32 serv_intv; + u16 spec_intv; +} __packed; + +struct element_chall_txt { + u8 len; + u8 chall_txt[0]; +} __packed; + +struct element_pwr_constr { + u8 len; + u8 local_pwr_constr; +} __packed; + +struct element_pwr_cap { + u8 len; + u8 min_pwr_cap; + u8 max_pwr_cap; +} __packed; + +struct element_tpc_req { + u8 len; +} __packed; + +struct element_tpc_rep { + u8 len; + u8 trans_pwr; + u8 link_marg; +} __packed; + +struct element_supp_ch { + u8 len; + u8 first_ch_nr[0]; + u8 nr_ch[0]; +} __packed; + +struct element_supp_ch_tuple { + u8 first_ch_nr; + u8 nr_ch; +} __packed; + +struct element_ch_sw_ann { + u8 len; + u8 switch_mode; + u8 new_nr; + u8 switch_cnt; +} __packed; + +struct element_meas_basic { + u8 ch_nr; + u64 start; + u16 dur; +} __packed; + +struct element_meas_cca { + u8 ch_nr; + u64 start; + u16 dur; +} __packed; + +struct element_meas_rpi { + u8 ch_nr; + u64 start; + u16 dur; +} __packed; + +struct element_meas_ch_load { + u8 op_class; + u8 ch_nr; + u16 rand_intv; + u16 dur; + u8 sub[0]; +} __packed; + +struct element_meas_noise { + u8 op_class; + u8 ch_nr; + u16 rand_intv; + u16 dur; + u8 sub[0]; +} __packed; + +struct element_meas_beacon { + u8 op_class; + u8 ch_nr; + u16 rand_intv; + u16 dur; + u8 mode; + u8 bssid[6]; + u8 sub[0]; +} __packed; + +struct element_meas_frame { + u8 op_class; + u8 ch_nr; + u16 rand_intv; + u16 dur; + u8 frame; + u8 mac[6]; + u8 sub[0]; +} __packed; + +struct element_meas_sta { + u8 peer_mac[6]; + u16 rand_intv; + u16 dur; + u8 group_id; + u8 sub[0]; +} __packed; + +struct element_meas_lci { + u8 loc_subj; + u8 latitude_req_res; + u8 longitude_req_res; + u8 altitude_req_res; + u8 sub[0]; +} __packed; + +struct element_meas_trans_str_cat { + u16 rand_intv; + u16 dur; + u8 peer_sta_addr[6]; + u8 traffic_id; + u8 bin_0_range; + u8 sub[0]; +} __packed; + +struct element_meas_mcast_diag { + u16 rand_intv; + u16 dur; + u8 group_mac[6]; + u8 mcast_triggered[0]; + u8 sub[0]; +} __packed; + +struct element_meas_loc_civic { + u8 loc_subj; + u8 civic_loc; + u8 loc_srv_intv_unit; + u16 loc_srv_intv; + u8 sub[0]; +} __packed; + +struct element_meas_loc_id { + u8 loc_subj; + u8 loc_srv_intv_unit; + u16 loc_srv_intv; + u8 sub[0]; +} __packed; + +struct element_meas_pause { + u8 time; + u8 sub[0]; +} __packed; + +struct element_meas_req { + u8 len; + u8 token; + u8 req_mode; + u8 type; + u8 req[0]; +} __packed; + +struct element_meas_rep { + u8 len; + u8 token; + u8 rep_mode; + u8 type; + u8 rep[0]; +} __packed; + +struct element_quiet { + u8 len; + u8 cnt; + u8 period; + u16 dur; + u16 offs; +} __packed; + +struct element_ibss_dfs { + u8 len; + u8 owner[6]; + u8 rec_intv; + u8 ch_map[0]; +} __packed; + +struct element_ibss_dfs_tuple { + u8 ch_nr; + u8 map; +} __packed; + +struct element_erp { + u8 len; + u8 param; +} __packed; + +struct element_ts_del { + u8 len; + u32 delay; +} __packed; + +struct element_tclas_proc { + u8 len; + u8 proc; +} __packed; + +struct element_ht_cap { + u8 len; + union { + u16 info; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + /* Correct order here ... */ + __extension__ u16 ldpc:1, + supp_width:1, + sm_pwr:2, + ht_green:1, + gi_20mhz:1, + gi_40mhz:1, + tx_stbc:1, + rx_stbc:2, + ht_ack:1, + max_msdu_length:1, + dsss_ck_mode:1, + res:1, + forty_int:1, + prot_supp:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __extension__ u16 rx_stbc:2, + ht_ack:1, + max_msdu_length:1, + dsss_ck_mode:1, + res:1, + forty_int:1, + prot_supp:1, + ldpc:1, + supp_width:1, + sm_pwr:2, + ht_green:1, + gi_20mhz:1, + gi_40mhz:1, + tx_stbc:1; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + }; + }; + u8 param; + union { + u8 mcs_set[16]; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + /* Correct order here ... */ + __extension__ u8 bitmask1:8; + __extension__ u8 bitmask2:8; + __extension__ u8 bitmask3:8; + __extension__ u8 bitmask4:8; + __extension__ u8 bitmask5:8; + __extension__ u8 bitmask6:8; + __extension__ u8 bitmask7:8; + __extension__ u8 bitmask8:8; + __extension__ u8 bitmask9:8; + __extension__ u8 bitmask10_res:8; + __extension__ u16 supp_rate_res:16; + __extension__ u32 tx_param_res:32; + +#elif defined(__BIG_ENDIAN_BITFIELD) + __extension__ u32 tx_param_res:32; + __extension__ u16 supp_rate_res:16; + __extension__ u8 bitmask10_res:8; + __extension__ u8 bitmask9:8; + __extension__ u8 bitmask8:8; + __extension__ u8 bitmask7:8; + __extension__ u8 bitmask6:8; + __extension__ u8 bitmask5:8; + __extension__ u8 bitmask4:8; + __extension__ u8 bitmask3:8; + __extension__ u8 bitmask2:8; + __extension__ u8 bitmask1:8; +#else +# error "Adjust your <asm/byteorder.h> defines" +#endif + }; + }; + u16 ext_cap; + u32 beam_cap; + u8 asel_cap; +} __packed; + +struct element_qos_cap { + u8 len; + u8 info; +} __packed; + +struct element_ext_supp_rates { + u8 len; + u8 rates[0]; +} __packed; + +struct element_vend_spec { + u8 len; + u8 oui[0]; + u8 specific[0]; +} __packed; + +static int8_t len_neq_error(u8 len, u8 intended) +{ + if(intended != len) { + tprintf("Length should be %u Bytes", intended); + return 1; + } + + return 0; +} + +static int8_t len_lt_error(u8 len, u8 intended) +{ + if(len < intended) { + tprintf("Length should be greater %u Bytes", intended); + return 1; + } + + return 0; +} + +static float data_rates(u8 id) +{ + /* XXX Why not (id / 2.f)? */ + switch (id) { + case 2: return 1.0f; + case 3: return 1.5f; + case 4: return 2.0f; + case 5: return 2.5f; + case 6: return 3.0f; + case 9: return 4.5f; + case 11: return 5.5f; + case 12: return 6.0f; + case 18: return 9.0f; + case 22: return 11.0f; + case 24: return 12.0f; + case 27: return 13.5f; + case 36: return 18.0f; + case 44: return 22.0f; + case 48: return 24.0f; + case 54: return 27.0f; + case 66: return 33.0f; + case 72: return 36.0f; + case 96: return 48.0f; + case 108: return 54.0f; + } + + return 0.f; +} + +struct subelement { + u8 id; + u8 len; + u8 data[0]; +} __packed; + + +static int8_t subelements(struct pkt_buff *pkt, u8 len) +{ + u8 i, j; + u8 *data; + + for (i=0; i<len;) { + struct subelement *sub; + + sub = (struct subelement *) pkt_pull(pkt, sizeof(*sub)); + if (sub == NULL) + return 0; + + tprintf(", Subelement ID %u, ", sub->id); + tprintf("Length %u, ", sub->len); + + data = pkt_pull(pkt, sub->len); + if (data == NULL) + return 0; + + tprintf("Data: 0x"); + for(j=0; j < sub->len; j++) + tprintf("%.2x ", data[j]); + + i += sub->len + 1; + } + + /* Not needed ?! Should break before*/ + /* + *if (i != len) { + * tprintf("Length error"); + * return 0; + *} + */ + + return 1; +} + +static int8_t inf_reserved(struct pkt_buff *pkt, u8 *id) +{ + u8 i; + u8 *data; + struct element_reserved *reserved; + + reserved = (struct element_reserved *) pkt_pull(pkt, sizeof(*reserved)); + if (reserved == NULL) + return 0; + + tprintf("Reserved (%u, Len (%u)): ", *id, reserved->len); + + data = pkt_pull(pkt, reserved->len); + if (data == NULL) + return 0; + + tprintf("Data 0x"); + for (i = 0; i < reserved->len; i++) + tprintf("%.2x", data[i]); + + return 1; +} + +static int8_t inf_ssid(struct pkt_buff *pkt, u8 *id) +{ + u8 i; + struct element_ssid *ssid; + char *ssid_name; + + ssid = (struct element_ssid *) pkt_pull(pkt, sizeof(*ssid)); + if (ssid == NULL) + return 0; + + tprintf(" SSID (%u, Len (%u)): ", *id, ssid->len); + + if ((ssid->len - sizeof(*ssid) + 1) > 0) { + ssid_name = (char *) pkt_pull(pkt, ssid->len); + if (ssid_name == NULL) + return 0; + + for (i = 0; i < ssid->len; i++) + tprintf("%c",ssid_name[i]); + } else { + tprintf("Wildcard SSID"); + } + + return 1; +} + +static int8_t inf_supp_rates(struct pkt_buff *pkt, u8 *id) +{ + u8 i; + u8 *rates; + struct element_supp_rates *supp_rates; + + supp_rates = (struct element_supp_rates *) + pkt_pull(pkt, sizeof(*supp_rates)); + if (supp_rates == NULL) + return 0; + + tprintf(" Supp. Rates (%u, Len (%u)): ", *id, supp_rates->len); + if (len_lt_error(supp_rates->len, 1)) + return 0; + + if ((supp_rates->len - sizeof(*supp_rates) + 1) > 0) { + rates = pkt_pull(pkt, supp_rates->len); + if (rates == NULL) + return 0; + + for (i = 0; i < supp_rates->len; i++) + tprintf("%g%s ", ((rates[i] & 0x80) >> 7) ? + data_rates(rates[i] & 0x3f) : + ((rates[i] & 0x3f) * 0.5), + ((rates[i] & 0x80) >> 7) ? "(B)" : ""); + return 1; + } + + return 0; +} + +static int8_t inf_fh_ps(struct pkt_buff *pkt, u8 *id) +{ + struct element_fh_ps *fh_ps; + + fh_ps = (struct element_fh_ps *) pkt_pull(pkt, sizeof(*fh_ps)); + if (fh_ps == NULL) + return 0; + + tprintf(" FH Param Set (%u, Len(%u)): ", *id, fh_ps->len); + if (len_neq_error(fh_ps->len, 5)) + return 0; + tprintf("Dwell Time: %fs, ", le16_to_cpu(fh_ps->dwell_time) * TU); + tprintf("HopSet: %u, ", fh_ps->hop_set); + tprintf("HopPattern: %u, ", fh_ps->hop_pattern); + tprintf("HopIndex: %u", fh_ps->hop_index); + + return 1; +} + +static int8_t inf_dsss_ps(struct pkt_buff *pkt, u8 *id) +{ + struct element_dsss_ps *dsss_ps; + + dsss_ps = (struct element_dsss_ps *) pkt_pull(pkt, sizeof(*dsss_ps)); + if (dsss_ps == NULL) + return 0; + + tprintf(" DSSS Param Set (%u, Len(%u)): ", *id, dsss_ps->len); + if (len_neq_error(dsss_ps->len, 1)) + return 0; + tprintf("Current Channel: %u", dsss_ps->curr_ch); + + return 1; +} + +static int8_t inf_cf_ps(struct pkt_buff *pkt, u8 *id) +{ + struct element_cf_ps *cf_ps; + + cf_ps = (struct element_cf_ps *) pkt_pull(pkt, sizeof(*cf_ps)); + if (cf_ps == NULL) + return 0; + + tprintf(" CF Param Set (%u, Len(%u)): ", *id, cf_ps->len); + if (len_neq_error(cf_ps->len, 6)) + return 0; + tprintf("CFP Count: %u, ", cf_ps->cfp_cnt); + tprintf("CFP Period: %u, ", cf_ps->cfp_period); + tprintf("CFP MaxDur: %fs, ", le16_to_cpu(cf_ps->cfp_max_dur) * TU); + tprintf("CFP DurRem: %fs", le16_to_cpu(cf_ps->cfp_dur_rem) * TU); + + return 1; +} + +static int8_t inf_tim(struct pkt_buff *pkt, u8 *id) +{ + struct element_tim *tim; + u8 i; + + tim = (struct element_tim *) pkt_pull(pkt, sizeof(*tim)); + if (tim == NULL) + return 0; + + tprintf(" TIM (%u, Len(%u)): ", *id, tim->len); + if (len_lt_error(tim->len, 3)) + return 0; + tprintf("DTIM Count: %u, ", tim->dtim_cnt); + tprintf("DTIM Period: %u, ", tim->dtim_period); + tprintf("Bitmap Control: %u, ", tim->bmp_cntrl); + if ((tim->len - sizeof(*tim) + 1) > 0) { + u8 *bmp = pkt_pull(pkt, (tim->len - sizeof(*tim) + 1)); + if (bmp == NULL) + return 0; + + tprintf("Partial Virtual Bitmap: 0x"); + for (i = 0; i < (tim->len - sizeof(*tim) + 1); i++) + tprintf("%.2x", bmp[i]); + } + + return 1; +} + +static int8_t inf_ibss_ps(struct pkt_buff *pkt, u8 *id) +{ + struct element_ibss_ps *ibss_ps; + + ibss_ps = (struct element_ibss_ps *) pkt_pull(pkt, sizeof(*ibss_ps)); + if (ibss_ps == NULL) + return 0; + + tprintf(" IBSS Param Set (%u, Len(%u)): ", *id, ibss_ps->len); + if (len_neq_error(ibss_ps->len, 2)) + return 0; + tprintf("ATIM Window: %fs", le16_to_cpu(ibss_ps->atim_win) * TU); + + return 1; +} + +static int8_t inf_country(struct pkt_buff *pkt, u8 *id) +{ + u8 i; + u8 *pad; + struct element_country *country; + + country = (struct element_country *) pkt_pull(pkt, sizeof(*country)); + if (country == NULL) + return 0; + + tprintf(" Country (%u, Len(%u)): ", *id, country->len); + if (len_lt_error(country->len, 6)) + return 0; + tprintf("Country String: %c%c%c", country->country_first, + country->country_sec, country->country_third); + + for (i = country->len % 3; i < (country->len - 3); i += 3) { + struct element_country_tripled *country_tripled; + + country_tripled = (struct element_country_tripled *) + pkt_pull(pkt, sizeof(*country_tripled)); + if (country_tripled == NULL) + return 0; + + if(country_tripled->frst_ch >= 201) { + tprintf("Oper Ext ID: %u, ", country_tripled->frst_ch); + tprintf("Operating Class: %u, ", country_tripled->nr_ch); + tprintf("Coverage Class: %u", country_tripled->max_trans); + } else { + tprintf("First Ch Nr: %u, ", country_tripled->frst_ch); + tprintf("Nr of Ch: %u, ", country_tripled->nr_ch); + tprintf("Max Transmit Pwr Lvl: %u", country_tripled->max_trans); + } + } + + if(country->len % 3) { + pad = pkt_pull(pkt, 1); + if (pad == NULL) + return 0; + + tprintf(", Pad: 0x%x", *pad); + } + + return 1; +} + +static int8_t inf_hop_pp(struct pkt_buff *pkt, u8 *id) +{ + struct element_hop_pp *hop_pp; + + hop_pp = (struct element_hop_pp *) pkt_pull(pkt, sizeof(*hop_pp)); + if (hop_pp == NULL) + return 0; + + tprintf(" Hopping Pattern Param (%u, Len(%u)): ", *id, hop_pp->len); + if (len_neq_error(hop_pp->len, 2)) + return 0; + tprintf("Prime Radix: %u, ", hop_pp->prime_radix); + tprintf("Nr of Ch: %u", hop_pp->nr_ch); + + return 1; +} + +static int8_t inf_hop_pt(struct pkt_buff *pkt, u8 *id) +{ + int i; + u8 *rand_tabl; + struct element_hop_pt *hop_pt; + + hop_pt = (struct element_hop_pt *) pkt_pull(pkt, sizeof(*hop_pt)); + if (hop_pt == NULL) + return 0; + + tprintf(" Hopping Pattern Table (%u, Len(%u)): ", *id, hop_pt->len); + if (len_lt_error(hop_pt->len, 4)) + return 0; + tprintf("Flag: %u, ", hop_pt->flag); + tprintf("Nr of Sets: %u, ", hop_pt->nr_sets); + tprintf("Modulus: %u, ", hop_pt->modules); + tprintf("Offs: %u", hop_pt->offs); + + if ((hop_pt->len - sizeof(*hop_pt) + 1) > 0) { + rand_tabl = pkt_pull(pkt, (hop_pt->len - sizeof(*hop_pt) + 1)); + if (rand_tabl == NULL) + return 0; + + tprintf(", Rand table: 0x"); + for (i = 0; i < (hop_pt->len - sizeof(*hop_pt) + 1); i++) + tprintf("%.2x", rand_tabl[i]); + } + + return 1; +} + +static int8_t inf_req(struct pkt_buff *pkt, u8 *id) +{ + int i; + struct element_req *req; + u8 *req_ids; + + req = (struct element_req *) pkt_pull(pkt, sizeof(*req)); + if (req == NULL) + return 0; + + tprintf(" Request Element (%u, Len(%u)): ", *id, req->len); + if ((req->len - sizeof(*req) + 1) > 0) { + req_ids = pkt_pull(pkt, (req->len - sizeof(*req) + 1)); + if (req_ids == NULL) + return 0; + + tprintf(", Requested Element IDs: "); + for (i = 0; i < (req->len - sizeof(*req) + 1); i++) + tprintf("%u ", req_ids[i]); + } + + return 1; +} + +static int8_t inf_bss_load(struct pkt_buff *pkt, u8 *id) +{ + struct element_bss_load *bss_load; + + bss_load = (struct element_bss_load *) pkt_pull(pkt, sizeof(*bss_load)); + if (bss_load == NULL) + return 0; + + tprintf(" BSS Load element (%u, Len(%u)): ", *id, bss_load->len); + if (len_neq_error(bss_load->len, 5)) + return 0; + tprintf("Station Count: %u, ", le16_to_cpu(bss_load->station_cnt)); + tprintf("Channel Utilization: %u, ", bss_load->ch_util); + tprintf("Available Admission Capacity: %uus", + bss_load->avlb_adm_cap * 32); + + return 1; +} + +static int8_t inf_edca_ps(struct pkt_buff *pkt, u8 *id) +{ + u32 ac_be, ac_bk, ac_vi, ac_vo; + struct element_edca_ps *edca_ps; + + edca_ps = (struct element_edca_ps *) pkt_pull(pkt, sizeof(*edca_ps)); + if (edca_ps == NULL) + return 0; + + ac_be = le32_to_cpu(edca_ps->ac_be); + ac_bk = le32_to_cpu(edca_ps->ac_bk); + ac_vi = le32_to_cpu(edca_ps->ac_vi); + ac_vo = le32_to_cpu(edca_ps->ac_vo); + + tprintf(" EDCA Param Set (%u, Len(%u)): ", *id, edca_ps->len); + if (len_neq_error(edca_ps->len, 18)) + return 0; + tprintf("QoS Info: 0x%x (-> EDCA Param Set Update Count (%u)," + "Q-Ack (%u), Queue Re (%u), TXOP Req(%u), Res(%u)), ", + edca_ps->qos_inf, edca_ps->qos_inf >> 4, + (edca_ps->qos_inf >> 3) & 1, (edca_ps->qos_inf >> 2) & 1, + (edca_ps->qos_inf >> 1) & 1, edca_ps->qos_inf & 1); + tprintf("Reserved: 0x%x, ", edca_ps->res); + tprintf("AC_BE Param Rec: 0x%x (-> AIFSN (%u), ACM (%u), ACI (%u)," + "Res (%u), ECWmin (%u), ECWmax(%u)), TXOP Limit (%uus)), ", ac_be, + ac_be >> 28, (ac_be >> 27) & 1, (ac_be >> 25) & 3, + (ac_be >> 24) & 1, (ac_be >> 20) & 15, (ac_be >> 16) & 15, + bswap_16(ac_be & 0xFFFF) * 32); + tprintf("AC_BK Param Rec: 0x%x (-> AIFSN (%u), ACM (%u), ACI (%u)," + "Res (%u), ECWmin (%u), ECWmax(%u)), TXOP Limit (%uus)), ", ac_bk, + ac_bk >> 28, (ac_bk >> 27) & 1, (ac_bk >> 25) & 3, + (ac_bk >> 24) & 1, (ac_bk >> 20) & 15, (ac_bk >> 16) & 15, + bswap_16(ac_bk & 0xFFFF) * 32); + tprintf("AC_VI Param Rec: 0x%x (-> AIFSN (%u), ACM (%u), ACI (%u)," + "Res (%u), ECWmin (%u), ECWmax(%u)), TXOP Limit (%uus)), ", ac_vi, + ac_vi >> 28, (ac_vi >> 27) & 1, (ac_vi >> 25) & 3, + (ac_vi >> 24) & 1, (ac_vi >> 20) & 15, (ac_vi >> 16) & 15, + bswap_16(ac_vi & 0xFFFF) * 32); + tprintf("AC_VO Param Rec: 0x%x (-> AIFSN (%u), ACM (%u), ACI (%u)," + "Res (%u), ECWmin (%u), ECWmax(%u)), TXOP Limit (%uus)", ac_vo, + ac_vo >> 28, (ac_vo >> 27) & 1, (ac_vo >> 25) & 3, + (ac_vo >> 24) & 1, (ac_vo >> 20) & 15, (ac_vo >> 16) & 15, + bswap_16(ac_vo & 0xFFFF) * 32); + + return 1; +} + +static int8_t inf_tspec(struct pkt_buff *pkt, u8 *id) +{ + u16 nom_msdu_size, surplus_bandw_allow; + struct element_tspec *tspec; + + tspec = (struct element_tspec *) pkt_pull(pkt, sizeof(*tspec)); + if (tspec == NULL) + return 0; + + nom_msdu_size = le16_to_cpu(tspec->nom_msdu_size); + surplus_bandw_allow = le16_to_cpu(tspec->surplus_bandw_allow); + + tprintf(" TSPEC (%u, Len(%u)): ", *id, tspec->len); + if (len_neq_error(tspec->len, 55)) + return 0; + tprintf("Traffic Type: %u, ", tspec->traffic_type); + tprintf("TSID: %u, ", tspec->tsid); + tprintf("Direction: %u, ", tspec->direction); + tprintf("Access Policy: %u, ", tspec->access_policy); + tprintf("Aggregation: %u, ", tspec->aggr); + tprintf("APSD: %u, ", tspec->apsd); + tprintf("User Priority: %u, ", tspec->user_prior); + tprintf("TSinfo Ack Policy: %u, ", tspec->tsinfo_ack_pol); + tprintf("Schedule: %u, ", tspec->schedule); + tprintf("Reserved: 0x%x, ", tspec->res); + tprintf("Nominal MSDU Size: %uB (Fixed (%u)), ", + nom_msdu_size >> 1, nom_msdu_size & 1); + tprintf("Maximum MSDU Size: %uB, ", le16_to_cpu(tspec->max_msdu_size)); + tprintf("Minimum Service Interval: %uus, ", + le32_to_cpu(tspec->min_srv_intv)); + tprintf("Maximum Service Interval: %uus, ", + le32_to_cpu(tspec->max_srv_intv)); + tprintf("Inactivity Interval: %uus, ", + le32_to_cpu(tspec->inactive_intv)); + tprintf("Suspension Interval: %uus, ", le32_to_cpu(tspec->susp_intv)); + tprintf("Service Start Time: %uus, ", + le32_to_cpu(tspec->srv_start_time)); + tprintf("Minimum Data Rate: %ub/s, ",le32_to_cpu(tspec->min_data_rate)); + tprintf("Mean Data Rate: %ub/s, ", le32_to_cpu(tspec->mean_data_rate)); + tprintf("Peak Data Rate: %ub/s, ",le32_to_cpu(tspec->peak_data_rate)); + tprintf("Burst Size: %uB, ", le32_to_cpu(tspec->burst_size)); + tprintf("Delay Bound: %uus, ", le32_to_cpu(tspec->delay_bound)); + tprintf("Minimum PHY Rate: %ub/s, ", le32_to_cpu(tspec->min_phy_rate)); + tprintf("Surplus Bandwidth: %u.%u, ", surplus_bandw_allow >> 13, + surplus_bandw_allow & 0x1FFF); + tprintf("Medium Time: %uus", le16_to_cpu(tspec->med_time) * 32); + + return 1; +} + +static const char *class_type(u8 type) +{ + switch (type) { + case 0: return "Ethernet parameters"; + case 1: return "TCP/UDP IP parameters"; + case 2: return "IEEE 802.1Q parameters"; + case 3: return "Filter Offset parameters"; + case 4: return "IP and higher layer parameters"; + case 5: return "IEEE 802.1D/Q parameters"; + default: return "Reserved"; + } +} + +static int8_t inf_tclas(struct pkt_buff *pkt, u8 *id) +{ + struct element_tclas *tclas; + struct element_tclas_frm_class *frm_class; + + tclas = (struct element_tclas *) pkt_pull(pkt, sizeof(*tclas)); + if (tclas == NULL) + return 0; + + frm_class = (struct element_tclas_frm_class *) + pkt_pull(pkt, sizeof(*frm_class)); + if (frm_class == NULL) + return 0; + + tprintf(" TCLAS (%u, Len(%u)): ", *id, tclas->len); + if (len_lt_error(tclas->len, 3)) + return 0; + tprintf("User Priority: %u, ", tclas->user_priority); + tprintf("Classifier Type: %s (%u), ", class_type(frm_class->type), + frm_class->type); + tprintf("Classifier Mask: 0x%x, ", frm_class->mask); + + if(frm_class->type == 0) { + struct element_tclas_type0 *type0; + + type0 = (struct element_tclas_type0 *) + pkt_pull(pkt, sizeof(*type0)); + if (type0 == NULL) + return 0; + + /* I think little endian, like the rest */ + tprintf("Src Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, ", + type0->sa[5], type0->sa[4], type0->sa[3], + type0->sa[2], type0->sa[1], type0->sa[0]); + tprintf("Dst Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, ", + type0->da[5], type0->da[4], type0->da[3], + type0->da[2], type0->da[1], type0->da[0]); + tprintf("Type: 0x%x", le16_to_cpu(type0->type)); + } + else if(frm_class->type == 1) { + struct element_tclas_type1 *type1; + + type1 = (struct element_tclas_type1 *) + pkt_pull(pkt, sizeof(*type1)); + if (type1 == NULL) + return 0; + + tprintf("Version: %u, ", type1->version); + /* big endian format follows */ + if(type1->version == 4) { + struct element_tclas_type1_ip4 *type1_ip4; + char src_ip[INET_ADDRSTRLEN]; + char dst_ip[INET_ADDRSTRLEN]; + + type1_ip4 = (struct element_tclas_type1_ip4 *) + pkt_pull(pkt, sizeof(*type1_ip4)); + if (type1_ip4 == NULL) + return 0; + + inet_ntop(AF_INET, &type1_ip4->sa, src_ip, sizeof(src_ip)); + inet_ntop(AF_INET, &type1_ip4->da, dst_ip, sizeof(dst_ip)); + + tprintf("Src IP: %s, ", src_ip); + tprintf("Dst IP: %s, ", dst_ip); + tprintf("Src Port: %u, ", ntohs(type1_ip4->sp)); + tprintf("Dst Port: %u, ", ntohs(type1_ip4->dp)); + tprintf("DSCP: 0x%x, ", type1_ip4->dscp); + tprintf("Proto: %u, ", type1_ip4->proto); + tprintf("Res: 0x%x", type1_ip4->reserved); + } + else if(type1->version == 6) { + struct element_tclas_type1_ip6 *type1_ip6; + char src_ip[INET6_ADDRSTRLEN]; + char dst_ip[INET6_ADDRSTRLEN]; + + type1_ip6 = (struct element_tclas_type1_ip6 *) + pkt_pull(pkt, sizeof(*type1_ip6)); + if (type1_ip6 == NULL) + return 0; + + inet_ntop(AF_INET6, &type1_ip6->sa, + src_ip, sizeof(src_ip)); + inet_ntop(AF_INET6, &type1_ip6->da, + dst_ip, sizeof(dst_ip)); + + tprintf("Src IP: %s, ", src_ip); + tprintf("Dst IP: %s, ", dst_ip); + tprintf("Src Port: %u, ", ntohs(type1_ip6->sp)); + tprintf("Dst Port: %u, ", ntohs(type1_ip6->dp)); + tprintf("Flow Label: 0x%x%x%x", type1_ip6->flow_label1, + type1_ip6->flow_label2, type1_ip6->flow_label3); + } + else { + tprintf("Version (%u) not supported", type1->version); + return 0; + } + + } + else if(frm_class->type == 2) { + struct element_tclas_type2 *type2; + + type2 = (struct element_tclas_type2 *) + pkt_pull(pkt, sizeof(*type2)); + if (type2 == NULL) + return 0; + + tprintf("802.1Q VLAN TCI: 0x%x", ntohs(type2->vlan_tci)); + } + else if(frm_class->type == 3) { + struct element_tclas_type3 *type3; + u8 len, i; + u8 *val; + + type3 = (struct element_tclas_type3 *) + pkt_pull(pkt, sizeof(*type3)); + if (type3 == NULL) + return 0; + + len = (tclas->len - 5) / 2; + + tprintf("Filter Offset: %u, ", type3->offs); + + if((len & 1) || (len_lt_error(tclas->len, 5))) { + tprintf("Length of TCLAS (%u) not correct", tclas->len); + return 0; + } + else { + val = pkt_pull(pkt, len); + if (val == NULL) + return 0; + + tprintf("Filter Value: 0x"); + for (i = 0; i < len / 2; i++) + tprintf("%x ", val[i]); + tprintf(", "); + tprintf("Filter Mask: 0x"); + for (i = len / 2; i < len; i++) + tprintf("%x ", val[i]); + } + + } + else if(frm_class->type == 4) { + struct element_tclas_type4 *type4; + + type4 = (struct element_tclas_type4 *) + pkt_pull(pkt, sizeof(*type4)); + if (type4 == NULL) + return 0; + + tprintf("Version: %u, ", type4->version); + /* big endian format follows */ + if(type4->version == 4) { + struct element_tclas_type4_ip4 *type4_ip4; + char src_ip[INET_ADDRSTRLEN]; + char dst_ip[INET_ADDRSTRLEN]; + + type4_ip4 = (struct element_tclas_type4_ip4 *) + pkt_pull(pkt, sizeof(*type4_ip4)); + if (type4_ip4 == NULL) + return 0; + + inet_ntop(AF_INET, &type4_ip4->sa, src_ip, sizeof(src_ip)); + inet_ntop(AF_INET, &type4_ip4->da, dst_ip, sizeof(dst_ip)); + + tprintf("Src IP: %s, ", src_ip); + tprintf("Dst IP: %s, ", dst_ip); + tprintf("Src Port: %u, ", ntohs(type4_ip4->sp)); + tprintf("Dst Port: %u, ", ntohs(type4_ip4->dp)); + tprintf("DSCP: 0x%x, ", type4_ip4->dscp); + tprintf("Proto: %u, ", type4_ip4->proto); + tprintf("Res: 0x%x", type4_ip4->reserved); + } + else if(type4->version == 6) { + struct element_tclas_type4_ip6 *type4_ip6; + char src_ip[INET6_ADDRSTRLEN]; + char dst_ip[INET6_ADDRSTRLEN]; + + type4_ip6 = (struct element_tclas_type4_ip6 *) + pkt_pull(pkt, sizeof(*type4_ip6)); + if (type4_ip6 == NULL) + return 0; + + inet_ntop(AF_INET6, &type4_ip6->sa, + src_ip, sizeof(src_ip)); + inet_ntop(AF_INET6, &type4_ip6->da, + dst_ip, sizeof(dst_ip)); + + tprintf("Src IP: %s, ", src_ip); + tprintf("Dst IP: %s, ", dst_ip); + tprintf("Src Port: %u, ", ntohs(type4_ip6->sp)); + tprintf("Dst Port: %u, ", ntohs(type4_ip6->dp)); + tprintf("DSCP: 0x%x, ", type4_ip6->dscp); + tprintf("Nxt Hdr: %u, ", type4_ip6->nxt_hdr); + tprintf("Flow Label: 0x%x%x%x", type4_ip6->flow_label1, + type4_ip6->flow_label2, type4_ip6->flow_label3); + } + else { + tprintf("Version (%u) not supported", type4->version); + return 0; + } + } + else if(frm_class->type == 5) { + struct element_tclas_type5 *type5; + + type5 = (struct element_tclas_type5 *) + pkt_pull(pkt, sizeof(*type5)); + if (type5 == NULL) + return 0; + + tprintf("802.1Q PCP: 0x%x, ", type5->pcp); + tprintf("802.1Q CFI: 0x%x, ", type5->cfi); + tprintf("802.1Q VID: 0x%x", type5->vid); + } + else { + tprintf("Classifier Type (%u) not supported", frm_class->type); + return 0; + } + + return 1; +} + +static int8_t inf_sched(struct pkt_buff *pkt, u8 *id) +{ + struct element_schedule *schedule; + u16 info; + + schedule = (struct element_schedule *) pkt_pull(pkt, sizeof(*schedule)); + if (schedule == NULL) + return 0; + + info = le16_to_cpu(schedule->inf); + + tprintf(" Schedule (%u, Len(%u)): ", *id, schedule->len); + if (len_neq_error(schedule->len, 12)) + return 0; + + tprintf("Aggregation: %u, ", info >> 15); + tprintf("TSID: %u, ", (info >> 11) & 0xF); + tprintf("Direction: %u, ", (info >> 9) & 0x3); + tprintf("Res: %u, ", info & 0x1FF); + tprintf("Serv Start Time: %uus, ", le32_to_cpu(schedule->start)); + tprintf("Serv Interval: %uus, ", le32_to_cpu(schedule->serv_intv)); + tprintf("Spec Interval: %fs", le32_to_cpu(schedule->spec_intv) * TU); + + return 1; +} + +static int8_t inf_chall_txt(struct pkt_buff *pkt, u8 *id) +{ + struct element_chall_txt *chall_txt; + u8 i; + u8 *txt; + + chall_txt = (struct element_chall_txt *) + pkt_pull(pkt, sizeof(*chall_txt)); + if (chall_txt == NULL) + return 0; + + tprintf(" Challenge Text (%u, Len(%u)): ", *id, chall_txt->len); + if ((chall_txt->len - sizeof(*chall_txt) + 1) > 0) { + txt = pkt_pull(pkt, (chall_txt->len - sizeof(*chall_txt) + 1)); + if (txt == NULL) + return 0; + + tprintf("0x"); + for (i = 0; i < (chall_txt->len - sizeof(*chall_txt) + 1); i++) + tprintf("%x", txt[i]); + } + + return 1; +} + +static int8_t inf_pwr_constr(struct pkt_buff *pkt, u8 *id) +{ + struct element_pwr_constr *pwr_constr; + + pwr_constr = (struct element_pwr_constr *) pkt_pull(pkt, sizeof(*pwr_constr)); + if (pwr_constr == NULL) + return 0; + + tprintf(" Power Constraint (%u, Len(%u)): ", *id, pwr_constr->len); + if (len_neq_error(pwr_constr->len, 1)) + return 0; + + tprintf("Local Power Constraint: %udB", pwr_constr->local_pwr_constr); + + return 1; +} + +static int8_t inf_pwr_cap(struct pkt_buff *pkt, u8 *id) +{ + struct element_pwr_cap *pwr_cap; + + pwr_cap = (struct element_pwr_cap *) pkt_pull(pkt, sizeof(*pwr_cap)); + if (pwr_cap == NULL) + return 0; + + tprintf(" Power Capability (%u, Len(%u)): ", *id, pwr_cap->len); + if (len_neq_error(pwr_cap->len, 2)) + return 0; + + tprintf("Min. Transm. Pwr Cap.: %ddBm, ", (int8_t)pwr_cap->min_pwr_cap); + tprintf("Max. Transm. Pwr Cap.: %ddBm", (int8_t)pwr_cap->max_pwr_cap); + + return 1; +} + +static int8_t inf_tpc_req(struct pkt_buff *pkt, u8 *id) +{ + struct element_tpc_req *tpc_req; + + tpc_req = (struct element_tpc_req *) pkt_pull(pkt, sizeof(*tpc_req)); + if (tpc_req == NULL) + return 0; + + tprintf(" TPC Request (%u, Len(%u))", *id, tpc_req->len); + if (len_neq_error(tpc_req->len, 0)) + return 0; + + return 1; +} + +static int8_t inf_tpc_rep(struct pkt_buff *pkt, u8 *id) +{ + struct element_tpc_rep *tpc_rep; + + tpc_rep = (struct element_tpc_rep *) pkt_pull(pkt, sizeof(*tpc_rep)); + if (tpc_rep == NULL) + return 0; + + tprintf(" TPC Report (%u, Len(%u)): ", *id, tpc_rep->len); + if (len_neq_error(tpc_rep->len, 2)) + return 0; + + tprintf("Transmit Power: %udBm, ", (int8_t)tpc_rep->trans_pwr); + tprintf("Link Margin: %udB", (int8_t)tpc_rep->trans_pwr); + + return 1; +} + +static int8_t inf_supp_ch(struct pkt_buff *pkt, u8 *id) +{ + struct element_supp_ch *supp_ch; + u8 i; + + supp_ch = (struct element_supp_ch *) pkt_pull(pkt, sizeof(*supp_ch)); + if (supp_ch == NULL) + return 0; + + tprintf(" Supp Channels (%u, Len(%u)): ", *id, supp_ch->len); + if (len_lt_error(supp_ch->len, 2)) + return 0; + + if(supp_ch->len & 1) { + tprintf("Length should be even"); + return 0; + } + + for (i = 0; i < supp_ch->len; i += 2) { + struct element_supp_ch_tuple *supp_ch_tuple; + + supp_ch_tuple = (struct element_supp_ch_tuple *) + pkt_pull(pkt, sizeof(*supp_ch_tuple)); + if (supp_ch_tuple == NULL) + return 0; + + tprintf("First Channel Nr: %u, ", supp_ch_tuple->first_ch_nr); + tprintf("Nr of Channels: %u, ", supp_ch_tuple->nr_ch); + } + + return 1; +} + +static int8_t inf_ch_sw_ann(struct pkt_buff *pkt, u8 *id) +{ + struct element_ch_sw_ann *ch_sw_ann; + + ch_sw_ann = (struct element_ch_sw_ann *) + pkt_pull(pkt, sizeof(*ch_sw_ann)); + if (ch_sw_ann == NULL) + return 0; + + tprintf(" Channel Switch Announc (%u, Len(%u)): ", *id, ch_sw_ann->len); + if (len_neq_error(ch_sw_ann->len, 3)) + return 0; + + tprintf("Switch Mode: %u, ", ch_sw_ann->switch_mode); + tprintf("New Nr: %u, ", ch_sw_ann->new_nr); + tprintf("Switch Count: %u", ch_sw_ann->switch_cnt); + + return 1; +} + +static const char *meas_type(u8 type) +{ + switch (type) { + case 0: return "Basic"; + case 1: return "Clear Channel assesment (CCA)"; + case 2: return "Receive power indication (RPI) histogram"; + case 3: return "Channel load"; + case 4: return "Noise histogram"; + case 5: return "Beacon"; + case 6: return "Frame"; + case 7: return "STA statistics"; + case 8: return "LCI"; + case 9: return "Transmit stream/category measurement"; + case 10: return "Multicast diagnostics"; + case 11: return "Location Civic"; + case 12: return "Location Identifier"; + case 13 ... 255: return "Reserved"; + } +} + +static int8_t inf_meas_req(struct pkt_buff *pkt, u8 *id) +{ + struct element_meas_req *meas_req; + + meas_req = (struct element_meas_req *) pkt_pull(pkt, sizeof(*meas_req)); + if (meas_req == NULL) + return 0; + + tprintf(" Measurement Req (%u, Len(%u)): ", *id, meas_req->len); + if (len_lt_error(meas_req->len, 3)) + return 0; + + tprintf("Token: %u, ", meas_req->token); + tprintf("Req Mode: 0x%x (Parallel (%u), Enable(%u), Request(%u), " + "Report(%u), Dur Mand(%u), Res(0x%x)), ", meas_req->req_mode, + meas_req->req_mode & 0x1, + (meas_req->req_mode >> 1) & 0x1, + (meas_req->req_mode >> 2) & 0x1, + (meas_req->req_mode >> 3) & 0x1, + (meas_req->req_mode >> 4) & 0x1, + meas_req->req_mode >> 7); + tprintf("Type: %s (%u), ", meas_type(meas_req->type), meas_req->type); + + if(meas_req->len > 3) { + if(meas_req->type == 0) { + struct element_meas_basic *basic; + + basic = (struct element_meas_basic *) + pkt_pull(pkt, sizeof(*basic)); + if (basic == NULL) + return 0; + + if ((meas_req->len - 3 - sizeof(*basic)) != 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Ch Nr: %uus, ", basic->ch_nr); + tprintf("Meas Start Time: %lu, ", + le64_to_cpu(basic->start)); + tprintf("Meas Duration: %fs", + le16_to_cpu(basic->dur) * TU); + + } + else if(meas_req->type == 1) { + struct element_meas_cca *cca; + + cca = (struct element_meas_cca *) + pkt_pull(pkt, sizeof(*cca)); + if (cca == NULL) + return 0; + + if ((meas_req->len - 3 - sizeof(*cca)) != 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Ch Nr: %uus, ", cca->ch_nr); + tprintf("Meas Start Time: %lu, ", + le64_to_cpu(cca->start)); + tprintf("Meas Duration: %fs", + le16_to_cpu(cca->dur) * TU); + } + else if(meas_req->type == 2) { + struct element_meas_rpi *rpi; + + rpi = (struct element_meas_rpi *) + pkt_pull(pkt, sizeof(*rpi)); + if (rpi == NULL) + return 0; + + if ((meas_req->len - 3 - sizeof(*rpi)) != 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Ch Nr: %uus, ", rpi->ch_nr); + tprintf("Meas Start Time: %lu, ", + le64_to_cpu(rpi->start)); + tprintf("Meas Duration: %fs", + le16_to_cpu(rpi->dur) * TU); + } + else if(meas_req->type == 3) { + struct element_meas_ch_load *ch_load; + + ch_load = (struct element_meas_ch_load *) + pkt_pull(pkt, sizeof(*ch_load)); + if (ch_load == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*ch_load)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("OP Class: %u, ", ch_load->op_class); + tprintf("Ch Nr: %u, ", ch_load->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(ch_load->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(ch_load->dur) * TU); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*ch_load))) + return 0; + } + else if(meas_req->type == 4) { + struct element_meas_noise *noise; + + noise = (struct element_meas_noise *) + pkt_pull(pkt, sizeof(*noise)); + if (noise == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*noise)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("OP Class: %u, ", noise->op_class); + tprintf("Ch Nr: %u, ", noise->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(noise->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(noise->dur) * TU); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*noise))) + return 0; + } + else if(meas_req->type == 5) { + struct element_meas_beacon *beacon; + + beacon = (struct element_meas_beacon *) + pkt_pull(pkt, sizeof(*beacon)); + if (beacon == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*beacon)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("OP Class: %u, ", beacon->op_class); + tprintf("Ch Nr: %u, ", beacon->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(beacon->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(beacon->dur) * TU); + tprintf("Mode: %u, ", beacon->mode); + tprintf("BSSID: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + beacon->bssid[0], beacon->bssid[1], + beacon->bssid[2], beacon->bssid[3], + beacon->bssid[4], beacon->bssid[5]); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*beacon))) + return 0; + } + else if(meas_req->type == 6) { + struct element_meas_frame *frame; + + frame = (struct element_meas_frame *) + pkt_pull(pkt, sizeof(*frame)); + if (frame == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*frame)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("OP Class: %u, ", frame->op_class); + tprintf("Ch Nr: %u, ", frame->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(frame->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(frame->dur) * TU); + tprintf("Request Type: %u, ", frame->frame); + tprintf("MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + frame->mac[0], frame->mac[1], + frame->mac[2], frame->mac[3], + frame->mac[4], frame->mac[5]); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*frame))) + return 0; + } + else if(meas_req->type == 7) { + struct element_meas_sta *sta; + + sta = (struct element_meas_sta *) + pkt_pull(pkt, sizeof(*sta)); + if (sta == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*sta)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Peer MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + sta->peer_mac[0], sta->peer_mac[1], + sta->peer_mac[2], sta->peer_mac[3], + sta->peer_mac[4], sta->peer_mac[5]); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(sta->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(sta->dur) * TU); + tprintf("Group ID: %u, ", sta->group_id); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*sta))) + return 0; + } + else if(meas_req->type == 8) { + struct element_meas_lci *lci; + + lci = (struct element_meas_lci *) + pkt_pull(pkt, sizeof(*lci)); + if (lci == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*lci)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Location Subj: %u, ", lci->loc_subj); + tprintf("Latitude Req Res: %udeg", + lci->latitude_req_res); + tprintf("Longitude Req Res: %udeg", + lci->longitude_req_res); + tprintf("Altitude Req Res: %udeg", + lci->altitude_req_res); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*lci))) + return 0; + } + else if(meas_req->type == 9) { + struct element_meas_trans_str_cat *trans; + + trans = (struct element_meas_trans_str_cat *) + pkt_pull(pkt, sizeof(*trans)); + if (trans == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*trans)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Rand Intv: %fs, ", + le16_to_cpu(trans->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(trans->dur) * TU); + tprintf("MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + trans->peer_sta_addr[0], trans->peer_sta_addr[1], + trans->peer_sta_addr[2], trans->peer_sta_addr[3], + trans->peer_sta_addr[4], trans->peer_sta_addr[5]); + tprintf("Traffic ID: %u, ", trans->traffic_id); + tprintf("Bin 0 Range: %u, ", trans->bin_0_range); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*trans))) + return 0; + } + else if(meas_req->type == 10) { + struct element_meas_mcast_diag *mcast; + + mcast = (struct element_meas_mcast_diag *) + pkt_pull(pkt, sizeof(*mcast)); + if (mcast == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*mcast)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Rand Intv: %fs, ", + le16_to_cpu(mcast->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(mcast->dur) * TU); + tprintf("Group MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + mcast->group_mac[0], mcast->group_mac[1], + mcast->group_mac[2], mcast->group_mac[3], + mcast->group_mac[4], mcast->group_mac[5]); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*mcast))) + return 0; + } + else if(meas_req->type == 11) { + struct element_meas_loc_civic *civic; + + civic = (struct element_meas_loc_civic *) + pkt_pull(pkt, sizeof(*civic)); + if (civic == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*civic)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Location Subj: %u, ", civic->loc_subj); + tprintf("Type: %u, ", civic->civic_loc); + tprintf("Srv Intv Units: %u, ", + le16_to_cpu(civic->loc_srv_intv_unit)); + tprintf("Srv Intv: %u, ", civic->loc_srv_intv); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*civic))) + return 0; + } + else if(meas_req->type == 12) { + struct element_meas_loc_id *id; + + id = (struct element_meas_loc_id *) + pkt_pull(pkt, sizeof(*id)); + if (id == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*id)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Location Subj: %u, ", id->loc_subj); + tprintf("Srv Intv Units: %u, ", + le16_to_cpu(id->loc_srv_intv_unit)); + tprintf("Srv Intv: %u", id->loc_srv_intv); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*id))) + return 0; + } + else if(meas_req->type == 255) { + struct element_meas_pause *pause; + + pause = (struct element_meas_pause *) + pkt_pull(pkt, sizeof(*pause)); + if (pause == NULL) + return 0; + + if ((ssize_t)(meas_req->len - 3 - sizeof(*pause)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_req->type); + return 0; + } + + tprintf("Pause Time: %fs, ", pause->time * 10 * TU); + + if(!subelements(pkt, + meas_req->len - 3 - sizeof(*pause))) + return 0; + } + else { + tprintf("Length field indicates data," + " but could not interpreted"); + return 0; + } + } + + return 1; +} + +static int8_t inf_meas_rep(struct pkt_buff *pkt, u8 *id) +{ + struct element_meas_rep *meas_rep; + + meas_rep = (struct element_meas_rep *) pkt_pull(pkt, sizeof(*meas_rep)); + if (meas_rep == NULL) + return 0; + + tprintf(" Measurement Rep (%u, Len(%u)): ", *id, meas_rep->len); + if (len_lt_error(meas_rep->len, 3)) + return 0; + + tprintf("Token: %u, ", meas_rep->token); + tprintf("Rep Mode: 0x%x (Late (%u), Incapable(%u), Refused(%u), ", + meas_rep->rep_mode, meas_rep->rep_mode >> 7, + (meas_rep->rep_mode >> 6) & 0x1, + (meas_rep->rep_mode >> 5) & 0x1); + tprintf("Type: %s (%u), ", meas_type(meas_rep->type), meas_rep->type); + + if(meas_rep->len > 3) { + if(meas_rep->type == 0) { + struct element_meas_basic *basic; + + basic = (struct element_meas_basic *) + pkt_pull(pkt, sizeof(*basic)); + if (basic == NULL) + return 0; + + if ((meas_rep->len - 3 - sizeof(*basic)) != 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Ch Nr: %uus, ", basic->ch_nr); + tprintf("Meas Start Time: %lu, ", + le64_to_cpu(basic->start)); + tprintf("Meas Duration: %fs", + le16_to_cpu(basic->dur) * TU); + + } + else if(meas_rep->type == 1) { + struct element_meas_cca *cca; + + cca = (struct element_meas_cca *) + pkt_pull(pkt, sizeof(*cca)); + if (cca == NULL) + return 0; + + if ((meas_rep->len - 3 - sizeof(*cca)) != 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Ch Nr: %uus, ", cca->ch_nr); + tprintf("Meas Start Time: %lu, ", + le64_to_cpu(cca->start)); + tprintf("Meas Duration: %fs", + le16_to_cpu(cca->dur) * TU); + } + else if(meas_rep->type == 2) { + struct element_meas_rpi *rpi; + + rpi = (struct element_meas_rpi *) + pkt_pull(pkt, sizeof(*rpi)); + if (rpi == NULL) + return 0; + + if ((meas_rep->len - 3 - sizeof(*rpi)) != 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Ch Nr: %uus, ", rpi->ch_nr); + tprintf("Meas Start Time: %lu, ", + le64_to_cpu(rpi->start)); + tprintf("Meas Duration: %fs", + le16_to_cpu(rpi->dur) * TU); + } + else if(meas_rep->type == 3) { + struct element_meas_ch_load *ch_load; + + ch_load = (struct element_meas_ch_load *) + pkt_pull(pkt, sizeof(*ch_load)); + if (ch_load == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*ch_load)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("OP Class: %u, ", ch_load->op_class); + tprintf("Ch Nr: %u, ", ch_load->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(ch_load->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(ch_load->dur) * TU); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*ch_load))) + return 0; + } + else if(meas_rep->type == 4) { + struct element_meas_noise *noise; + + noise = (struct element_meas_noise *) + pkt_pull(pkt, sizeof(*noise)); + if (noise == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*noise)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("OP Class: %u, ", noise->op_class); + tprintf("Ch Nr: %u, ", noise->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(noise->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(noise->dur) * TU); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*noise))) + return 0; + } + else if(meas_rep->type == 5) { + struct element_meas_beacon *beacon; + + beacon = (struct element_meas_beacon *) + pkt_pull(pkt, sizeof(*beacon)); + if (beacon == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*beacon)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("OP Class: %u, ", beacon->op_class); + tprintf("Ch Nr: %u, ", beacon->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(beacon->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(beacon->dur) * TU); + tprintf("Mode: %u, ", beacon->mode); + tprintf("BSSID: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + beacon->bssid[0], beacon->bssid[1], + beacon->bssid[2], beacon->bssid[3], + beacon->bssid[4], beacon->bssid[5]); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*beacon))) + return 0; + } + else if(meas_rep->type == 6) { + struct element_meas_frame *frame; + + frame = (struct element_meas_frame *) + pkt_pull(pkt, sizeof(*frame)); + if (frame == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*frame)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("OP Class: %u, ", frame->op_class); + tprintf("Ch Nr: %u, ", frame->ch_nr); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(frame->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(frame->dur) * TU); + tprintf("Request Type: %u, ", frame->frame); + tprintf("MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + frame->mac[0], frame->mac[1], + frame->mac[2], frame->mac[3], + frame->mac[4], frame->mac[5]); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*frame))) + return 0; + } + else if(meas_rep->type == 7) { + struct element_meas_sta *sta; + + sta = (struct element_meas_sta *) + pkt_pull(pkt, sizeof(*sta)); + if (sta == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*sta)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Peer MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, ", + sta->peer_mac[0], sta->peer_mac[1], + sta->peer_mac[2], sta->peer_mac[3], + sta->peer_mac[4], sta->peer_mac[5]); + tprintf("Rand Intv: %fs, ", + le16_to_cpu(sta->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(sta->dur) * TU); + tprintf("Group ID: %u, ", sta->group_id); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*sta))) + return 0; + } + else if(meas_rep->type == 8) { + struct element_meas_lci *lci; + + lci = (struct element_meas_lci *) + pkt_pull(pkt, sizeof(*lci)); + if (lci == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*lci)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Location Subj: %u, ", lci->loc_subj); + tprintf("Latitude Req Res: %udeg", + lci->latitude_req_res); + tprintf("Longitude Req Res: %udeg", + lci->longitude_req_res); + tprintf("Altitude Req Res: %udeg", + lci->altitude_req_res); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*lci))) + return 0; + } + else if(meas_rep->type == 9) { + struct element_meas_trans_str_cat *trans; + + trans = (struct element_meas_trans_str_cat *) + pkt_pull(pkt, sizeof(*trans)); + if (trans == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*trans)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Rand Intv: %fs, ", + le16_to_cpu(trans->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(trans->dur) * TU); + tprintf("MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, ", + trans->peer_sta_addr[0], trans->peer_sta_addr[1], + trans->peer_sta_addr[2], trans->peer_sta_addr[3], + trans->peer_sta_addr[4], trans->peer_sta_addr[5]); + tprintf("Traffic ID: %u, ", trans->traffic_id); + tprintf("Bin 0 Range: %u, ", trans->bin_0_range); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*trans))) + return 0; + } + else if(meas_rep->type == 10) { + struct element_meas_mcast_diag *mcast; + + mcast = (struct element_meas_mcast_diag *) + pkt_pull(pkt, sizeof(*mcast)); + if (mcast == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*mcast)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Rand Intv: %fs, ", + le16_to_cpu(mcast->rand_intv) * TU); + tprintf("Meas Duration: %fs", + le16_to_cpu(mcast->dur) * TU); + tprintf("Group MAC Addr: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + mcast->group_mac[0], mcast->group_mac[1], + mcast->group_mac[2], mcast->group_mac[3], + mcast->group_mac[4], mcast->group_mac[5]); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*mcast))) + return 0; + } + else if(meas_rep->type == 11) { + struct element_meas_loc_civic *civic; + + civic = (struct element_meas_loc_civic *) + pkt_pull(pkt, sizeof(*civic)); + if (civic == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*civic)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Location Subj: %u, ", civic->loc_subj); + tprintf("Type: %u, ", civic->civic_loc); + tprintf("Srv Intv Units: %u, ", + le16_to_cpu(civic->loc_srv_intv_unit)); + tprintf("Srv Intv: %u, ", civic->loc_srv_intv); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*civic))) + return 0; + } + else if(meas_rep->type == 12) { + struct element_meas_loc_id *id; + + id = (struct element_meas_loc_id *) + pkt_pull(pkt, sizeof(*id)); + if (id == NULL) + return 0; + + if ((ssize_t)(meas_rep->len - 3 - sizeof(*id)) < 0) { + tprintf("Length of Req matchs not Type %u", + meas_rep->type); + return 0; + } + + tprintf("Location Subj: %u, ", id->loc_subj); + tprintf("Srv Intv Units: %u, ", + le16_to_cpu(id->loc_srv_intv_unit)); + tprintf("Srv Intv: %u", id->loc_srv_intv); + + if(!subelements(pkt, + meas_rep->len - 3 - sizeof(*id))) + return 0; + } + else { + tprintf("Length field indicates data," + " but could not interpreted"); + return 0; + } + } + + return 1; +} + +static int8_t inf_quiet(struct pkt_buff *pkt, u8 *id) +{ + struct element_quiet *quiet; + + quiet = (struct element_quiet *) pkt_pull(pkt, sizeof(*quiet)); + if (quiet == NULL) + return 0; + + tprintf(" Quit (%u, Len(%u)): ", *id, quiet->len); + if (len_neq_error(quiet->len, 6)) + return 0; + + tprintf("Count: %ud, ", quiet->cnt); + tprintf("Period: %u, ", quiet->period); + tprintf("Duration: %fs, ", le16_to_cpu(quiet->dur) * TU); + tprintf("Offs: %fs", le16_to_cpu(quiet->offs) * TU); + + + return 1; +} + +static int8_t inf_ibss_dfs(struct pkt_buff *pkt, u8 *id) +{ + struct element_ibss_dfs *ibss_dfs; + u8 i; + + ibss_dfs = (struct element_ibss_dfs *) pkt_pull(pkt, sizeof(*ibss_dfs)); + if (ibss_dfs == NULL) + return 0; + + tprintf(" IBSS DFS (%u, Len(%u)): ", *id, ibss_dfs->len); + if (len_lt_error(ibss_dfs->len, 7)) + return 0; + + tprintf("Owner: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, ", + ibss_dfs->owner[0], ibss_dfs->owner[1], + ibss_dfs->owner[2], ibss_dfs->owner[3], + ibss_dfs->owner[4], ibss_dfs->owner[5]); + tprintf("Recovery Intv: %u, ", ibss_dfs->rec_intv); + + if((ibss_dfs->len - sizeof(*ibss_dfs) + 1) & 1) { + tprintf("Length of Channel Map should be modulo 2"); + return 0; + } + + for (i = 0; i < ibss_dfs->len; i += 2) { + struct element_ibss_dfs_tuple *ibss_dfs_tuple; + + ibss_dfs_tuple = (struct element_ibss_dfs_tuple *) + pkt_pull(pkt, sizeof(*ibss_dfs_tuple)); + if (ibss_dfs_tuple == NULL) + return 0; + + tprintf("Channel Nr: %u, ", ibss_dfs_tuple->ch_nr); + tprintf("Map: %u, ", ibss_dfs_tuple->map); + } + + return 1; +} + +static int8_t inf_erp(struct pkt_buff *pkt, u8 *id) +{ + struct element_erp *erp; + + erp = (struct element_erp *) pkt_pull(pkt, sizeof(*erp)); + if (erp == NULL) + return 0; + + tprintf(" ERP (%u, Len(%u)): ", *id, erp->len); + if (len_neq_error(erp->len, 1)) + return 0; + tprintf("Non ERP Present (%u), ", erp->param & 0x1); + tprintf("Use Protection (%u), ", (erp->param >> 1) & 0x1); + tprintf("Barker Preamble Mode (%u), ", (erp->param >> 2) & 0x1); + tprintf("Reserved (0x%.5x)", erp->param >> 3); + + return 1; +} + +static int8_t inf_ts_del(struct pkt_buff *pkt, u8 *id) +{ + struct element_ts_del *ts_del; + + ts_del = (struct element_ts_del *) pkt_pull(pkt, sizeof(*ts_del)); + if (ts_del == NULL) + return 0; + + tprintf(" TS Delay (%u, Len(%u)): ", *id, ts_del->len); + if (len_neq_error(ts_del->len, 4)) + return 0; + tprintf("Delay (%fs)", le32_to_cpu(ts_del->delay) * TU); + + return 1; +} + +static int8_t inf_tclas_proc(struct pkt_buff *pkt, u8 *id) +{ + struct element_tclas_proc *tclas_proc; + + tclas_proc = (struct element_tclas_proc *) + pkt_pull(pkt, sizeof(*tclas_proc)); + if (tclas_proc == NULL) + return 0; + + tprintf(" TCLAS Procesing (%u, Len(%u)): ", *id, tclas_proc->len); + if (len_neq_error(tclas_proc->len, 1)) + return 0; + tprintf("Processing (%u)", tclas_proc->proc); + + return 1; +} + +static int8_t inf_ht_cap(struct pkt_buff *pkt, u8 *id) +{ + struct element_ht_cap *ht_cap; + u32 tx_param_res, beam_cap; + u16 ext_cap; + + ht_cap = (struct element_ht_cap *) + pkt_pull(pkt, sizeof(*ht_cap)); + if (ht_cap == NULL) + return 0; + + tx_param_res = le32_to_cpu(ht_cap->tx_param_res); + beam_cap = le32_to_cpu(ht_cap->beam_cap); + ext_cap = le16_to_cpu(ht_cap->ext_cap); + + tprintf(" HT Capabilities (%u, Len(%u)): ", *id, ht_cap->len); + if (len_neq_error(ht_cap->len, 26)) + return 0; + tprintf("Info (LDCP Cod Cap (%u), Supp Ch Width Set (%u)," + " SM Pwr Save(%u), HT-Greenfield (%u), Short GI for 20/40 MHz" + " (%u/%u), Tx/Rx STBC (%u/%u), HT-Delayed Block Ack (%u)," + " Max A-MSDU Len (%u), DSSS/CCK Mode in 40 MHz (%u)," + " Res (0x%x), Forty MHz Intol (%u), L-SIG TXOP Protection Supp" + " (%u)), ", ht_cap->ldpc, ht_cap->supp_width, + ht_cap->sm_pwr, ht_cap->ht_green, ht_cap->gi_20mhz, + ht_cap->gi_40mhz, ht_cap->tx_stbc, ht_cap->rx_stbc, + ht_cap->ht_ack, ht_cap->max_msdu_length, ht_cap->dsss_ck_mode, + ht_cap->res, ht_cap->forty_int, ht_cap->prot_supp); + tprintf("A-MPDU Params (Max Len Exp (%u), Min Start Spacing (%u)," + " Res (0x%x)), ", ht_cap->param >> 6, (ht_cap->param >> 3) & 0x7, + ht_cap->param & 0x07); + tprintf("Supp MCS Set (Rx MCS Bitmask (0x%x%x%x%x%x%x%x%x%x%x)," + " Res (0x%x), Rx High Supp Data Rate (%u), Res (0x%x)," + " Tx MCS Set Def (%u), Tx Rx MCS Set Not Eq (%u)," + " Tx Max Number Spat Str Supp (%u)," + " Tx Uneq Mod Supp (%u), Res (0x%x)), ", + ht_cap->bitmask1, ht_cap->bitmask2, ht_cap->bitmask3, + ht_cap->bitmask4, ht_cap->bitmask5, ht_cap->bitmask6, + ht_cap->bitmask7, ht_cap->bitmask8, ht_cap->bitmask9, + ht_cap->bitmask10_res >> 3, ht_cap->bitmask10_res & 0x7, + le16_to_cpu(ht_cap->supp_rate_res) >> 6, + le16_to_cpu(ht_cap->supp_rate_res) & 0x3F, + tx_param_res >> 31, (tx_param_res >> 30) & 1, + (tx_param_res >> 28) & 3, (tx_param_res >> 27) & 1, + tx_param_res & 0x7FFFFFF); + tprintf("Ext Cap (PCO (%u), PCO Trans Time (%u), Res (0x%x)," + " MCS Feedb (%u), +HTC Supp (%u), RD Resp (%u), Res (0x%x)), ", + ext_cap >> 15, (ext_cap >> 13) & 3, (ext_cap >> 8) & 0x1F, + (ext_cap >> 6) & 3, (ext_cap >> 5) & 1, (ext_cap >> 4) & 1, + ext_cap & 0xF); + tprintf("Transm Beamf (Impl Transm Beamf Rec Cap (%u)," + " Rec/Transm Stagg Sound Cap (%u/%u)," + " Rec/Trans NDP Cap (%u/%u), Impl Transm Beamf Cap (%u)," + " Cal (%u), Expl CSI Transm Beamf Cap (%u)," + " Expl Noncmpr/Compr Steering Cap (%u/%u)," + " Expl Trans Beamf CSI Feedb (%u)," + " Expl Noncmpr/Cmpr Feedb Cap (%u/%u)," + " Min Grpg (%u), CSI Num Beamf Ant Supp (%u)," + " Noncmpr/Cmpr Steering Nr Beamf Ant Supp (%u/%u)," + " CSI Max Nr Rows Beamf Supp (%u)," + " Ch Estim Cap (%u), Res (0x%x)), ", + beam_cap >> 31, (beam_cap >> 30) & 1, (beam_cap >> 29) & 1, + (beam_cap >> 28) & 1, (beam_cap >> 27) & 1, (beam_cap >> 26) & 1, + (beam_cap >> 24) & 3, (beam_cap >> 23) & 1, (beam_cap >> 22) & 1, + (beam_cap >> 21) & 1, (beam_cap >> 19) & 3, (beam_cap >> 17) & 3, + (beam_cap >> 15) & 3, (beam_cap >> 13) & 3, (beam_cap >> 11) & 3, + (beam_cap >> 9) & 3, (beam_cap >> 7) & 3, (beam_cap >> 5) & 3, + (beam_cap >> 3) & 3, beam_cap & 7); + tprintf("ASEL (Ant Select Cap (%u)," + " Expl CSI Feedb Based Transm ASEL Cap (%u)," + " Ant Indic Feedb Based Transm ASEL Cap (%u)," + " Expl CSI Feedb Cap (%u), Ant Indic Feedb Cap (%u)," + " Rec ASEL Cap (%u), Transm Sound PPDUs Cap (%u), Res (0x%x))", + ht_cap->asel_cap >> 7, (ht_cap->asel_cap >> 6) & 1, + (ht_cap->asel_cap >> 5) & 1, (ht_cap->asel_cap >> 4) & 1, + (ht_cap->asel_cap >> 3) & 1, (ht_cap->asel_cap >> 2) & 1, + (ht_cap->asel_cap >> 1) & 1, ht_cap->asel_cap & 1); + + return 1; +} + +static int8_t inf_qos_cap(struct pkt_buff *pkt, u8 *id) +{ + struct element_qos_cap *qos_cap; + + qos_cap = (struct element_qos_cap *) + pkt_pull(pkt, sizeof(*qos_cap)); + if (qos_cap == NULL) + return 0; + + tprintf(" QoS Capabilities (%u, Len(%u)): ", *id, qos_cap->len); + if (len_neq_error(qos_cap->len, 1)) + return 0; + + tprintf("Info (0x%x)", qos_cap->info); + + return 1; +} + +static int8_t inf_rsn(struct pkt_buff *pkt, u8 *id) +{ + return 0; +} + +static int8_t inf_ext_supp_rates(struct pkt_buff *pkt, u8 *id) +{ + u8 i; + u8 *rates; + struct element_ext_supp_rates *ext_supp_rates; + + ext_supp_rates = (struct element_ext_supp_rates *) + pkt_pull(pkt, sizeof(*ext_supp_rates)); + if (ext_supp_rates == NULL) + return 0; + + tprintf(" Ext Support Rates (%u, Len(%u)): ", *id, ext_supp_rates->len); + + if ((ext_supp_rates->len - sizeof(*ext_supp_rates) + 1) > 0) { + rates = pkt_pull(pkt, ext_supp_rates->len); + if (rates == NULL) + return 0; + + for (i = 0; i < ext_supp_rates->len; i++) + tprintf("%g ", (rates[i] & 0x80) ? + ((rates[i] & 0x3f) * 0.5) : + data_rates(rates[i])); + return 1; + } + + return 0; +} + +static int8_t inf_ap_ch_exp(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_neighb_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_rcpi(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mde(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_fte(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_time_out_int(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_rde(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_dse_reg_loc(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_supp_op_class(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ext_ch_sw_ann(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ht_op(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_sec_ch_offs(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_bss_avg_acc_del(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ant(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_rsni(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_meas_pilot_trans(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_bss_avl_adm_cap(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_bss_ac_acc_del(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_time_adv(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_rm_ena_cap(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mult_bssid(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_20_40_bss_coex(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_20_40_bss_int_ch_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_overl_bss_scan_para(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ric_desc(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mgmt_mic(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ev_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ev_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_diagn_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_diagn_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_loc_para(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_nontr_bssid_cap(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ssid_list(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mult_bssid_index(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_fms_desc(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_fms_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_fms_resp(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_qos_tfc_cap(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_bss_max_idle_per(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_tfs_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_tfs_resp(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_wnm_sleep_mod(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_tim_bcst_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_tim_bcst_resp(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_coll_interf_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ch_usage(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_time_zone(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_dms_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_dms_resp(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_link_id(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_wakeup_sched(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ch_sw_timing(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_pti_ctrl(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_tpu_buff_status(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_interw(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_adv_proto(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_exp_bandw_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_qos_map_set(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_roam_cons(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_emer_alert_id(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mesh_conf(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mesh_id(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mesh_link_metr_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_cong_notif(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mesh_peer_mgmt(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mesh_ch_sw_para(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mesh_awake_win(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_beacon_timing(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mccaop_setup_req(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mccaop_setup_rep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mccaop_adv(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mccaop_teardwn(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_gann(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_rann(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_ext_cap(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_preq(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_prep(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_perr(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_pxu(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_pxuc(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_auth_mesh_peer_exch(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mic(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_dest_uri(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_u_apsd_coex(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_mccaop_adv_overv(struct pkt_buff *pkt, u8 *id) { + return 0; +} + +static int8_t inf_vend_spec(struct pkt_buff *pkt, u8 *id) +{ + u8 i; + u8 *data; + struct element_vend_spec *vend_spec; + + vend_spec = (struct element_vend_spec *) + pkt_pull(pkt, sizeof(*vend_spec)); + if (vend_spec == NULL) + return 0; + + tprintf(" Vendor Specific (%u, Len (%u)): ", *id, vend_spec->len); + + data = pkt_pull(pkt, vend_spec->len); + if (data == NULL) + return 0; + + tprintf("Data 0x"); + for (i = 0; i < vend_spec->len; i++) + tprintf("%.2x", data[i]); + + return 1; +} + +static int8_t inf_elements(struct pkt_buff *pkt) +{ + u8 *id = pkt_pull(pkt, 1); + if (id == NULL) + return 0; + + switch (*id) { + case 0: return inf_ssid(pkt, id); + case 1: return inf_supp_rates(pkt, id); + case 2: return inf_fh_ps(pkt, id); + case 3: return inf_dsss_ps(pkt, id); + case 4: return inf_cf_ps(pkt, id); + case 5: return inf_tim(pkt, id); + case 6: return inf_ibss_ps(pkt, id); + case 7: return inf_country(pkt, id); + case 8: return inf_hop_pp(pkt, id); + case 9: return inf_hop_pt(pkt, id); + case 10: return inf_req(pkt, id); + case 11: return inf_bss_load(pkt, id); + case 12: return inf_edca_ps(pkt, id); + case 13: return inf_tspec(pkt, id); + case 14: return inf_tclas(pkt, id); + case 15: return inf_sched(pkt, id); + case 16: return inf_chall_txt(pkt, id); + case 17 ... 31: return inf_reserved(pkt, id); + case 32: return inf_pwr_constr(pkt, id); + case 33: return inf_pwr_cap(pkt, id); + case 34: return inf_tpc_req(pkt, id); + case 35: return inf_tpc_rep(pkt, id); + case 36: return inf_supp_ch(pkt, id); + case 37: return inf_ch_sw_ann(pkt, id); + case 38: return inf_meas_req(pkt, id); + case 39: return inf_meas_rep(pkt, id); + case 40: return inf_quiet(pkt, id); + case 41: return inf_ibss_dfs(pkt, id); + case 42: return inf_erp(pkt, id); + case 43: return inf_ts_del(pkt, id); + case 44: return inf_tclas_proc(pkt, id); + case 45: return inf_ht_cap(pkt, id); + case 46: return inf_qos_cap(pkt, id); + case 47: return inf_reserved(pkt, id); + case 48: return inf_rsn(pkt, id); + case 49: return inf_rsn(pkt, id); + case 50: return inf_ext_supp_rates(pkt, id); + case 51: return inf_ap_ch_exp(pkt, id); + case 52: return inf_neighb_rep(pkt, id); + case 53: return inf_rcpi(pkt, id); + case 54: return inf_mde(pkt, id); + case 55: return inf_fte(pkt, id); + case 56: return inf_time_out_int(pkt, id); + case 57: return inf_rde(pkt, id); + case 58: return inf_dse_reg_loc(pkt, id); + case 59: return inf_supp_op_class(pkt, id); + case 60: return inf_ext_ch_sw_ann(pkt, id); + case 61: return inf_ht_op(pkt, id); + case 62: return inf_sec_ch_offs(pkt, id); + case 63: return inf_bss_avg_acc_del(pkt, id); + case 64: return inf_ant(pkt, id); + case 65: return inf_rsni(pkt, id); + case 66: return inf_meas_pilot_trans(pkt, id); + case 67: return inf_bss_avl_adm_cap(pkt, id); + case 68: return inf_bss_ac_acc_del(pkt, id); + case 69: return inf_time_adv(pkt, id); + case 70: return inf_rm_ena_cap(pkt, id); + case 71: return inf_mult_bssid(pkt, id); + case 72: return inf_20_40_bss_coex(pkt, id); + case 73: return inf_20_40_bss_int_ch_rep(pkt, id); + case 74: return inf_overl_bss_scan_para(pkt, id); + case 75: return inf_ric_desc(pkt, id); + case 76: return inf_mgmt_mic(pkt, id); + case 78: return inf_ev_req(pkt, id); + case 79: return inf_ev_rep(pkt, id); + case 80: return inf_diagn_req(pkt, id); + case 81: return inf_diagn_rep(pkt, id); + case 82: return inf_loc_para(pkt, id); + case 83: return inf_nontr_bssid_cap(pkt, id); + case 84: return inf_ssid_list(pkt, id); + case 85: return inf_mult_bssid_index(pkt, id); + case 86: return inf_fms_desc(pkt, id); + case 87: return inf_fms_req(pkt, id); + case 88: return inf_fms_resp(pkt, id); + case 89: return inf_qos_tfc_cap(pkt, id); + case 90: return inf_bss_max_idle_per(pkt, id); + case 91: return inf_tfs_req(pkt, id); + case 92: return inf_tfs_resp(pkt, id); + case 93: return inf_wnm_sleep_mod(pkt, id); + case 94: return inf_tim_bcst_req(pkt, id); + case 95: return inf_tim_bcst_resp(pkt, id); + case 96: return inf_coll_interf_rep(pkt, id); + case 97: return inf_ch_usage(pkt, id); + case 98: return inf_time_zone(pkt, id); + case 99: return inf_dms_req(pkt, id); + case 100: return inf_dms_resp(pkt, id); + case 101: return inf_link_id(pkt, id); + case 102: return inf_wakeup_sched(pkt, id); + case 104: return inf_ch_sw_timing(pkt, id); + case 105: return inf_pti_ctrl(pkt, id); + case 106: return inf_tpu_buff_status(pkt, id); + case 107: return inf_interw(pkt, id); + case 108: return inf_adv_proto(pkt, id); + case 109: return inf_exp_bandw_req(pkt, id); + case 110: return inf_qos_map_set(pkt, id); + case 111: return inf_roam_cons(pkt, id); + case 112: return inf_emer_alert_id(pkt, id); + case 113: return inf_mesh_conf(pkt, id); + case 114: return inf_mesh_id(pkt, id); + case 115: return inf_mesh_link_metr_rep(pkt, id); + case 116: return inf_cong_notif(pkt, id); + case 117: return inf_mesh_peer_mgmt(pkt, id); + case 118: return inf_mesh_ch_sw_para(pkt, id); + case 119: return inf_mesh_awake_win(pkt, id); + case 120: return inf_beacon_timing(pkt, id); + case 121: return inf_mccaop_setup_req(pkt, id); + case 122: return inf_mccaop_setup_rep(pkt, id); + case 123: return inf_mccaop_adv(pkt, id); + case 124: return inf_mccaop_teardwn(pkt, id); + case 125: return inf_gann(pkt, id); + case 126: return inf_rann(pkt, id); + case 127: return inf_ext_cap(pkt, id); + case 128: return inf_reserved(pkt, id); + case 129: return inf_reserved(pkt, id); + case 130: return inf_preq(pkt, id); + case 131: return inf_prep(pkt, id); + case 132: return inf_perr(pkt, id); + case 133: return inf_reserved(pkt, id); + case 134: return inf_reserved(pkt, id); + case 135: return inf_reserved(pkt, id); + case 136: return inf_reserved(pkt, id); + case 137: return inf_pxu(pkt, id); + case 138: return inf_pxuc(pkt, id); + case 139: return inf_auth_mesh_peer_exch(pkt, id); + case 140: return inf_mic(pkt, id); + case 141: return inf_dest_uri(pkt, id); + case 142: return inf_u_apsd_coex(pkt, id); + case 143 ... 173: return inf_reserved(pkt, id); + case 174: return inf_mccaop_adv_overv(pkt, id); + case 221: return inf_vend_spec(pkt, id); + } + + return 0; +} + +#define ESS 0b0000000000000001 +#define IBSS 0b0000000000000010 +#define CF_Pollable 0b0000000000000100 +#define CF_Poll_Req 0b0000000000001000 +#define Privacy 0b0000000000010000 +#define Short_Pre 0b0000000000100000 +#define PBCC 0b0000000001000000 +#define Ch_Agility 0b0000000010000000 +#define Spec_Mgmt 0b0000000100000000 +#define QoS 0b0000001000000000 +#define Short_Slot_t 0b0000010000000000 +#define APSD 0b0000100000000000 +#define Radio_Meas 0b0001000000000000 +#define DSSS_OFDM 0b0010000000000000 +#define Del_Block_ACK 0b0100000000000000 +#define Imm_Block_ACK 0b1000000000000000 + +static int8_t cap_field(u16 cap_inf) +{ + if (ESS & cap_inf) + tprintf(" ESS;"); + if (IBSS & cap_inf) + tprintf(" IBSS;"); + if (CF_Pollable & cap_inf) + tprintf(" CF Pollable;"); + if (CF_Poll_Req & cap_inf) + tprintf(" CF-Poll Request;"); + if (Privacy & cap_inf) + tprintf(" Privacy;"); + if (Short_Pre & cap_inf) + tprintf(" Short Preamble;"); + if (PBCC & cap_inf) + tprintf(" PBCC;"); + if (Ch_Agility & cap_inf) + tprintf(" Channel Agility;"); + if (Spec_Mgmt & cap_inf) + tprintf(" Spectrum Management;"); + if (QoS & cap_inf) + tprintf(" QoS;"); + if (Short_Slot_t & cap_inf) + tprintf(" Short Slot Time;"); + if (APSD & cap_inf) + tprintf(" APSD;"); + if (Radio_Meas & cap_inf) + tprintf(" Radio Measurement;"); + if (DSSS_OFDM & cap_inf) + tprintf(" DSSS-OFDM;"); + if (Del_Block_ACK & cap_inf) + tprintf(" Delayed Block Ack;"); + if (Imm_Block_ACK & cap_inf) + tprintf(" Immediate Block Ack;"); + + return 1; +} + +/* Management Dissectors */ +static int8_t assoc_req(struct pkt_buff *pkt) { + return 0; +} + +static int8_t assoc_resp(struct pkt_buff *pkt) { + return 0; +} + +static int8_t reassoc_req(struct pkt_buff *pkt) { + return 0; +} + +static int8_t reassoc_resp(struct pkt_buff *pkt) { + return 0; +} + +static int8_t probe_req(struct pkt_buff *pkt) { + return 0; +} + +static int8_t probe_resp(struct pkt_buff *pkt) { + return 0; +} + +static int8_t beacon(struct pkt_buff *pkt) +{ + struct ieee80211_mgmt_beacon *beacon; + + beacon = (struct ieee80211_mgmt_beacon *) + pkt_pull(pkt, sizeof(*beacon)); + if (beacon == NULL) + return 0; + + tprintf("Timestamp 0x%.16lx, ", le64_to_cpu(beacon->timestamp)); + tprintf("Beacon Interval (%fs), ", le16_to_cpu(beacon->beacon_int)*TU); + tprintf("Capabilities (0x%x <->", le16_to_cpu(beacon->capab_info)); + cap_field(le16_to_cpu(beacon->capab_info)); + tprintf(")"); + + if(pkt_len(pkt)) { + tprintf("\n\tParameters:"); + while (inf_elements(pkt)) { + tprintf("\n\t"); + } + } + + if(pkt_len(pkt)) + return 0; + return 1; +} + +static int8_t atim(struct pkt_buff *pkt) { + return 0; +} + +static int8_t disassoc(struct pkt_buff *pkt) { + return 0; +} + +static int8_t auth(struct pkt_buff *pkt) { + return 0; +} + +static int8_t deauth(struct pkt_buff *pkt) { + return 0; +} +/* End Management Dissectors */ + +/* Control Dissectors */ +static int8_t ps_poll(struct pkt_buff *pkt) { + return 0; +} + +static int8_t rts(struct pkt_buff *pkt) { + return 0; +} + +static int8_t cts(struct pkt_buff *pkt) { + return 0; +} + +static int8_t ack(struct pkt_buff *pkt) { + return 0; +} + +static int8_t cf_end(struct pkt_buff *pkt) { + return 0; +} + +static int8_t cf_end_ack(struct pkt_buff *pkt) { + return 0; +} +/* End Control Dissectors */ + +/* Data Dissectors */ +static int8_t data(struct pkt_buff *pkt) { + return 0; +} + +static int8_t data_cf_ack(struct pkt_buff *pkt) { + return 0; +} + +static int8_t data_cf_poll(struct pkt_buff *pkt) { + return 0; +} + +static int8_t data_cf_ack_poll(struct pkt_buff *pkt) { + return 0; +} + +static int8_t null(struct pkt_buff *pkt) { + return 0; +} + +static int8_t cf_ack(struct pkt_buff *pkt) { + return 0; +} + +static int8_t cf_poll(struct pkt_buff *pkt) { + return 0; +} + +static int8_t cf_ack_poll(struct pkt_buff *pkt) { + return 0; +} +/* End Data Dissectors */ + +static const char *mgt_sub(u8 subtype, struct pkt_buff *pkt, + int8_t (**get_content)(struct pkt_buff *pkt)) +{ + u16 seq_ctrl; + struct ieee80211_mgmt *mgmt; + const char *dst, *src, *bssid; + + mgmt = (struct ieee80211_mgmt *) pkt_pull(pkt, sizeof(*mgmt)); + if (mgmt == NULL) + return 0; + + dst = lookup_vendor((mgmt->da[0] << 16) | + (mgmt->da[1] << 8) | + mgmt->da[2]); + src = lookup_vendor((mgmt->sa[0] << 16) | + (mgmt->sa[1] << 8) | + mgmt->sa[2]); + + bssid = lookup_vendor((mgmt->bssid[0] << 16) | + (mgmt->bssid[1] << 8) | + mgmt->bssid[2]); + seq_ctrl = le16_to_cpu(mgmt->seq_ctrl); + + tprintf("Duration (%u),", le16_to_cpu(mgmt->duration)); + tprintf("\n\tDestination (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ", + mgmt->da[0], mgmt->da[1], mgmt->da[2], + mgmt->da[3], mgmt->da[4], mgmt->da[5]); + if (dst) { + tprintf("=> (%s:%.2x:%.2x:%.2x)", dst, + mgmt->da[3], mgmt->da[4], mgmt->da[5]); + } + + tprintf("\n\tSource (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ", + mgmt->sa[0], mgmt->sa[1], mgmt->sa[2], + mgmt->sa[3], mgmt->sa[4], mgmt->sa[5]); + if (src) { + tprintf("=> (%s:%.2x:%.2x:%.2x)", src, + mgmt->sa[3], mgmt->sa[4], mgmt->sa[5]); + } + + tprintf("\n\tBSSID (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ", + mgmt->bssid[0], mgmt->bssid[1], mgmt->bssid[2], + mgmt->bssid[3], mgmt->bssid[4], mgmt->bssid[5]); + if(bssid) { + tprintf("=> (%s:%.2x:%.2x:%.2x)", bssid, + mgmt->bssid[3], mgmt->bssid[4], mgmt->bssid[5]); + } + + tprintf("\n\tFragmentnr. (%u), Seqnr. (%u). ", + seq_ctrl & 0xf, seq_ctrl >> 4); + + switch (subtype) { + case 0b0000: + *get_content = assoc_req; + return "Association Request"; + case 0b0001: + *get_content = assoc_resp; + return "Association Response"; + case 0b0010: + *get_content = reassoc_req; + return "Reassociation Request"; + case 0b0011: + *get_content = reassoc_resp; + return "Reassociation Response"; + case 0b0100: + *get_content = probe_req; + return "Probe Request"; + case 0b0101: + *get_content = probe_resp; + return "Probe Response"; + case 0b1000: + *get_content = beacon; + return "Beacon"; + case 0b1001: + *get_content = atim; + return "ATIM"; + case 0b1010: + *get_content = disassoc; + return "Disassociation"; + case 0b1011: + *get_content = auth; + return "Authentication"; + case 0b1100: + *get_content = deauth; + return "Deauthentication"; + case 0b0110 ... 0b0111: + case 0b1101 ... 0b1111: + *get_content = NULL; + return "Reserved"; + default: + *get_content = NULL; + return "Management SubType unknown"; + } +} + +static const char *ctrl_sub(u8 subtype, struct pkt_buff *pkt, + int8_t (**get_content)(struct pkt_buff *pkt)) +{ + switch (subtype) { + case 0b1010: + *get_content = ps_poll; + return "PS-Poll"; + case 0b1011: + *get_content = rts; + return "RTS"; + case 0b1100: + *get_content = cts; + return "CTS"; + case 0b1101: + *get_content = ack; + return "ACK"; + case 0b1110: + *get_content = cf_end; + return "CF End"; + case 0b1111: + *get_content = cf_end_ack; + return "CF End + CF-ACK"; + case 0b0000 ... 0b1001: + *get_content = NULL; + return "Reserved"; + default: + return "Control SubType unkown"; + } +} + +static const char *data_sub(u8 subtype, struct pkt_buff *pkt, + int8_t (**get_content)(struct pkt_buff *pkt)) +{ + switch (subtype) { + case 0b0000: + *get_content = data; + return "Data"; + case 0b0001: + *get_content = data_cf_ack; + return "Data + CF-ACK"; + case 0b0010: + *get_content = data_cf_poll; + return "Data + CF-Poll"; + case 0b0011: + *get_content = data_cf_ack_poll; + return "Data + CF-ACK + CF-Poll"; + case 0b0100: + *get_content = null; + return "Null"; + case 0b0101: + *get_content = cf_ack; + return "CF-ACK"; + case 0b0110: + *get_content = cf_poll; + return "CF-Poll"; + case 0b0111: + *get_content = cf_ack_poll; + return "CF-ACK + CF-Poll"; + case 0b1000 ... 0b1111: + *get_content = NULL; + return "Reserved"; + default: + *get_content = NULL; + return "Data SubType unkown"; + } +} + +static const char * +frame_control_type(u8 type, const char *(**get_subtype)(u8 subtype, + struct pkt_buff *pkt, int8_t (**get_content)(struct pkt_buff *pkt))) +{ + switch (type) { + case 0b00: + *get_subtype = mgt_sub; + return "Management"; + case 0b01: + *get_subtype = ctrl_sub; + return "Control"; + case 0b10: + *get_subtype = data_sub; + return "Data"; + case 0b11: + *get_subtype = NULL; + return "Reserved"; + default: + *get_subtype = NULL; + return "Control Type unkown"; + } +} + +static void ieee80211(struct pkt_buff *pkt) +{ + int8_t (*get_content)(struct pkt_buff *pkt) = NULL; + const char *(*get_subtype)(u8 subtype, struct pkt_buff *pkt, + int8_t (**get_content)(struct pkt_buff *pkt)) = NULL; + const char *subtype = NULL; + struct ieee80211_frm_ctrl *frm_ctrl; + + frm_ctrl = (struct ieee80211_frm_ctrl *) + pkt_pull(pkt, sizeof(*frm_ctrl)); + if (frm_ctrl == NULL) + return; + + tprintf(" [ 802.11 Frame Control (0x%04x)]\n", + le16_to_cpu(frm_ctrl->frame_control)); + + tprintf(" [ Proto Version (%u), ", frm_ctrl->proto_version); + tprintf("Type (%u, %s), ", frm_ctrl->type, + frame_control_type(frm_ctrl->type, &get_subtype)); + if (get_subtype) { + subtype = (*get_subtype)(frm_ctrl->subtype, pkt, &get_content); + tprintf("Subtype (%u, %s)", frm_ctrl->subtype, subtype); + } else { + tprintf("%s%s%s", colorize_start_full(black, red), + "No SubType Data available", colorize_end()); + } + + tprintf("%s%s", frm_ctrl->to_ds ? ", Frame goes to DS" : "", + frm_ctrl->from_ds ? ", Frame comes from DS" : ""); + tprintf("%s", frm_ctrl->more_frags ? ", More Fragments" : ""); + tprintf("%s", frm_ctrl->retry ? ", Frame is retransmitted" : ""); + tprintf("%s", frm_ctrl->power_mgmt ? ", In Power Saving Mode" : ""); + tprintf("%s", frm_ctrl->more_data ? ", More Data" : ""); + tprintf("%s", frm_ctrl->wep ? ", Needs WEP" : ""); + tprintf("%s", frm_ctrl->order ? ", Order" : ""); + tprintf(" ]\n"); + + if (get_content) { + tprintf(" [ Subtype %s: ", subtype); + if (!((*get_content) (pkt))) + tprintf("%s%s%s", colorize_start_full(black, red), + "Failed to dissect Subtype", colorize_end()); + tprintf(" ]"); + } else { + tprintf("%s%s%s", colorize_start_full(black, red), + "No SubType Data available", colorize_end()); + } + + tprintf("\n"); + +// pkt_set_proto(pkt, &ieee802_lay2, ntohs(eth->h_proto)); +} + +static void ieee80211_less(struct pkt_buff *pkt) +{ + tprintf("802.11 frame (more on todo)"); +} + +struct protocol ieee80211_ops = { + .key = 0, + .print_full = ieee80211, + .print_less = ieee80211_less, +}; |