1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 8 * Sun elects to license this software under the BSD license. 9 * See README for more details. 10 */ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <stdarg.h> 17 #include <unistd.h> 18 #include <string.h> 19 #include <syslog.h> 20 #include <sys/stat.h> 21 #include <errno.h> 22 #include <signal.h> 23 #include <fcntl.h> 24 #include <door.h> 25 #include <libdladm.h> 26 #include <libdllink.h> 27 #include <sys/ethernet.h> 28 29 #include "wpa_impl.h" 30 #include "wpa_enc.h" 31 #include "driver.h" 32 #include "eloop.h" 33 #include "l2_packet.h" 34 35 static const char *wpa_supplicant_version = 36 "wpa_supplicant v1.0"; 37 38 extern struct wpa_driver_ops wpa_driver_wifi_ops; 39 int wpa_debug_level = MSG_ERROR; 40 41 /* 42 * wpa_printf - conditional printf 43 * @level: priority level (MSG_*) of the message 44 * @fmt: printf format string, followed by optional arguments 45 * 46 * This function is used to print conditional debugging and error messages. The 47 * output may be directed to stdout, stderr, and/or syslog based on 48 * configuration. 49 */ 50 void 51 wpa_printf(int level, char *fmt, ...) 52 { 53 va_list ap; 54 char buffer[MAX_LOGBUF]; 55 56 if (level < wpa_debug_level) 57 return; 58 59 va_start(ap, fmt); 60 61 /* LINTED E_SEC_PRINTF_VAR_FMT */ 62 (void) vsnprintf(buffer, sizeof (buffer), fmt, ap); 63 64 va_end(ap); 65 66 syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer); 67 } 68 69 /* 70 * wpa_hexdump - conditional hex dump 71 * @level: priority level (MSG_*) of the message 72 * @title: title of for the message 73 * @buf: data buffer to be dumped 74 * @len: length of the @buf 75 * 76 * This function is used to print conditional debugging and error messages. The 77 * output may be directed to stdout, stderr, and/or syslog based on 78 * configuration. The contents of @buf is printed out has hex dump. 79 */ 80 void 81 wpa_hexdump(int level, const char *title, const uint8_t *buf, size_t len) 82 { 83 size_t i; 84 char buffer[MAX_LOGBUF], tmp[4]; 85 int n; 86 87 if (level < wpa_debug_level) 88 return; 89 90 (void) snprintf(buffer, sizeof (buffer), "%s - hexdump(len=%d):", 91 title, len); 92 n = strlen(buffer); 93 94 for (i = 0; i < len; i++) { 95 (void) sprintf(tmp, " %02x", buf[i]); 96 97 n += strlen(tmp); 98 if (n >= MAX_LOGBUF) break; 99 100 (void) strlcat(buffer, tmp, sizeof (buffer)); 101 } 102 103 syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer); 104 } 105 106 static const char * 107 wpa_ssid_txt(char *ssid, size_t ssid_len) 108 { 109 static char ssid_txt[MAX_ESSID_LENGTH + 1]; 110 char *pos; 111 112 if (ssid_len > MAX_ESSID_LENGTH) 113 ssid_len = MAX_ESSID_LENGTH; 114 (void) memcpy(ssid_txt, ssid, ssid_len); 115 ssid_txt[ssid_len] = '\0'; 116 for (pos = ssid_txt; *pos != '\0'; pos ++) { 117 if ((uint8_t)*pos < 32 || (uint8_t)*pos >= 127) 118 *pos = '_'; 119 } 120 return (ssid_txt); 121 } 122 123 /* ARGSUSED */ 124 void 125 wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 126 { 127 struct wpa_supplicant *wpa_s = eloop_ctx; 128 struct wpa_ssid *ssid; 129 130 if (wpa_s->conf == NULL) 131 return; 132 133 if (wpa_s->wpa_state == WPA_DISCONNECTED) 134 wpa_s->wpa_state = WPA_SCANNING; 135 136 ssid = wpa_s->conf->ssid; 137 wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", 138 ssid ? "specific": "broadcast"); 139 140 if (ssid) { 141 wpa_printf(MSG_DEBUG, "Scan SSID: %s", ssid->ssid); 142 } 143 144 if (wpa_s->driver->scan(wpa_s->linkid)) { 145 wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); 146 } 147 } 148 149 void 150 wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) 151 { 152 wpa_printf(MSG_DEBUG, "Setting scan request: %d sec %d usec", 153 sec, usec); 154 (void) eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 155 (void) eloop_register_timeout(sec, usec, wpa_supplicant_scan, 156 wpa_s, NULL); 157 } 158 159 void 160 wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) 161 { 162 wpa_printf(MSG_DEBUG, "Cancelling scan request"); 163 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 164 } 165 166 /* ARGSUSED */ 167 static void 168 wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) 169 { 170 struct wpa_supplicant *wpa_s = eloop_ctx; 171 172 wpa_printf(MSG_INFO, "Authentication with " MACSTR " timed out.", 173 MAC2STR(wpa_s->bssid)); 174 175 wpa_s->reassociate = 1; 176 wpa_supplicant_req_scan(wpa_s, 0, 0); 177 } 178 179 void 180 wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, 181 int sec, int usec) 182 { 183 wpa_printf(MSG_DEBUG, "Setting authentication timeout: %d sec " 184 "%d usec", sec, usec); 185 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); 186 (void) eloop_register_timeout(sec, usec, wpa_supplicant_timeout, 187 wpa_s, NULL); 188 } 189 190 void 191 wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s) 192 { 193 wpa_printf(MSG_DEBUG, "Cancelling authentication timeout"); 194 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); 195 } 196 197 static void 198 wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) 199 { 200 l2_packet_deinit(wpa_s->l2); 201 wpa_s->l2 = NULL; 202 203 if (wpa_s->conf != NULL) { 204 wpa_config_free(wpa_s->conf); 205 wpa_s->conf = NULL; 206 } 207 208 free(wpa_s->ap_wpa_ie); 209 pmksa_candidate_free(wpa_s); 210 pmksa_cache_free(wpa_s); 211 } 212 213 static void 214 wpa_clear_keys(struct wpa_supplicant *wpa_s, uint8_t *addr) 215 { 216 wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, 217 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, NULL, 0); 218 wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, 219 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 1, 0, NULL, 0, NULL, 0); 220 wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, 221 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 2, 0, NULL, 0, NULL, 0); 222 wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, 223 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 3, 0, NULL, 0, NULL, 0); 224 if (addr) { 225 wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, addr, 226 0, 0, NULL, 0, NULL, 0); 227 } 228 } 229 230 static void 231 wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) 232 { 233 wpa_s->wpa_state = WPA_DISCONNECTED; 234 (void) memset(wpa_s->bssid, 0, IEEE80211_ADDR_LEN); 235 } 236 237 static int 238 wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, 239 dladm_wlan_ess_t *bss, struct wpa_ssid *ssid, 240 uint8_t *wpa_ie, int *wpa_ie_len) 241 { 242 struct wpa_ie_data ie; 243 int sel, proto; 244 uint8_t *ap_ie; 245 size_t ap_ie_len; 246 247 /* RSN or WPA */ 248 if (bss->we_wpa_ie_len && bss->we_wpa_ie[0] == RSN_INFO_ELEM && 249 (ssid->proto & WPA_PROTO_RSN)) { 250 wpa_printf(MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0"); 251 proto = WPA_PROTO_RSN; 252 } else { 253 wpa_printf(MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0"); 254 proto = WPA_PROTO_WPA; 255 } 256 257 ap_ie = bss->we_wpa_ie; 258 ap_ie_len = bss->we_wpa_ie_len; 259 260 if (wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) { 261 wpa_printf(MSG_WARNING, "WPA: Failed to parse WPA IE for " 262 "the selected BSS."); 263 return (-1); 264 } 265 266 wpa_s->proto = proto; 267 free(wpa_s->ap_wpa_ie); 268 wpa_s->ap_wpa_ie = malloc(ap_ie_len); 269 (void) memcpy(wpa_s->ap_wpa_ie, ap_ie, ap_ie_len); 270 wpa_s->ap_wpa_ie_len = ap_ie_len; 271 272 sel = ie.group_cipher & ssid->group_cipher; 273 if (sel & WPA_CIPHER_CCMP) { 274 wpa_s->group_cipher = WPA_CIPHER_CCMP; 275 } else if (sel & WPA_CIPHER_TKIP) { 276 wpa_s->group_cipher = WPA_CIPHER_TKIP; 277 } else if (sel & WPA_CIPHER_WEP104) { 278 wpa_s->group_cipher = WPA_CIPHER_WEP104; 279 } else if (sel & WPA_CIPHER_WEP40) { 280 wpa_s->group_cipher = WPA_CIPHER_WEP40; 281 } else { 282 wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher."); 283 return (-1); 284 } 285 286 sel = ie.pairwise_cipher & ssid->pairwise_cipher; 287 if (sel & WPA_CIPHER_CCMP) { 288 wpa_s->pairwise_cipher = WPA_CIPHER_CCMP; 289 } else if (sel & WPA_CIPHER_TKIP) { 290 wpa_s->pairwise_cipher = WPA_CIPHER_TKIP; 291 } else if (sel & WPA_CIPHER_NONE) { 292 wpa_s->pairwise_cipher = WPA_CIPHER_NONE; 293 } else { 294 wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise " 295 "cipher."); 296 return (-1); 297 } 298 299 sel = ie.key_mgmt & ssid->key_mgmt; 300 if (sel & WPA_KEY_MGMT_IEEE8021X) { 301 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 302 } else if (sel & WPA_KEY_MGMT_PSK) { 303 wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; 304 } else { 305 wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated " 306 "key management type."); 307 return (-1); 308 } 309 310 *wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie); 311 if (*wpa_ie_len < 0) { 312 wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE."); 313 return (-1); 314 } 315 wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len); 316 317 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) 318 (void) memcpy(wpa_s->pmk, ssid->psk, PMK_LEN); 319 else if (wpa_s->cur_pmksa) 320 (void) memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, PMK_LEN); 321 else { 322 (void) memset(wpa_s->pmk, 0, PMK_LEN); 323 } 324 325 return (0); 326 } 327 328 static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, 329 dladm_wlan_ess_t *bss, struct wpa_ssid *ssid) 330 { 331 uint8_t wpa_ie[IEEE80211_MAX_OPT_IE]; 332 int wpa_ie_len; 333 334 wpa_s->reassociate = 0; 335 wpa_printf(MSG_DEBUG, "Trying to associate with " MACSTR 336 " (SSID='%s' freq=%d MHz)", MAC2STR(bss->we_bssid.wb_bytes), 337 wpa_ssid_txt((char *)ssid->ssid, ssid->ssid_len), bss->we_freq); 338 wpa_supplicant_cancel_scan(wpa_s); 339 340 if (bss->we_wpa_ie_len && 341 (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) { 342 wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, 343 bss->we_bssid.wb_bytes, NULL); 344 if (wpa_s->cur_pmksa) { 345 wpa_hexdump(MSG_DEBUG, "RSN: PMKID", 346 wpa_s->cur_pmksa->pmkid, PMKID_LEN); 347 } 348 if (wpa_supplicant_set_suites(wpa_s, bss, ssid, 349 wpa_ie, &wpa_ie_len)) { 350 wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key " 351 "management and encryption suites"); 352 return; 353 } 354 } else { 355 wpa_ie_len = 0; 356 } 357 358 wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes); 359 wpa_s->wpa_state = WPA_ASSOCIATING; 360 wpa_s->driver->associate(wpa_s->linkid, 361 (const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len); 362 363 /* Timeout for IEEE 802.11 authentication and association */ 364 wpa_supplicant_req_auth_timeout(wpa_s, 15, 0); 365 } 366 367 void 368 wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code) 369 { 370 uint8_t *addr = NULL; 371 wpa_s->wpa_state = WPA_DISCONNECTED; 372 if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", 373 IEEE80211_ADDR_LEN) != 0) { 374 wpa_s->driver->disassociate(wpa_s->linkid, reason_code); 375 addr = wpa_s->bssid; 376 } 377 wpa_clear_keys(wpa_s, addr); 378 } 379 380 static dladm_wlan_ess_t * 381 wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, 382 dladm_wlan_ess_t *results, int num, struct wpa_ssid **selected_ssid) 383 { 384 struct wpa_ssid *ssid; 385 dladm_wlan_ess_t *bss, *selected = NULL; 386 int i; 387 388 struct wpa_ie_data ie; 389 390 wpa_printf(MSG_DEBUG, "Selecting BSS from scan results (%d)", num); 391 392 bss = NULL; 393 ssid = NULL; 394 395 /* try to find matched AP */ 396 for (i = 0; i < num && !selected; i++) { 397 bss = &results[i]; 398 wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " 399 "wpa_ie_len=%d", 400 i, MAC2STR(bss->we_bssid.wb_bytes), 401 wpa_ssid_txt(bss->we_ssid.we_bytes, bss->we_ssid_len), 402 bss->we_wpa_ie_len); 403 if (bss->we_wpa_ie_len == 0) { 404 wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE"); 405 } 406 407 ssid = group; 408 if (bss->we_ssid_len != ssid->ssid_len || 409 memcmp(bss->we_ssid.we_bytes, ssid->ssid, 410 bss->we_ssid_len) != 0) { 411 wpa_printf(MSG_DEBUG, " skip - SSID mismatch"); 412 continue; 413 } 414 if (!((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)) && 415 wpa_parse_wpa_ie(wpa_s, bss->we_wpa_ie, 416 bss->we_wpa_ie_len, &ie) == 0)) { 417 wpa_printf(MSG_DEBUG, " skip - " 418 "could not parse WPA/RSN IE"); 419 continue; 420 } 421 if (!(ie.proto & ssid->proto)) { 422 wpa_printf(MSG_DEBUG, " skip - proto mismatch"); 423 continue; 424 } 425 if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { 426 wpa_printf(MSG_DEBUG, " skip - PTK cipher mismatch"); 427 continue; 428 } 429 if (!(ie.group_cipher & ssid->group_cipher)) { 430 wpa_printf(MSG_DEBUG, " skip - GTK cipher mismatch"); 431 continue; 432 } 433 if (!(ie.key_mgmt & ssid->key_mgmt)) { 434 wpa_printf(MSG_DEBUG, " skip - key mgmt mismatch"); 435 continue; 436 } 437 438 selected = bss; 439 *selected_ssid = ssid; 440 wpa_printf(MSG_DEBUG, " selected"); 441 } 442 443 return (selected); 444 } 445 446 447 static void 448 wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s) 449 { 450 dladm_wlan_ess_t results[MAX_SCANRESULTS]; 451 int num; 452 dladm_wlan_ess_t *selected = NULL; 453 struct wpa_ssid *ssid; 454 455 (void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS); 456 num = wpa_s->driver->get_scan_results(wpa_s->linkid, results, 457 MAX_SCANRESULTS); 458 wpa_printf(MSG_DEBUG, "Scan results: %d", num); 459 if (num < 0) 460 return; 461 if (num > MAX_SCANRESULTS) { 462 wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)", 463 num, MAX_SCANRESULTS); 464 num = MAX_SCANRESULTS; 465 } 466 467 selected = wpa_supplicant_select_bss(wpa_s, 468 wpa_s->conf->ssid, results, num, &ssid); 469 470 if (selected) { 471 if (wpa_s->reassociate || 472 memcmp(selected->we_bssid.wb_bytes, wpa_s->bssid, 473 IEEE80211_ADDR_LEN) != 0) { 474 wpa_supplicant_associate(wpa_s, selected, ssid); 475 } else { 476 wpa_printf(MSG_DEBUG, "Already associated with the " 477 "selected AP."); 478 } 479 } else { 480 wpa_printf(MSG_DEBUG, "No suitable AP found."); 481 wpa_supplicant_req_scan(wpa_s, 5, 0); /* wait 5 seconds */ 482 } 483 } 484 485 /* 486 * wpa_event_handler - report a driver event for wpa_supplicant 487 * @wpa_s: pointer to wpa_supplicant data; this is the @ctx variable registered 488 * with wpa_driver_events_init() 489 * @event: event type (defined above) 490 * 491 * Driver wrapper code should call this function whenever an event is received 492 * from the driver. 493 */ 494 void 495 wpa_event_handler(void *cookie, wpa_event_type event) 496 { 497 struct wpa_supplicant *wpa_s = cookie; 498 uint8_t bssid[IEEE80211_ADDR_LEN]; 499 500 switch (event) { 501 case EVENT_ASSOC: 502 wpa_s->wpa_state = WPA_ASSOCIATED; 503 wpa_printf(MSG_DEBUG, "\nAssociation event - clear replay " 504 "counter\n"); 505 (void) memset(wpa_s->rx_replay_counter, 0, 506 WPA_REPLAY_COUNTER_LEN); 507 wpa_s->rx_replay_counter_set = 0; 508 wpa_s->renew_snonce = 1; 509 if (wpa_s->driver->get_bssid(wpa_s->linkid, 510 (char *)bssid) >= 0 && 511 memcmp(bssid, wpa_s->bssid, IEEE80211_ADDR_LEN) != 0) { 512 wpa_printf(MSG_DEBUG, "Associated to a new BSS: " 513 "BSSID=" MACSTR, MAC2STR(bssid)); 514 (void) memcpy(wpa_s->bssid, bssid, IEEE80211_ADDR_LEN); 515 if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE) 516 wpa_clear_keys(wpa_s, bssid); 517 } 518 519 wpa_s->eapol_received = 0; 520 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { 521 wpa_supplicant_cancel_auth_timeout(wpa_s); 522 } else { 523 /* Timeout for receiving the first EAPOL packet */ 524 wpa_supplicant_req_auth_timeout(wpa_s, 10, 0); 525 } 526 break; 527 case EVENT_DISASSOC: 528 if (wpa_s->wpa_state >= WPA_ASSOCIATED) 529 wpa_supplicant_req_scan(wpa_s, 0, 100000); 530 wpa_supplicant_mark_disassoc(wpa_s); 531 wpa_printf(MSG_DEBUG, "Disconnect event - remove keys"); 532 if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE) 533 wpa_clear_keys(wpa_s, wpa_s->bssid); 534 break; 535 case EVENT_SCAN_RESULTS: 536 wpa_supplicant_scan_results(wpa_s); 537 break; 538 default: 539 wpa_printf(MSG_INFO, "Unknown event %d", event); 540 break; 541 } 542 } 543 544 /* ARGSUSED */ 545 static void 546 wpa_supplicant_terminate(int sig, void *eloop_ctx, void *signal_ctx) 547 { 548 wpa_printf(MSG_INFO, "Signal %d received - terminating", sig); 549 eloop_terminate(); 550 } 551 552 static int 553 wpa_supplicant_driver_init(const char *link, struct wpa_supplicant *wpa_s) 554 { 555 wpa_s->l2 = l2_packet_init(link, ETHERTYPE_EAPOL, 556 wpa_supplicant_rx_eapol, wpa_s); 557 if (wpa_s->l2 == NULL) 558 return (-1); 559 560 if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) { 561 (void) fprintf(stderr, "Failed to get own L2 address\n"); 562 return (-1); 563 } 564 565 if (wpa_s->driver->set_wpa(wpa_s->linkid, 1) < 0) { 566 wpa_printf(MSG_ERROR, "Failed to enable WPA in the driver."); 567 return (-1); 568 } 569 570 wpa_clear_keys(wpa_s, NULL); 571 wpa_supplicant_req_scan(wpa_s, 0, 100000); 572 573 return (0); 574 } 575 576 static int door_id = -1; 577 578 /* ARGSUSED */ 579 static void 580 event_handler(void *cookie, char *argp, size_t asize, 581 door_desc_t *dp, uint_t n_desc) 582 { 583 wpa_event_type event; 584 585 event = ((wl_events_t *)argp)->event; 586 wpa_event_handler(cookie, event); 587 588 (void) door_return(NULL, 0, NULL, 0); 589 } 590 591 /* 592 * Create the driver to wpad door 593 */ 594 int 595 wpa_supplicant_door_setup(void *cookie, char *doorname) 596 { 597 struct stat stbuf; 598 int error = 0; 599 600 wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname); 601 /* 602 * Create the door 603 */ 604 door_id = door_create(event_handler, cookie, 605 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 606 607 if (door_id < 0) { 608 error = -1; 609 goto out; 610 } 611 612 if (stat(doorname, &stbuf) < 0) { 613 int newfd; 614 if ((newfd = creat(doorname, 0666)) < 0) { 615 (void) door_revoke(door_id); 616 door_id = -1; 617 error = -1; 618 619 goto out; 620 } 621 (void) close(newfd); 622 } 623 624 if (fattach(door_id, doorname) < 0) { 625 if ((errno != EBUSY) || (fdetach(doorname) < 0) || 626 (fattach(door_id, doorname) < 0)) { 627 (void) door_revoke(door_id); 628 door_id = -1; 629 error = -1; 630 631 goto out; 632 } 633 } 634 635 out: 636 return (error); 637 } 638 639 void 640 wpa_supplicant_door_destroy(char *doorname) 641 { 642 wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname); 643 644 if (door_id == -1) 645 return; 646 647 if (door_revoke(door_id) == -1) { 648 wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.", 649 door_id, strerror(errno)); 650 } 651 652 if (fdetach(doorname) == -1) { 653 wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.", 654 doorname, strerror(errno)); 655 } 656 657 (void) close(door_id); 658 } 659 660 static int 661 wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value) 662 { 663 free(ssid->ssid); 664 665 ssid->ssid = (uint8_t *)strdup(value); 666 ssid->ssid_len = strlen(value); 667 668 if (ssid->ssid == NULL) { 669 wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value); 670 return (-1); 671 } 672 if (ssid->ssid_len > MAX_ESSID_LENGTH) { 673 free(ssid->ssid); 674 wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value); 675 return (-1); 676 } 677 wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid); 678 return (0); 679 } 680 681 static struct wpa_ssid * 682 wpa_config_read_network(struct wpa_supplicant *wpa_s) 683 { 684 struct wpa_ssid *ssid; 685 char buf[MAX_ESSID_LENGTH + 1]; 686 dladm_secobj_class_t cl; 687 uint8_t psk[MAX_PSK_LENGTH + 1]; 688 uint_t key_len; 689 690 wpa_printf(MSG_MSGDUMP, "Start of a new network configration"); 691 692 ssid = (struct wpa_ssid *)malloc(sizeof (*ssid)); 693 if (ssid == NULL) 694 return (NULL); 695 (void) memset(ssid, 0, sizeof (*ssid)); 696 697 /* 698 * Set default supported values 699 */ 700 ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN; 701 ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; 702 ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | 703 WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40; 704 ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */ 705 706 (void) memset(buf, 0, MAX_ESSID_LENGTH + 1); 707 wpa_s->driver->get_ssid(wpa_s->linkid, (char *)buf); 708 709 (void) wpa_config_parse_ssid(ssid, 0, buf); 710 711 key_len = sizeof (psk); 712 (void) dladm_get_secobj((const char *)wpa_s->kname, &cl, psk, &key_len, 713 DLADM_OPT_ACTIVE); 714 psk[key_len] = '\0'; 715 ssid->passphrase = strdup((const char *)psk); 716 717 if (ssid->passphrase) { 718 pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid, 719 ssid->ssid_len, 4096, ssid->psk, PMK_LEN); 720 wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)", 721 ssid->psk, PMK_LEN); 722 ssid->psk_set = 1; 723 } 724 725 if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) { 726 wpa_printf(MSG_ERROR, "WPA-PSK accepted for key " 727 "management, but no PSK configured."); 728 free(ssid); 729 ssid = NULL; 730 } 731 732 return (ssid); 733 } 734 735 struct wpa_config * 736 wpa_config_read(void *arg) 737 { 738 struct wpa_ssid *ssid; 739 struct wpa_config *config; 740 struct wpa_supplicant *wpa_s = arg; 741 742 config = malloc(sizeof (*config)); 743 if (config == NULL) 744 return (NULL); 745 (void) memset(config, 0, sizeof (*config)); 746 config->eapol_version = 1; /* fixed value */ 747 748 wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n"); 749 750 ssid = wpa_config_read_network(wpa_s); 751 if (ssid == NULL) { 752 wpa_config_free(config); 753 config = NULL; 754 } else { 755 config->ssid = ssid; 756 } 757 758 return (config); 759 } 760 761 void 762 wpa_config_free(struct wpa_config *config) 763 { 764 struct wpa_ssid *ssid = config->ssid; 765 766 if (ssid != NULL) { 767 free(ssid->ssid); 768 free(ssid->passphrase); 769 free(ssid); 770 } 771 free(config); 772 } 773 774 static int 775 daemon(boolean_t nochdir, boolean_t noclose) 776 { 777 int retv; 778 779 if ((retv = fork()) == -1) 780 return (-1); 781 if (retv != 0) 782 _exit(EXIT_SUCCESS); 783 if (setsid() == -1) 784 return (-1); 785 786 if (!nochdir && chdir("/") == -1) 787 return (-1); 788 789 if (!noclose) { 790 (void) close(0); 791 (void) close(1); 792 (void) close(2); 793 if ((retv = open("/dev/null", O_RDWR)) != -1) { 794 (void) dup2(retv, 1); 795 (void) dup2(retv, 2); 796 } 797 } 798 799 return (0); 800 } 801 802 static void 803 usage(void) 804 { 805 (void) printf("%s\n\n" 806 "usage:\n" 807 " wpa_supplicant [-hv] -i<ifname> -k<keyname>\n" 808 "options:\n" 809 " -h = show this help text\n" 810 " -v = show version\n", 811 wpa_supplicant_version); 812 } 813 814 int 815 main(int argc, char *argv[]) 816 { 817 struct wpa_supplicant wpa_s; 818 char *link = NULL; 819 char *key = NULL; 820 dlpi_handle_t dh = NULL; 821 datalink_id_t linkid; 822 dladm_phys_attr_t dpa; 823 int c; 824 int exitcode; 825 char door_file[WPA_STRSIZE]; 826 827 for (;;) { 828 c = getopt(argc, argv, "Dk:hi:v"); 829 if (c < 0) 830 break; 831 switch (c) { 832 case 'D': 833 wpa_debug_level = MSG_DEBUG; 834 break; 835 case 'h': 836 usage(); 837 return (-1); 838 case 'i': 839 link = optarg; 840 break; 841 case 'k': 842 key = optarg; 843 break; 844 case 'v': 845 (void) printf("%s\n", wpa_supplicant_version); 846 return (-1); 847 default: 848 usage(); 849 return (-1); 850 } 851 } 852 853 /* 854 * key name is required to retrieve PSK value through libwdladm APIs. 855 * key is saved by dladm command by keyname 856 * see dladm. 857 */ 858 if ((link == NULL) || (key == NULL)) { 859 wpa_printf(MSG_ERROR, "\nLink & key is required."); 860 return (-1); 861 } 862 863 if ((strlen(key) >= sizeof (wpa_s.kname))) { 864 wpa_printf(MSG_ERROR, "Too long key name '%s'.", key); 865 return (-1); 866 } 867 868 if (daemon(0, 0)) 869 return (-1); 870 871 /* 872 * Hold this link open to prevent a link renaming operation. 873 */ 874 if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) { 875 wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link); 876 return (-1); 877 } 878 879 if (dladm_name2info(link, &linkid, NULL, NULL, NULL) != 880 DLADM_STATUS_OK) { 881 wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link); 882 dlpi_close(dh); 883 return (-1); 884 } 885 886 /* 887 * Get the device name of the link, which will be used as the door 888 * file name used to communicate with the driver. Note that different 889 * links use different doors. 890 */ 891 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 892 DLADM_STATUS_OK) { 893 wpa_printf(MSG_ERROR, 894 "Failed to get device name of link '%s'.", link); 895 dlpi_close(dh); 896 return (-1); 897 } 898 (void) snprintf(door_file, WPA_STRSIZE, "%s_%s", WPA_DOOR, dpa.dp_dev); 899 900 (void) memset(&wpa_s, 0, sizeof (wpa_s)); 901 wpa_s.driver = &wpa_driver_wifi_ops; 902 wpa_s.linkid = linkid; 903 (void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname)); 904 eloop_init(&wpa_s); 905 906 /* 907 * Setup default WPA/WPA2 configuration 908 * get ESSID and PSK value 909 */ 910 wpa_s.conf = wpa_config_read(&wpa_s); 911 if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) { 912 wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n"); 913 exitcode = -1; 914 goto cleanup; 915 } 916 917 exitcode = 0; 918 919 /* 920 * Setup door file to communicate with driver 921 */ 922 if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) { 923 wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file); 924 exitcode = -1; 925 goto cleanup; 926 } 927 928 wpa_s.renew_snonce = 1; 929 if (wpa_supplicant_driver_init(link, &wpa_s) < 0) { 930 exitcode = -1; 931 goto cleanup; 932 } 933 934 /* 935 * This link is hold again in wpa_supplicant_driver_init(), so that 936 * we release the first reference. 937 */ 938 dlpi_close(dh); 939 dh = NULL; 940 941 wpa_printf(MSG_DEBUG, "=> eloop_run"); 942 943 (void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL); 944 (void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL); 945 (void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL); 946 947 eloop_run(); 948 949 wpa_printf(MSG_DEBUG, "<= eloop_run()"); 950 wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING); 951 952 if (wpa_s.driver->set_wpa(wpa_s.linkid, 0) < 0) { 953 wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n"); 954 } 955 956 cleanup: 957 wpa_supplicant_door_destroy(door_file); 958 wpa_supplicant_cleanup(&wpa_s); 959 eloop_destroy(); 960 961 if (dh != NULL) 962 dlpi_close(dh); 963 964 return (exitcode); 965 } 966