/* src/p80211/p80211wext.c * * Glue code to make linux-wlan-ng a happy wireless extension camper. * * original author: Reyk Floeter * Completely re-written by Solomon Peachy * * Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. * -------------------------------------------------------------------- * * linux-wlan * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License version 2 (the "GPL"), in which * case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use * your version of this file under the MPL, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete * the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * -------------------------------------------------------------------- */ /*================================================================*/ /* System Includes */ #include #include #include #include #include #include #include #include #if WIRELESS_EXT > 12 #include #endif #include #include #include #include /*================================================================*/ /* Project Includes */ #include "version.h" #include "wlan_compat.h" #include "p80211types.h" #include "p80211hdr.h" #include "p80211conv.h" #include "p80211mgmt.h" #include "p80211msg.h" #include "p80211metastruct.h" #include "p80211metadef.h" #include "p80211netdev.h" #include "p80211ioctl.h" #include "p80211req.h" static int p80211wext_giwrate(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra); static int p80211wext_giwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid); /* compatibility to wireless extensions */ #ifdef WIRELESS_EXT static UINT8 p80211_mhz_to_channel(UINT16 mhz) { if (mhz >= 5000) { return ((mhz - 5000) / 5); } if (mhz == 2482) return 14; if (mhz >= 2407) { return ((mhz - 2407) / 5); } return 0; } static UINT16 p80211_channel_to_mhz(UINT8 ch, int dot11a) { if (ch == 0) return 0; if (ch > 200) return 0; /* 5G */ if (dot11a) { return (5000 + (5 * ch)); } /* 2.4G */ if (ch == 14) return 2484; if ((ch < 14) && (ch > 0)) { return (2407 + (5 * ch)); } return 0; } /* taken from orinoco.c ;-) */ static const long p80211wext_channel_freq[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; #define NUM_CHANNELS (sizeof(p80211wext_channel_freq) / sizeof(p80211wext_channel_freq[0])) /* steal a spare bit to store the shared/opensystems state. should default to open if not set */ #define HOSTWEP_SHAREDKEY BIT3 /** function declarations =============== */ static int qual_as_percent(int snr ) { if ( snr <= 0 ) return 0; if ( snr <= 40 ) return snr*5/2; return 100; } static int p80211wext_dorequest(wlandevice_t *wlandev, UINT32 did, UINT32 data) { p80211msg_dot11req_mibset_t msg; p80211item_uint32_t mibitem; int result; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibset; mibitem.did = did; mibitem.data = data; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); DBFEXIT; return result; } static int p80211wext_autojoin(wlandevice_t *wlandev) { p80211msg_lnxreq_autojoin_t msg; struct iw_point data; char ssid[IW_ESSID_MAX_SIZE]; int result; int err = 0; DBFENTER; /* Get ESSID */ result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid); if (result) { err = -EFAULT; goto exit; } if ( wlandev->hostwep & HOSTWEP_SHAREDKEY ) msg.authtype.data = P80211ENUM_authalg_sharedkey; else msg.authtype.data = P80211ENUM_authalg_opensystem; msg.msgcode = DIDmsg_lnxreq_autojoin; /* Trim the last '\0' to fit the SSID format */ if (data.length && ssid[data.length-1] == '\0') { data.length = data.length - 1; } memcpy(msg.ssid.data.data, ssid, data.length); msg.ssid.data.len = data.length; result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } /* called by /proc/net/wireless */ struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev) { p80211msg_lnxreq_commsquality_t quality; wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct iw_statistics* wstats = &wlandev->wstats; int retval; DBFENTER; /* Check */ if ( (wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING) ) return NULL; /* XXX Only valid in station mode */ wstats->status = 0; /* build request message */ quality.msgcode = DIDmsg_lnxreq_commsquality; quality.dbm.data = P80211ENUM_truth_true; quality.dbm.status = P80211ENUM_msgitem_status_data_ok; /* send message to nsd */ if ( wlandev->mlmerequest == NULL ) return NULL; retval = wlandev->mlmerequest(wlandev, (p80211msg_t*) &quality); wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */ wstats->qual.level = quality.level.data; /* instant signal level */ wstats->qual.noise = quality.noise.data; /* instant noise level */ #if WIRELESS_EXT > 18 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else wstats->qual.updated = 7; #endif wstats->discard.code = wlandev->rx.decrypt_err; wstats->discard.nwid = 0; wstats->discard.misc = 0; #if WIRELESS_EXT > 11 wstats->discard.fragment = 0; // incomplete fragments wstats->discard.retries = 0; // tx retries. wstats->miss.beacon = 0; #endif DBFEXIT; return wstats; } static int p80211wext_giwname(netdevice_t *dev, struct iw_request_info *info, char *name, char *extra) { struct iw_param rate; int result; int err = 0; DBFENTER; result = p80211wext_giwrate(dev, NULL, &rate, NULL); if (result) { err = -EFAULT; goto exit; } switch (rate.value) { case 1000000: case 2000000: strcpy(name, "IEEE 802.11-DS"); break; case 5500000: case 11000000: strcpy(name, "IEEE 802.11-b"); break; } exit: DBFEXIT; return err; } static int p80211wext_giwfreq(netdevice_t *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); if (mibitem.data > NUM_CHANNELS) { err = -EFAULT; goto exit; } /* convert into frequency instead of a channel */ freq->e = 1; freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000; exit: DBFEXIT; return err; } static int p80211wext_siwfreq(netdevice_t *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } msg.msgcode = DIDmsg_dot11req_mibset; mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; mibitem.status = P80211ENUM_msgitem_status_data_ok; if ( (freq->e == 0) && (freq->m <= 1000) ) mibitem.data = freq->m; else mibitem.data = p80211_mhz_to_channel(freq->m); memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } #if WIRELESS_EXT > 8 static int p80211wext_giwmode(netdevice_t *dev, struct iw_request_info *info, __u32 *mode, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; DBFENTER; switch (wlandev->macmode) { case WLAN_MACMODE_IBSS_STA: *mode = IW_MODE_ADHOC; break; case WLAN_MACMODE_ESS_STA: *mode = IW_MODE_INFRA; break; case WLAN_MACMODE_ESS_AP: *mode = IW_MODE_MASTER; break; default: /* Not set yet. */ *mode = IW_MODE_AUTO; } DBFEXIT; return 0; } static int p80211wext_siwmode(netdevice_t *dev, struct iw_request_info *info, __u32 *mode, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && *mode != IW_MODE_MASTER) { err = (-EOPNOTSUPP); goto exit; } /* Operation mode is the same with current mode */ if (*mode == wlandev->macmode) goto exit; switch (*mode) { case IW_MODE_ADHOC: wlandev->macmode = WLAN_MACMODE_IBSS_STA; break; case IW_MODE_INFRA: wlandev->macmode = WLAN_MACMODE_ESS_STA; break; case IW_MODE_MASTER: wlandev->macmode = WLAN_MACMODE_ESS_AP; break; default: /* Not set yet. */ WLAN_LOG_INFO("Operation mode: %d not support\n", *mode); return -EOPNOTSUPP; } /* Set Operation mode to the PORT TYPE RID */ #warning "get rid of p2mib here" msg.msgcode = DIDmsg_dot11req_mibset; mibitem.did = DIDmib_p2_p2Static_p2CnfPortType; mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) err = -EFAULT; exit: DBFEXIT; return err; } static int p80211wext_giwrange(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { struct iw_range *range = (struct iw_range *) extra; int i, val; DBFENTER; // for backward compatability set size & zero everything we don't understand data->length = sizeof(*range); memset(range,0,sizeof(*range)); #if WIRELESS_EXT > 9 range->txpower_capa = IW_TXPOW_DBM; // XXX what about min/max_pmp, min/max_pmt, etc. #endif #if WIRELESS_EXT > 10 range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 13; range->retry_capa = IW_RETRY_LIMIT; range->retry_flags = IW_RETRY_LIMIT; range->min_retry = 0; range->max_retry = 255; #endif /* WIRELESS_EXT > 10 */ #if WIRELESS_EXT > 16 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | //mode/freq/ssid IW_EVENT_CAPA_MASK(SIOCGIWAP) | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); range->event_capa[1] = IW_EVENT_CAPA_K_1; //encode range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) | IW_EVENT_CAPA_MASK(IWEVCUSTOM) ); #endif range->num_channels = NUM_CHANNELS; /* XXX need to filter against the regulatory domain &| active set */ val = 0; for (i = 0; i < NUM_CHANNELS ; i++) { range->freq[val].i = i + 1; range->freq[val].m = p80211wext_channel_freq[i] * 100000; range->freq[val].e = 1; val++; } range->num_frequency = val; /* Max of /proc/net/wireless */ range->max_qual.qual = 100; range->max_qual.level = 0; range->max_qual.noise = 0; range->sensitivity = 3; // XXX these need to be nsd-specific! range->min_rts = 0; range->max_rts = 2347; range->min_frag = 256; range->max_frag = 2346; range->max_encoding_tokens = NUM_WEPKEYS; range->num_encoding_sizes = 2; range->encoding_size[0] = 5; range->encoding_size[1] = 13; // XXX what about num_bitrates/throughput? range->num_bitrates = 0; /* estimated max throughput */ // XXX need to cap it if we're running at ~2Mbps.. range->throughput = 5500000; DBFEXIT; return 0; } #endif static int p80211wext_giwap(netdevice_t *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; DBFENTER; memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN); ap_addr->sa_family = ARPHRD_ETHER; DBFEXIT; return 0; } #if WIRELESS_EXT > 8 static int p80211wext_giwencode(netdevice_t *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; int err = 0; int i; DBFENTER; if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) erq->flags = IW_ENCODE_ENABLED; else erq->flags = IW_ENCODE_DISABLED; if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) erq->flags |= IW_ENCODE_RESTRICTED; else erq->flags |= IW_ENCODE_OPEN; i = (erq->flags & IW_ENCODE_INDEX) - 1; if (i == -1) i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; if ((i < 0) || (i >= NUM_WEPKEYS)) { err = -EINVAL; goto exit; } erq->flags |= i + 1; /* copy the key from the driver cache as the keys are read-only MIBs */ erq->length = wlandev->wep_keylens[i]; memcpy(key, wlandev->wep_keys[i], erq->length); exit: DBFEXIT; return err; } static int p80211wext_siwencode(netdevice_t *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211msg_dot11req_mibset_t msg; p80211item_pstr32_t pstr; int err = 0; int result = 0; int enable = 0; int i; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } /* Check the Key index first. */ if((i = (erq->flags & IW_ENCODE_INDEX))) { if ((i < 1) || (i > NUM_WEPKEYS)) { err = -EINVAL; goto exit; } else i--; result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, i); if (result) { err = -EFAULT; goto exit; } else { enable = 1; } } else { // Do not thing when no Key Index } /* Check if there is no key information in the iwconfig request */ if((erq->flags & IW_ENCODE_NOKEY) == 0 && enable == 1) { /*------------------------------------------------------------ * If there is WEP Key for setting, check the Key Information * and then set it to the firmware. -------------------------------------------------------------*/ if (erq->length > 0) { /* copy the key from the driver cache as the keys are read-only MIBs */ wlandev->wep_keylens[i] = erq->length; memcpy(wlandev->wep_keys[i], key, erq->length); /* Prepare data struture for p80211req_dorequest. */ memcpy(pstr.data.data, key, erq->length); pstr.data.len = erq->length; switch(i) { case 0: pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; break; case 1: pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; break; case 2: pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; break; case 3: pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; break; default: err = -EINVAL; goto exit; } msg.msgcode = DIDmsg_dot11req_mibset; memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } } } /* Check the PrivacyInvoked flag */ if (erq->flags & IW_ENCODE_DISABLED) { result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false); } else if((erq->flags & IW_ENCODE_ENABLED) || enable == 1) { result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true); } if (result) { err = -EFAULT; goto exit; } /* Check the ExcludeUnencrypted flag */ if (erq->flags & IW_ENCODE_RESTRICTED) { result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true); } else if (erq->flags & IW_ENCODE_OPEN) { result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false); } if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } static int p80211wext_giwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; DBFENTER; if (wlandev->ssid.len) { data->length = wlandev->ssid.len; data->flags = 1; memcpy(essid, wlandev->ssid.data, data->length); essid[data->length] = 0; #if (WIRELESS_EXT < 21) data->length++; #endif } else { memset(essid, 0, sizeof(wlandev->ssid.data)); data->length = 0; data->flags = 0; } DBFEXIT; return 0; } static int p80211wext_siwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211msg_lnxreq_autojoin_t msg; int result; int err = 0; int length = data->length; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } if ( wlandev->hostwep & HOSTWEP_SHAREDKEY ) msg.authtype.data = P80211ENUM_authalg_sharedkey; else msg.authtype.data = P80211ENUM_authalg_opensystem; msg.msgcode = DIDmsg_lnxreq_autojoin; #if (WIRELESS_EXT < 21) if (length) length--; #endif /* Trim the last '\0' to fit the SSID format */ if (length && essid[length-1] == '\0') { length--; } memcpy(msg.ssid.data.data, essid, length); msg.ssid.data.len = length; WLAN_LOG_DEBUG(1,"autojoin_ssid for %s \n",essid); result = p80211req_dorequest(wlandev, (UINT8*)&msg); WLAN_LOG_DEBUG(1,"autojoin_ssid %d\n",result); if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } static int p80211wext_siwcommit(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } /* Auto Join */ err = p80211wext_autojoin(wlandev); exit: DBFEXIT; return err; } static int p80211wext_giwrate(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); rrq->fixed = 0; /* can it change? */ rrq->disabled = 0; rrq->value = 0; #define HFA384x_RATEBIT_1 ((UINT16)1) #define HFA384x_RATEBIT_2 ((UINT16)2) #define HFA384x_RATEBIT_5dot5 ((UINT16)4) #define HFA384x_RATEBIT_11 ((UINT16)8) switch (mibitem.data) { case HFA384x_RATEBIT_1: rrq->value = 1000000; break; case HFA384x_RATEBIT_2: rrq->value = 2000000; break; case HFA384x_RATEBIT_5dot5: rrq->value = 5500000; break; case HFA384x_RATEBIT_11: rrq->value = 11000000; break; default: err = -EINVAL; } exit: DBFEXIT; return err; } static int p80211wext_giwrts(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); rts->value = mibitem.data; rts->disabled = (rts->value == 2347); rts->fixed = 1; exit: DBFEXIT; return err; } static int p80211wext_siwrts(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; if (rts->disabled) mibitem.data = 2347; else mibitem.data = rts->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } static int p80211wext_giwfrag(netdevice_t *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); frag->value = mibitem.data; frag->disabled = (frag->value == 2346); frag->fixed = 1; exit: DBFEXIT; return err; } static int p80211wext_siwfrag(netdevice_t *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } msg.msgcode = DIDmsg_dot11req_mibset; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; if (frag->disabled) mibitem.data = 2346; else mibitem.data = frag->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } #endif /* WIRELESS_EXT > 8 */ #if WIRELESS_EXT > 10 #ifndef IW_RETRY_LONG #define IW_RETRY_LONG IW_RETRY_MAX #endif #ifndef IW_RETRY_SHORT #define IW_RETRY_SHORT IW_RETRY_MIN #endif static int p80211wext_giwretry(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; UINT16 shortretry, longretry, lifetime; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); shortretry = mibitem.data; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); longretry = mibitem.data; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); lifetime = mibitem.data; rrq->disabled = 0; if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { rrq->flags = IW_RETRY_LIFETIME; rrq->value = lifetime * 1024; } else { if (rrq->flags & IW_RETRY_LONG) { rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; rrq->value = longretry; } else { rrq->flags = IW_RETRY_LIMIT; rrq->value = shortretry; if (shortretry != longretry) rrq->flags |= IW_RETRY_SHORT; } } exit: DBFEXIT; return err; } static int p80211wext_siwretry(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } if (rrq->disabled) { err = -EINVAL; goto exit; } msg.msgcode = DIDmsg_dot11req_mibset; if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; mibitem.data = rrq->value /= 1024; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } } else { if (rrq->flags & IW_RETRY_LONG) { mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; mibitem.data = rrq->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } } if (rrq->flags & IW_RETRY_SHORT) { mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; mibitem.data = rrq->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } } } exit: DBFEXIT; return err; } #endif /* WIRELESS_EXT > 10 */ #if WIRELESS_EXT > 9 static int p80211wext_siwtxpow(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; if (!wlan_wext_write) { err = (-EOPNOTSUPP); goto exit; } msg.msgcode = DIDmsg_dot11req_mibset; switch (rrq->value) { case 1 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1; break; case 2 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2; break; case 3 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3; break; case 4 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4; break; case 5 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5; break; case 6 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6; break; case 7 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7; break; case 8 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break; default: mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break; } memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } exit: DBFEXIT; return err; } static int p80211wext_giwtxpow(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; int err = 0; DBFENTER; msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) { err = -EFAULT; goto exit; } memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); // XXX handle OFF by setting disabled = 1; rrq->flags = 0; // IW_TXPOW_DBM; rrq->disabled = 0; rrq->fixed = 0; rrq->value = mibitem.data; exit: DBFEXIT; return err; } #endif /* WIRELESS_EXT > 9 */ static int p80211wext_siwspy(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; DBFENTER; /* Copy the data from the input buffer */ memcpy(address, extra, sizeof(struct sockaddr)*number); wlandev->spy_number = 0; if (number > 0) { /* extract the addresses */ for (i = 0; i < number; i++) { memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN); } /* reset stats */ memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY); /* set number of addresses */ wlandev->spy_number = number; } DBFEXIT; return 0; } /* jkriegl: from orinoco, modified */ static int p80211wext_giwspy(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; int number; int i; DBFENTER; number = wlandev->spy_number; if (number > 0) { /* populate address and spy struct's */ for (i = 0; i < number; i++) { memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN); address[i].sa_family = AF_UNIX; memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality)); } /* reset update flag */ for (i=0; i < number; i++) wlandev->spy_stat[i].updated = 0; } /* push stuff to user space */ srq->length = number; memcpy(extra, address, sizeof(struct sockaddr)*number); memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number); DBFEXIT; return 0; } static int prism2_result2err (int prism2_result) { int err = 0; switch (prism2_result) { case P80211ENUM_resultcode_invalid_parameters: err = -EINVAL; break; case P80211ENUM_resultcode_implementation_failure: err = -EIO; break; case P80211ENUM_resultcode_not_supported: err = -EOPNOTSUPP; break; default: err = 0; break; } return err; } #if WIRELESS_EXT > 13 static int p80211wext_siwscan(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211msg_dot11req_scan_t msg; int result; int err = 0; int i = 0; DBFENTER; if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { WLAN_LOG_ERROR("Can't scan in AP mode\n"); err = (-EOPNOTSUPP); goto exit; } memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t)); msg.msgcode = DIDmsg_dot11req_scan; msg.bsstype.data = P80211ENUM_bsstype_any; memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t)); msg.bssid.data.len = 6; msg.scantype.data = P80211ENUM_scantype_active; msg.probedelay.data = 0; for (i = 1; i <= 14; i++) msg.channellist.data.data[i-1] = i; msg.channellist.data.len = 14; msg.maxchanneltime.data = 250; msg.minchanneltime.data = 200; result = p80211req_dorequest(wlandev, (UINT8*)&msg); if (result) err = prism2_result2err (msg.resultcode.data); exit: DBFEXIT; return err; } /* Helper to translate scan into Wireless Extensions scan results. * Inspired by the prism54 code, which was in turn inspired by the * airo driver code. */ static char * wext_translate_bss(struct iw_request_info *info, char *current_ev, char *end_buf, p80211msg_dot11req_scan_results_t *bss) { struct iw_event iwe; /* Temporary buffer */ /* The first entry must be the MAC address */ memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN); iwe.u.ap_addr.sa_family = ARPHRD_ETHER; iwe.cmd = SIOCGIWAP; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* The following entries will be displayed in the same order we give them */ /* The ESSID. */ if (bss->ssid.data.len > 0) { char essid[IW_ESSID_MAX_SIZE + 1]; int size; size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len); memset(&essid, 0, sizeof (essid)); memcpy(&essid, bss->ssid.data.data, size); WLAN_LOG_DEBUG(1, " essid size = %d\n", size); iwe.u.data.length = size; iwe.u.data.flags = 1; iwe.cmd = SIOCGIWESSID; current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &essid[0]); WLAN_LOG_DEBUG(1, " essid size OK.\n"); } switch (bss->bsstype.data) { case P80211ENUM_bsstype_infrastructure: iwe.u.mode = IW_MODE_MASTER; break; case P80211ENUM_bsstype_independent: iwe.u.mode = IW_MODE_ADHOC; break; default: iwe.u.mode = 0; break; } iwe.cmd = SIOCGIWMODE; if (iwe.u.mode) current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); /* Encryption capability */ if (bss->privacy.data == P80211ENUM_truth_true) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; iwe.cmd = SIOCGIWENCODE; current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL); /* Add frequency. (short) bss->channel is the frequency in MHz */ iwe.u.freq.m = bss->dschannel.data; iwe.u.freq.e = 0; iwe.cmd = SIOCGIWFREQ; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.u.qual.level = bss->signal.data; iwe.u.qual.noise = bss->noise.data; /* do a simple SNR for quality */ iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data); iwe.cmd = IWEVQUAL; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); return current_ev; } static int p80211wext_giwscan(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; p80211msg_dot11req_scan_results_t msg; int result = 0; int err = 0; int i = 0; int scan_good = 0; char *current_ev = extra; DBFENTER; /* Since wireless tools doesn't really have a way of passing how * many scan results results there were back here, keep grabbing them * until we fail. */ do { memset(&msg, 0, sizeof(msg)); msg.msgcode = DIDmsg_dot11req_scan_results; msg.bssindex.data = i; result = p80211req_dorequest(wlandev, (UINT8*)&msg); if ((result != 0) || (msg.resultcode.data != P80211ENUM_resultcode_success)) { break; } current_ev = wext_translate_bss(info, current_ev, extra + IW_SCAN_MAX_DATA, &msg); scan_good = 1; i++; } while (i < IW_MAX_AP); srq->length = (current_ev - extra); srq->flags = 0; /* todo */ if (result && !scan_good) err = prism2_result2err (msg.resultcode.data); DBFEXIT; return err; } #endif /*****************************************************/ //extra wireless extensions stuff to support NetworkManager (I hope) #if WIRELESS_EXT > 17 /* SIOCSIWENCODEEXT */ static int p80211wext_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; p80211msg_dot11req_mibset_t msg; p80211item_pstr32_t *pstr; int result = 0; struct iw_point *encoding = &wrqu->encoding; int idx = encoding->flags & IW_ENCODE_INDEX; WLAN_LOG_DEBUG(1,"set_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len); if ( ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY ) { // set default key ? I'm not sure if this the the correct thing to do here if ( idx ) { if (idx < 1 || idx > NUM_WEPKEYS) { return -EINVAL; } else idx--; } WLAN_LOG_DEBUG(1,"setting default key (%d)\n",idx); result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, idx); if ( result ) return -EFAULT; } if ( ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) { if ( ! ext->alg & IW_ENCODE_ALG_WEP) { WLAN_LOG_DEBUG(1,"asked to set a non wep key :("); return -EINVAL; } if (idx) { if (idx <1 || idx > NUM_WEPKEYS) return -EINVAL; else idx--; } WLAN_LOG_DEBUG(1,"Set WEP key (%d)\n",idx); wlandev->wep_keylens[idx] = ext->key_len; memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len); memset( &msg,0,sizeof(msg)); pstr = (p80211item_pstr32_t*)&msg.mibattribute.data; memcpy(pstr->data.data, ext->key,ext->key_len); pstr->data.len = ext->key_len; switch (idx) { case 0: pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; break; case 1: pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; break; case 2: pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; break; case 3: pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; break; default: break; } msg.msgcode = DIDmsg_dot11req_mibset; result = p80211req_dorequest(wlandev,(UINT8*)&msg); WLAN_LOG_DEBUG(1,"result (%d)\n",result); } return result; } /* SIOCGIWENCODEEXT */ static int p80211wext_get_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct iw_point *encoding = &wrqu->encoding; int result = 0; int max_len; int idx; DBFENTER; WLAN_LOG_DEBUG(1,"get_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len); max_len = encoding->length - sizeof(*ext); if ( max_len <= 0) { WLAN_LOG_DEBUG(1,"get_encodeext max_len [%d] invalid\n",max_len); result = -EINVAL; goto exit; } idx = encoding->flags & IW_ENCODE_INDEX; WLAN_LOG_DEBUG(1,"get_encode_ext index [%d]\n",idx); if (idx) { if (idx < 1 || idx > NUM_WEPKEYS ) { WLAN_LOG_DEBUG(1,"get_encode_ext invalid key index [%d]\n",idx); result = -EINVAL; goto exit; } idx--; } else { /* default key ? not sure what to do */ /* will just use key[0] for now ! FIX ME */ } encoding->flags = idx + 1; memset(ext,0,sizeof(*ext)); ext->alg = IW_ENCODE_ALG_WEP; ext->key_len = wlandev->wep_keylens[idx]; memcpy( ext->key, wlandev->wep_keys[idx] , ext->key_len ); encoding->flags |= IW_ENCODE_ENABLED; exit: DBFEXIT; return result; } /* SIOCSIWAUTH */ static int p80211_wext_set_iwauth (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct iw_param *param = &wrqu->param; int result =0; WLAN_LOG_DEBUG(1,"set_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX ); switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_DROP_UNENCRYPTED: WLAN_LOG_DEBUG(1,"drop_unencrypted %d\n",param->value); if (param->value) result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true); else result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false); break; case IW_AUTH_PRIVACY_INVOKED: WLAN_LOG_DEBUG(1,"privacy invoked %d\n",param->value); if ( param->value) result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true); else result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false); break; case IW_AUTH_80211_AUTH_ALG: if ( param->value & IW_AUTH_ALG_OPEN_SYSTEM ) { WLAN_LOG_DEBUG(1,"set open_system\n"); wlandev->hostwep &= ~HOSTWEP_SHAREDKEY; } else if ( param->value & IW_AUTH_ALG_SHARED_KEY) { WLAN_LOG_DEBUG(1,"set shared key\n"); wlandev->hostwep |= HOSTWEP_SHAREDKEY; } else { /* don't know what to do know :( */ WLAN_LOG_DEBUG(1,"unknown AUTH_ALG (%d)\n",param->value); result = -EINVAL; } break; default: break; } return result; } /* SIOCSIWAUTH */ static int p80211_wext_get_iwauth (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; struct iw_param *param = &wrqu->param; int result =0; WLAN_LOG_DEBUG(1,"get_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX ); switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_DROP_UNENCRYPTED: param->value = wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED?1:0; break; case IW_AUTH_PRIVACY_INVOKED: param->value = wlandev->hostwep & HOSTWEP_PRIVACYINVOKED?1:0; break; case IW_AUTH_80211_AUTH_ALG: param->value = wlandev->hostwep & HOSTWEP_SHAREDKEY?IW_AUTH_ALG_SHARED_KEY:IW_AUTH_ALG_OPEN_SYSTEM; break; default: break; } return result; } #endif /*****************************************************/ /* typedef int (*iw_handler)(netdevice_t *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); */ #if WIRELESS_EXT > 12 static iw_handler p80211wext_handlers[] = { (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */ (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */ (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */ (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */ (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ (iw_handler) NULL, /* SIOCGIWSENS */ (iw_handler) NULL, /* not used */ /* SIOCSIWRANGE */ (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */ (iw_handler) NULL, /* not used */ /* SIOCSIWPRIV */ (iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */ (iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */ (iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */ (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */ (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWAP */ (iw_handler) p80211wext_giwap, /* SIOCGIWAP */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCGIWAPLIST */ #if WIRELESS_EXT > 13 (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */ #else /* WIRELESS_EXT > 13 */ (iw_handler) NULL, /* null */ /* SIOCSIWSCAN */ (iw_handler) NULL, /* null */ /* SIOCGIWSCAN */ #endif /* WIRELESS_EXT > 13 */ (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */ (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */ (iw_handler) NULL, /* SIOCSIWNICKN */ (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWRATE */ (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */ (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */ (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */ (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */ (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */ (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */ (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */ (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */ (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */ (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */ (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */ (iw_handler) NULL, /* SIOCSIWPOWER */ (iw_handler) NULL, /* SIOCGIWPOWER */ #if WIRELESS_EXT > 17 /* WPA operations */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */ (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */ (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */ (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */ (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */ (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */ (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */ #endif }; struct iw_handler_def p80211wext_handler_def = { .num_standard = sizeof(p80211wext_handlers) / sizeof(iw_handler), .num_private = 0, .num_private_args = 0, .standard = p80211wext_handlers, .private = NULL, .private_args = NULL, #if WIRELESS_EXT > 16 .get_wireless_stats = p80211wext_get_wireless_stats #endif }; #endif /* wireless extensions' ioctls */ int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; #if WIRELESS_EXT < 13 struct iwreq *iwr = (struct iwreq*)ifr; #endif p80211item_uint32_t mibitem; int err = 0; DBFENTER; mibitem.status = P80211ENUM_msgitem_status_data_ok; if ( wlandev->msdstate != WLAN_MSD_RUNNING ) { err = -ENODEV; goto exit; } WLAN_LOG_DEBUG(1, "Received wireless extension ioctl #%d.\n", cmd); switch (cmd) { #if WIRELESS_EXT < 13 case SIOCSIWNAME: /* unused */ err = (-EOPNOTSUPP); break; case SIOCGIWNAME: /* get name == wireless protocol */ err = p80211wext_giwname(dev, NULL, (char *) &iwr->u, NULL); break; case SIOCSIWNWID: case SIOCGIWNWID: err = (-EOPNOTSUPP); break; case SIOCSIWFREQ: /* set channel */ err = p80211wext_siwfreq(dev, NULL, &(iwr->u.freq), NULL); break; case SIOCGIWFREQ: /* get channel */ err = p80211wext_giwfreq(dev, NULL, &(iwr->u.freq), NULL); break; case SIOCSIWRANGE: case SIOCSIWPRIV: case SIOCSIWAP: /* set access point MAC addresses (BSSID) */ err = (-EOPNOTSUPP); break; case SIOCGIWAP: /* get access point MAC addresses (BSSID) */ err = p80211wext_giwap(dev, NULL, &(iwr->u.ap_addr), NULL); break; #if WIRELESS_EXT > 8 case SIOCSIWMODE: /* set operation mode */ case SIOCSIWESSID: /* set SSID (network name) */ case SIOCSIWRATE: /* set default bit rate (bps) */ err = (-EOPNOTSUPP); break; case SIOCGIWMODE: /* get operation mode */ err = p80211wext_giwmode(dev, NULL, &iwr->u.mode, NULL); break; case SIOCGIWNICKN: /* get node name/nickname */ case SIOCGIWESSID: /* get SSID */ if(iwr->u.essid.pointer) { char ssid[IW_ESSID_MAX_SIZE+1]; memset(ssid, 0, sizeof(ssid)); err = p80211wext_giwessid(dev, NULL, &iwr->u.essid, ssid); if(copy_to_user(iwr->u.essid.pointer, ssid, sizeof(ssid))) err = (-EFAULT); } break; case SIOCGIWRATE: err = p80211wext_giwrate(dev, NULL, &iwr->u.bitrate, NULL); break; case SIOCGIWRTS: err = p80211wext_giwrts(dev, NULL, &iwr->u.rts, NULL); break; case SIOCGIWFRAG: err = p80211wext_giwfrag(dev, NULL, &iwr->u.rts, NULL); break; case SIOCGIWENCODE: if (!capable(CAP_NET_ADMIN)) err = -EPERM; else if (iwr->u.encoding.pointer) { char keybuf[MAX_KEYLEN]; err = p80211wext_giwencode(dev, NULL, &iwr->u.encoding, keybuf); if (copy_to_user(iwr->u.encoding.pointer, keybuf, iwr->u.encoding.length)) err = -EFAULT; } break; case SIOCGIWAPLIST: case SIOCSIWRTS: case SIOCSIWFRAG: case SIOCSIWSENS: case SIOCGIWSENS: case SIOCSIWNICKN: /* set node name/nickname */ case SIOCSIWENCODE: /* set encoding token & mode */ case SIOCSIWSPY: case SIOCGIWSPY: case SIOCSIWPOWER: case SIOCGIWPOWER: case SIOCGIWPRIV: err = (-EOPNOTSUPP); break; case SIOCGIWRANGE: if(iwr->u.data.pointer != NULL) { struct iw_range range; err = p80211wext_giwrange(dev, NULL, &iwr->u.data, (char *) &range); /* Push that up to the caller */ if (copy_to_user(iwr->u.data.pointer, &range, sizeof(range))) err = -EFAULT; } break; #endif /* WIRELESS_EXT > 8 */ #if WIRELESS_EXT > 9 case SIOCSIWTXPOW: err = (-EOPNOTSUPP); break; case SIOCGIWTXPOW: err = p80211wext_giwtxpow(dev, NULL, &iwr->u.txpower, NULL); break; #endif /* WIRELESS_EXT > 9 */ #if WIRELESS_EXT > 10 case SIOCSIWRETRY: err = (-EOPNOTSUPP); break; case SIOCGIWRETRY: err = p80211wext_giwretry(dev, NULL, &iwr->u.retry, NULL); break; #endif /* WIRELESS_EXT > 10 */ #endif /* WIRELESS_EXT <= 12 */ default: err = (-EOPNOTSUPP); break; } exit: DBFEXIT; return (err); } int p80211wext_event_associated(wlandevice_t *wlandev, int assoc) { union iwreq_data data; DBFENTER; #if WIRELESS_EXT > 13 /* Send the association state first */ data.ap_addr.sa_family = ARPHRD_ETHER; if (assoc) { memcpy(data.ap_addr.sa_data, wlandev->bssid, WLAN_ADDR_LEN); } else { memset(data.ap_addr.sa_data, 0, WLAN_ADDR_LEN); } if (wlan_wext_write) wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL); if (!assoc) goto done; // XXX send association data, like IEs, etc etc. #endif done: DBFEXIT; return 0; } #endif /* compatibility to wireless extensions */