| 3193 | (((const u_int8_t *)(p))[0] << 8))) |
| 3194 | |
| 3195 | static void |
| 3196 | printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) |
| 3197 | { |
| 3198 | u_int8_t len = ie[1]; |
| 3199 | |
| 3200 | printf("%s", tag); |
| 3201 | if (verbose) { |
| 3202 | static const char *dev_pass_id[] = { |
| 3203 | "D", /* Default (PIN) */ |
| 3204 | "U", /* User-specified */ |
| 3205 | "M", /* Machine-specified */ |
| 3206 | "K", /* Rekey */ |
| 3207 | "P", /* PushButton */ |
| 3208 | "R" /* Registrar-specified */ |
| 3209 | }; |
| 3210 | int n; |
| 3211 | int f; |
| 3212 | |
| 3213 | ie +=6, len -= 4; /* NB: len is payload only */ |
| 3214 | |
| 3215 | /* WPS IE in Beacon and Probe Resp frames have different fields */ |
| 3216 | printf("<"); |
| 3217 | while (len) { |
| 3218 | uint16_t tlv_type = BE_READ_2(ie); |
| 3219 | uint16_t tlv_len = BE_READ_2(ie + 2); |
| 3220 | uint16_t cfg_mthd; |
| 3221 | |
| 3222 | /* some devices broadcast invalid WPS frames */ |
| 3223 | if (tlv_len > len) { |
| 3224 | printf("bad frame length tlv_type=0x%02x " |
| 3225 | "tlv_len=%d len=%d", tlv_type, tlv_len, |
| 3226 | len); |
| 3227 | break; |
| 3228 | } |
| 3229 | |
| 3230 | ie += 4, len -= 4; |
| 3231 | |
| 3232 | switch (tlv_type) { |
| 3233 | case IEEE80211_WPS_ATTR_VERSION: |
| 3234 | printf("v:%d.%d", *ie >> 4, *ie & 0xf); |
| 3235 | break; |
| 3236 | case IEEE80211_WPS_ATTR_AP_SETUP_LOCKED: |
| 3237 | printf(" ap_setup:%s", *ie ? "locked" : |
| 3238 | "unlocked"); |
| 3239 | break; |
| 3240 | case IEEE80211_WPS_ATTR_CONFIG_METHODS: |
| 3241 | case IEEE80211_WPS_ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: |
| 3242 | if (tlv_type == IEEE80211_WPS_ATTR_SELECTED_REGISTRAR_CONFIG_METHODS) |
| 3243 | printf(" sel_reg_cfg_mthd:"); |
| 3244 | else |
| 3245 | printf(" cfg_mthd:" ); |
| 3246 | cfg_mthd = BE_READ_2(ie); |
| 3247 | f = 0; |
| 3248 | for (n = 15; n >= 0; n--) { |
| 3249 | if (f) { |
| 3250 | printf(","); |
| 3251 | f = 0; |
| 3252 | } |