Created
June 7, 2010 00:07
-
-
Save an-roo/428052 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| wl_iw_setap(struct net_device *dev, struct ap_profile *ap) | |
| { | |
| int updown = 0; | |
| int channel = 0; | |
| int wsec = 0; | |
| int wpa_auth = 0; | |
| int apstate = 1; | |
| wlc_ssid_t ap_ssid; | |
| wlc_ssid_t null_ssid; | |
| int max_assoc = 8; | |
| //char deauth_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | |
| int i; | |
| char * ptr; | |
| int mpc = 0; | |
| int wep = 0; | |
| wl_wsec_key_t key; | |
| #ifdef CUSTOMER_HW2 /* HTC need limited the selected channel */ | |
| int start_channel, end_channel; | |
| #endif | |
| memset(&null_ssid, 0, sizeof(wlc_ssid_t)); | |
| WL_SOFTAP(("wl_iw: set ap profile:\n")); | |
| WL_SOFTAP((" ssid = %s\n", ap->ssid)); | |
| WL_SOFTAP((" security = %s\n", ap->sec)); | |
| if (ap->key[0] != '\0') | |
| WL_SOFTAP((" key = %s\n", ap->key)); | |
| WL_SOFTAP((" channel = %d\n", ap->channel)); | |
| WL_SOFTAP((" max scb = %d\n", ap->max_scb)); | |
| dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)); | |
| apstate = 0; | |
| dev_wlc_ioctl(dev, WLC_SET_AP, &apstate, sizeof(apstate)); | |
| apstate = 1; | |
| dev_wlc_ioctl(dev, WLC_SET_AP, &apstate, sizeof(apstate)); | |
| /* check auto channel later */ | |
| #ifdef CUSTOMER_HW2 /* HTC need limited the selected channel */ | |
| if ((ap->channel >> 8) || (ap->channel == 0)) | |
| #else | |
| if (ap->channel == 0) | |
| #endif | |
| #if 1 | |
| { | |
| int chosen = 0; | |
| wl_uint32_list_t request; | |
| int rescan = 0; | |
| int retry = 0; | |
| int ret = 0; | |
| dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); | |
| dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid)); | |
| auto_channel_retry: | |
| request.count = htod32(0); | |
| ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request)); | |
| if (ret < 0) { | |
| WL_SOFTAP(("can't start auto channel scan\n")); | |
| return -1; | |
| } | |
| get_channel_retry: | |
| bcm_mdelay(500); | |
| ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); | |
| if (ret < 0 || dtoh32(chosen) == 0) { | |
| if (retry++ < 3) | |
| goto get_channel_retry; | |
| else { | |
| WL_SOFTAP(("can't get auto channel sel, err = %d, chosen = %d\n", ret, chosen)); | |
| return -1; | |
| } | |
| } | |
| if ((chosen == 1) && (!rescan++)) | |
| goto auto_channel_retry; | |
| #ifdef CUSTOMER_HW2 /* HTC need limited the selected channel */ | |
| if (ap->channel == 0) | |
| ap->channel = chosen; | |
| else { | |
| start_channel = (ap->channel >> 8) & 0xff; | |
| end_channel = ap->channel & 0xff; | |
| WL_SOFTAP(("channel range from %d to %d\n", start_channel, end_channel)); | |
| if (chosen > end_channel) { | |
| if (chosen <= 6) | |
| chosen = end_channel; | |
| else | |
| chosen = start_channel; | |
| } else if (chosen < start_channel) | |
| chosen = start_channel; | |
| ap->channel = chosen; | |
| } | |
| #else | |
| ap->channel = chosen; | |
| #endif | |
| WL_SOFTAP(("Set auto channel = %d\n", chosen)); | |
| dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)); | |
| } | |
| #else | |
| ap->channel = 6; | |
| #endif | |
| channel = ap->channel; | |
| dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)); | |
| if (strnicmp(ap->sec, "open", strlen("open")) == 0) { | |
| wsec = 0; | |
| dev_wlc_intvar_set(dev, "wsec", wsec); | |
| wpa_auth = WPA_AUTH_DISABLED; | |
| dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); | |
| } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) { | |
| memset(&key, 0, sizeof(key)); | |
| wsec = WEP_ENABLED; | |
| dev_wlc_intvar_set(dev, "wsec", wsec); | |
| key.index = 0; | |
| if (wl_iw_parse_wep(ap->key, &key)) { | |
| WL_SOFTAP(("wep key parse err!\n")); | |
| return -1; | |
| } | |
| key.index = htod32(key.index); | |
| key.len = htod32(key.len); | |
| key.algo = htod32(key.algo); | |
| key.flags = htod32(key.flags); | |
| wep = 1; | |
| wpa_auth = WPA_AUTH_DISABLED; | |
| dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); | |
| } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) { | |
| wsec_pmk_t psk; | |
| size_t key_len; | |
| wsec = AES_ENABLED; | |
| dev_wlc_intvar_set(dev, "wsec", wsec); | |
| key_len = strlen(ap->key); | |
| if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { | |
| WL_SOFTAP(("passphrase must be between %d and %d characters long\n", | |
| WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN)); | |
| return -1; | |
| } | |
| /* anthony: turn all psk-key to 64 char wide in default. */ | |
| if ( key_len < WSEC_MAX_PSK_LEN ){ | |
| unsigned char output[2*SHA1HashSize]; | |
| char key_str_buf[WSEC_MAX_PSK_LEN+1]; | |
| /* anthony: call passhash to make hash */ | |
| pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32); | |
| /* anthony: turn hex digit to char string */ | |
| ptr = key_str_buf; | |
| for (i=0; i<(WSEC_MAX_PSK_LEN/8); i++){ | |
| /* anthony: the order is comfirmed in big-endian. It maybe different in little-endian? */ | |
| sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], (uint)output[i*4+1], (uint)output[i*4+2], (uint)output[i*4+3]); | |
| ptr += 8; | |
| } | |
| printk("%s: passphase = %s\n", __FUNCTION__, key_str_buf); | |
| psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN); | |
| memcpy(psk.key, key_str_buf, psk.key_len); | |
| } else { | |
| psk.key_len = htod16((ushort) key_len); | |
| memcpy(psk.key, ap->key, key_len); | |
| } | |
| psk.flags = htod16(WSEC_PASSPHRASE); | |
| dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); | |
| wpa_auth = WPA2_AUTH_PSK; | |
| dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); | |
| } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) { | |
| wsec_pmk_t psk; | |
| size_t key_len; | |
| wsec = TKIP_ENABLED; | |
| dev_wlc_intvar_set(dev, "wsec", wsec); | |
| key_len = strlen(ap->key); | |
| if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { | |
| WL_SOFTAP(("passphrase must be between %d and %d characters long\n", | |
| WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN)); | |
| return -1; | |
| } | |
| /* anthony: turn all psk-key to 64 char wide in default. */ | |
| if ( key_len < WSEC_MAX_PSK_LEN ){ | |
| unsigned char output[2*SHA1HashSize]; | |
| char key_str_buf[WSEC_MAX_PSK_LEN+1]; | |
| printk("%s: do passhash...\n", __FUNCTION__); | |
| /* anthony: call passhash to make hash */ | |
| pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32); | |
| /* anthony: turn hex digit to char string */ | |
| ptr = key_str_buf; | |
| for (i=0; i<(WSEC_MAX_PSK_LEN/8); i++) | |
| { | |
| printk("[%02d]: %08x\n", i, *((unsigned int*)&output[i*4])); | |
| /* anthony: the order is comfirmed in big-endian. It maybe different in little-endian? */ | |
| sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], (uint)output[i*4+1], (uint)output[i*4+2], (uint)output[i*4+3]); | |
| ptr += 8; | |
| } | |
| printk("%s: passphase = %s\n", __FUNCTION__, key_str_buf); | |
| psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN); | |
| memcpy(psk.key, key_str_buf, psk.key_len); | |
| } else { | |
| psk.key_len = htod16((ushort) key_len); | |
| memcpy(psk.key, ap->key, key_len); | |
| } | |
| psk.flags = htod16(WSEC_PASSPHRASE); | |
| dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); | |
| wpa_auth = WPA_AUTH_PSK; | |
| dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); | |
| } | |
| WL_SOFTAP(("ap setup done\n")); | |
| updown = 0; | |
| dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); | |
| max_assoc = ap->max_scb; | |
| dev_wlc_intvar_set(dev, "maxassoc", max_assoc); | |
| ap_mode = 1; | |
| ap_ssid.SSID_len = strlen(ap->ssid); | |
| strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); | |
| dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid)); | |
| dev_wlc_intvar_set(dev, "mpc", mpc); | |
| if (wep) | |
| dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment