1 /* 2 * P2P - IE builder 3 * Copyright (c) 2009-2010, Atheros Communications 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "common/ieee802_11_defs.h" 13 #include "wps/wps_i.h" 14 #include "p2p_i.h" 15 16 17 void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token) 18 { 19 wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC); 20 wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 21 22 wpabuf_put_u8(buf, subtype); /* OUI Subtype */ 23 wpabuf_put_u8(buf, dialog_token); 24 wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); 25 } 26 27 28 void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, 29 u8 dialog_token) 30 { 31 wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); 32 wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); 33 wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 34 35 wpabuf_put_u8(buf, subtype); /* OUI Subtype */ 36 wpabuf_put_u8(buf, dialog_token); 37 wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); 38 } 39 40 41 u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf) 42 { 43 u8 *len; 44 45 /* P2P IE header */ 46 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 47 len = wpabuf_put(buf, 1); /* IE length to be filled */ 48 wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 49 wpa_printf(MSG_DEBUG, "P2P: * P2P IE header"); 50 return len; 51 } 52 53 54 void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len) 55 { 56 /* Update P2P IE Length */ 57 *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 58 } 59 60 61 void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab) 62 { 63 /* P2P Capability */ 64 wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY); 65 wpabuf_put_le16(buf, 2); 66 wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */ 67 wpabuf_put_u8(buf, group_capab); /* Group Capabilities */ 68 wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x", 69 dev_capab, group_capab); 70 } 71 72 73 void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent) 74 { 75 /* Group Owner Intent */ 76 wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT); 77 wpabuf_put_le16(buf, 1); 78 wpabuf_put_u8(buf, go_intent); 79 wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u", 80 go_intent >> 1, go_intent & 0x01); 81 } 82 83 84 void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, 85 u8 reg_class, u8 channel) 86 { 87 /* Listen Channel */ 88 wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL); 89 wpabuf_put_le16(buf, 5); 90 wpabuf_put_data(buf, country, 3); 91 wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ 92 wpabuf_put_u8(buf, channel); /* Channel Number */ 93 wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u " 94 "Channel %u", reg_class, channel); 95 } 96 97 98 void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, 99 u8 reg_class, u8 channel) 100 { 101 /* Operating Channel */ 102 wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL); 103 wpabuf_put_le16(buf, 5); 104 wpabuf_put_data(buf, country, 3); 105 wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ 106 wpabuf_put_u8(buf, channel); /* Channel Number */ 107 wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u " 108 "Channel %u", reg_class, channel); 109 } 110 111 112 void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, 113 struct p2p_channels *chan) 114 { 115 u8 *len; 116 size_t i; 117 118 /* Channel List */ 119 wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST); 120 len = wpabuf_put(buf, 2); /* IE length to be filled */ 121 wpabuf_put_data(buf, country, 3); /* Country String */ 122 123 for (i = 0; i < chan->reg_classes; i++) { 124 struct p2p_reg_class *c = &chan->reg_class[i]; 125 wpabuf_put_u8(buf, c->reg_class); 126 wpabuf_put_u8(buf, c->channels); 127 wpabuf_put_data(buf, c->channel, c->channels); 128 } 129 130 /* Update attribute length */ 131 WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); 132 wpa_hexdump(MSG_DEBUG, "P2P: * Channel List", 133 len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2); 134 } 135 136 137 void p2p_buf_add_status(struct wpabuf *buf, u8 status) 138 { 139 /* Status */ 140 wpabuf_put_u8(buf, P2P_ATTR_STATUS); 141 wpabuf_put_le16(buf, 1); 142 wpabuf_put_u8(buf, status); 143 wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status); 144 } 145 146 147 void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, 148 struct p2p_device *peer) 149 { 150 u8 *len; 151 u16 methods; 152 size_t nlen, i; 153 154 /* P2P Device Info */ 155 wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO); 156 len = wpabuf_put(buf, 2); /* IE length to be filled */ 157 158 /* P2P Device address */ 159 wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 160 161 /* Config Methods */ 162 methods = 0; 163 if (peer && peer->wps_method != WPS_NOT_READY) { 164 if (peer->wps_method == WPS_PBC) 165 methods |= WPS_CONFIG_PUSHBUTTON; 166 else if (peer->wps_method == WPS_PIN_DISPLAY || 167 peer->wps_method == WPS_PIN_KEYPAD) 168 methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 169 } else if (p2p->cfg->config_methods) { 170 methods |= p2p->cfg->config_methods & 171 (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY | 172 WPS_CONFIG_KEYPAD); 173 } else { 174 methods |= WPS_CONFIG_PUSHBUTTON; 175 methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 176 } 177 wpabuf_put_be16(buf, methods); 178 179 /* Primary Device Type */ 180 wpabuf_put_data(buf, p2p->cfg->pri_dev_type, 181 sizeof(p2p->cfg->pri_dev_type)); 182 183 /* Number of Secondary Device Types */ 184 wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types); 185 186 /* Secondary Device Type List */ 187 for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) 188 wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i], 189 WPS_DEV_TYPE_LEN); 190 191 /* Device Name */ 192 nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0; 193 wpabuf_put_be16(buf, ATTR_DEV_NAME); 194 wpabuf_put_be16(buf, nlen); 195 wpabuf_put_data(buf, p2p->cfg->dev_name, nlen); 196 197 /* Update attribute length */ 198 WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); 199 wpa_printf(MSG_DEBUG, "P2P: * Device Info"); 200 } 201 202 203 void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr) 204 { 205 /* P2P Device ID */ 206 wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID); 207 wpabuf_put_le16(buf, ETH_ALEN); 208 wpabuf_put_data(buf, dev_addr, ETH_ALEN); 209 wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr)); 210 } 211 212 213 void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, 214 u8 client_timeout) 215 { 216 /* Configuration Timeout */ 217 wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT); 218 wpabuf_put_le16(buf, 2); 219 wpabuf_put_u8(buf, go_timeout); 220 wpabuf_put_u8(buf, client_timeout); 221 wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms) " 222 "client %d (*10ms)", go_timeout, client_timeout); 223 } 224 225 226 void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr) 227 { 228 /* Intended P2P Interface Address */ 229 wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR); 230 wpabuf_put_le16(buf, ETH_ALEN); 231 wpabuf_put_data(buf, interface_addr, ETH_ALEN); 232 wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR, 233 MAC2STR(interface_addr)); 234 } 235 236 237 void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid) 238 { 239 /* P2P Group BSSID */ 240 wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID); 241 wpabuf_put_le16(buf, ETH_ALEN); 242 wpabuf_put_data(buf, bssid, ETH_ALEN); 243 wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR, 244 MAC2STR(bssid)); 245 } 246 247 248 void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, 249 const u8 *ssid, size_t ssid_len) 250 { 251 /* P2P Group ID */ 252 wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID); 253 wpabuf_put_le16(buf, ETH_ALEN + ssid_len); 254 wpabuf_put_data(buf, dev_addr, ETH_ALEN); 255 wpabuf_put_data(buf, ssid, ssid_len); 256 wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR, 257 MAC2STR(dev_addr)); 258 wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len); 259 } 260 261 262 void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags) 263 { 264 /* Invitation Flags */ 265 wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS); 266 wpabuf_put_le16(buf, 1); 267 wpabuf_put_u8(buf, flags); 268 wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags); 269 } 270 271 272 static void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc) 273 { 274 if (desc == NULL) 275 return; 276 277 wpabuf_put_u8(buf, desc->count_type); 278 wpabuf_put_le32(buf, desc->duration); 279 wpabuf_put_le32(buf, desc->interval); 280 wpabuf_put_le32(buf, desc->start_time); 281 } 282 283 284 void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, 285 struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2) 286 { 287 /* Notice of Absence */ 288 wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE); 289 wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0)); 290 wpabuf_put_u8(buf, noa_index); 291 wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f)); 292 p2p_buf_add_noa_desc(buf, desc1); 293 p2p_buf_add_noa_desc(buf, desc2); 294 wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); 295 } 296 297 298 void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, 299 u16 interval) 300 { 301 /* Extended Listen Timing */ 302 wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING); 303 wpabuf_put_le16(buf, 4); 304 wpabuf_put_le16(buf, period); 305 wpabuf_put_le16(buf, interval); 306 wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec " 307 "interval %u msec)", period, interval); 308 } 309 310 311 void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p) 312 { 313 /* P2P Interface */ 314 wpabuf_put_u8(buf, P2P_ATTR_INTERFACE); 315 wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN); 316 /* P2P Device address */ 317 wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 318 /* 319 * FIX: Fetch interface address list from driver. Do not include 320 * the P2P Device address if it is never used as interface address. 321 */ 322 /* P2P Interface Address Count */ 323 wpabuf_put_u8(buf, 1); 324 wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 325 } 326 327 328 void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country, 329 u8 oper_class, u8 channel, 330 enum p2p_role_indication role) 331 { 332 /* OOB Group Owner Negotiation Channel */ 333 wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL); 334 wpabuf_put_le16(buf, 6); 335 wpabuf_put_data(buf, country, 3); 336 wpabuf_put_u8(buf, oper_class); /* Operating Class */ 337 wpabuf_put_u8(buf, channel); /* Channel Number */ 338 wpabuf_put_u8(buf, (u8) role); /* Role indication */ 339 wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating " 340 "Class %u Channel %u Role %d", 341 oper_class, channel, role); 342 } 343 344 345 static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, 346 const char *val) 347 { 348 size_t len; 349 350 len = val ? os_strlen(val) : 0; 351 if (wpabuf_tailroom(buf) < 4 + len) 352 return -1; 353 wpabuf_put_be16(buf, attr); 354 #ifndef CONFIG_WPS_STRICT 355 if (len == 0) { 356 /* 357 * Some deployed WPS implementations fail to parse zeor-length 358 * attributes. As a workaround, send a space character if the 359 * device attribute string is empty. 360 */ 361 if (wpabuf_tailroom(buf) < 3) 362 return -1; 363 wpabuf_put_be16(buf, 1); 364 wpabuf_put_u8(buf, ' '); 365 return 0; 366 } 367 #endif /* CONFIG_WPS_STRICT */ 368 wpabuf_put_be16(buf, len); 369 if (val) 370 wpabuf_put_data(buf, val, len); 371 return 0; 372 } 373 374 375 int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, 376 int all_attr) 377 { 378 u8 *len; 379 int i; 380 381 if (wpabuf_tailroom(buf) < 6) 382 return -1; 383 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 384 len = wpabuf_put(buf, 1); 385 wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); 386 387 if (wps_build_version(buf) < 0) 388 return -1; 389 390 if (all_attr) { 391 if (wpabuf_tailroom(buf) < 5) 392 return -1; 393 wpabuf_put_be16(buf, ATTR_WPS_STATE); 394 wpabuf_put_be16(buf, 1); 395 wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED); 396 } 397 398 if (pw_id >= 0) { 399 if (wpabuf_tailroom(buf) < 6) 400 return -1; 401 /* Device Password ID */ 402 wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID); 403 wpabuf_put_be16(buf, 2); 404 wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", 405 pw_id); 406 wpabuf_put_be16(buf, pw_id); 407 } 408 409 if (all_attr) { 410 if (wpabuf_tailroom(buf) < 5) 411 return -1; 412 wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE); 413 wpabuf_put_be16(buf, 1); 414 wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO); 415 416 if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 || 417 p2p_add_wps_string(buf, ATTR_MANUFACTURER, 418 p2p->cfg->manufacturer) < 0 || 419 p2p_add_wps_string(buf, ATTR_MODEL_NAME, 420 p2p->cfg->model_name) < 0 || 421 p2p_add_wps_string(buf, ATTR_MODEL_NUMBER, 422 p2p->cfg->model_number) < 0 || 423 p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER, 424 p2p->cfg->serial_number) < 0) 425 return -1; 426 427 if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN) 428 return -1; 429 wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE); 430 wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN); 431 wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN); 432 433 if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name) 434 < 0) 435 return -1; 436 437 if (wpabuf_tailroom(buf) < 6) 438 return -1; 439 wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); 440 wpabuf_put_be16(buf, 2); 441 wpabuf_put_be16(buf, p2p->cfg->config_methods); 442 } 443 444 if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) 445 return -1; 446 447 if (all_attr && p2p->cfg->num_sec_dev_types) { 448 if (wpabuf_tailroom(buf) < 449 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types) 450 return -1; 451 wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST); 452 wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN * 453 p2p->cfg->num_sec_dev_types); 454 wpabuf_put_data(buf, p2p->cfg->sec_dev_type, 455 WPS_DEV_TYPE_LEN * 456 p2p->cfg->num_sec_dev_types); 457 } 458 459 /* Add the WPS vendor extensions */ 460 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 461 if (p2p->wps_vendor_ext[i] == NULL) 462 break; 463 if (wpabuf_tailroom(buf) < 464 4 + wpabuf_len(p2p->wps_vendor_ext[i])) 465 continue; 466 wpabuf_put_be16(buf, ATTR_VENDOR_EXT); 467 wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i])); 468 wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]); 469 } 470 471 p2p_buf_update_ie_hdr(buf, len); 472 473 return 0; 474 } 475