| Johannes Berg | fee5267 | 2008-11-26 22:36:31 +0100 | [diff] [blame] | 1 | /* | 
|  | 2 | * cfg80211 - wext compat code | 
|  | 3 | * | 
|  | 4 | * This is temporary code until all wireless functionality is migrated | 
|  | 5 | * into cfg80211, when that happens all the exports here go away and | 
|  | 6 | * we directly assign the wireless handlers of wireless interfaces. | 
|  | 7 | * | 
|  | 8 | * Copyright 2008	Johannes Berg <johannes@sipsolutions.net> | 
|  | 9 | */ | 
|  | 10 |  | 
|  | 11 | #include <linux/wireless.h> | 
|  | 12 | #include <linux/nl80211.h> | 
|  | 13 | #include <net/iw_handler.h> | 
|  | 14 | #include <net/wireless.h> | 
|  | 15 | #include <net/cfg80211.h> | 
|  | 16 | #include "core.h" | 
|  | 17 |  | 
|  | 18 | int cfg80211_wext_giwname(struct net_device *dev, | 
|  | 19 | struct iw_request_info *info, | 
|  | 20 | char *name, char *extra) | 
|  | 21 | { | 
|  | 22 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 
|  | 23 | struct ieee80211_supported_band *sband; | 
|  | 24 | bool is_ht = false, is_a = false, is_b = false, is_g = false; | 
|  | 25 |  | 
|  | 26 | if (!wdev) | 
|  | 27 | return -EOPNOTSUPP; | 
|  | 28 |  | 
|  | 29 | sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; | 
|  | 30 | if (sband) { | 
|  | 31 | is_a = true; | 
|  | 32 | is_ht |= sband->ht_cap.ht_supported; | 
|  | 33 | } | 
|  | 34 |  | 
|  | 35 | sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; | 
|  | 36 | if (sband) { | 
|  | 37 | int i; | 
|  | 38 | /* Check for mandatory rates */ | 
|  | 39 | for (i = 0; i < sband->n_bitrates; i++) { | 
|  | 40 | if (sband->bitrates[i].bitrate == 10) | 
|  | 41 | is_b = true; | 
|  | 42 | if (sband->bitrates[i].bitrate == 60) | 
|  | 43 | is_g = true; | 
|  | 44 | } | 
|  | 45 | is_ht |= sband->ht_cap.ht_supported; | 
|  | 46 | } | 
|  | 47 |  | 
|  | 48 | strcpy(name, "IEEE 802.11"); | 
|  | 49 | if (is_a) | 
|  | 50 | strcat(name, "a"); | 
|  | 51 | if (is_b) | 
|  | 52 | strcat(name, "b"); | 
|  | 53 | if (is_g) | 
|  | 54 | strcat(name, "g"); | 
|  | 55 | if (is_ht) | 
|  | 56 | strcat(name, "n"); | 
|  | 57 |  | 
|  | 58 | return 0; | 
|  | 59 | } | 
|  | 60 | EXPORT_SYMBOL(cfg80211_wext_giwname); | 
| Johannes Berg | e60c774 | 2008-11-26 23:31:40 +0100 | [diff] [blame] | 61 |  | 
|  | 62 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | 
|  | 63 | u32 *mode, char *extra) | 
|  | 64 | { | 
|  | 65 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 
|  | 66 | struct cfg80211_registered_device *rdev; | 
|  | 67 | struct vif_params vifparams; | 
|  | 68 | enum nl80211_iftype type; | 
| Johannes Berg | ac7f9cf | 2009-03-21 17:07:59 +0100 | [diff] [blame] | 69 | int ret; | 
| Johannes Berg | e60c774 | 2008-11-26 23:31:40 +0100 | [diff] [blame] | 70 |  | 
|  | 71 | if (!wdev) | 
|  | 72 | return -EOPNOTSUPP; | 
|  | 73 |  | 
|  | 74 | rdev = wiphy_to_dev(wdev->wiphy); | 
|  | 75 |  | 
|  | 76 | if (!rdev->ops->change_virtual_intf) | 
|  | 77 | return -EOPNOTSUPP; | 
|  | 78 |  | 
|  | 79 | /* don't support changing VLANs, you just re-create them */ | 
|  | 80 | if (wdev->iftype == NL80211_IFTYPE_AP_VLAN) | 
|  | 81 | return -EOPNOTSUPP; | 
|  | 82 |  | 
|  | 83 | switch (*mode) { | 
|  | 84 | case IW_MODE_INFRA: | 
|  | 85 | type = NL80211_IFTYPE_STATION; | 
|  | 86 | break; | 
|  | 87 | case IW_MODE_ADHOC: | 
|  | 88 | type = NL80211_IFTYPE_ADHOC; | 
|  | 89 | break; | 
|  | 90 | case IW_MODE_REPEAT: | 
|  | 91 | type = NL80211_IFTYPE_WDS; | 
|  | 92 | break; | 
|  | 93 | case IW_MODE_MONITOR: | 
|  | 94 | type = NL80211_IFTYPE_MONITOR; | 
|  | 95 | break; | 
|  | 96 | default: | 
|  | 97 | return -EINVAL; | 
|  | 98 | } | 
|  | 99 |  | 
| Johannes Berg | ac7f9cf | 2009-03-21 17:07:59 +0100 | [diff] [blame] | 100 | if (type == wdev->iftype) | 
|  | 101 | return 0; | 
|  | 102 |  | 
| Johannes Berg | e60c774 | 2008-11-26 23:31:40 +0100 | [diff] [blame] | 103 | memset(&vifparams, 0, sizeof(vifparams)); | 
|  | 104 |  | 
| Johannes Berg | ac7f9cf | 2009-03-21 17:07:59 +0100 | [diff] [blame] | 105 | ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, | 
|  | 106 | NULL, &vifparams); | 
|  | 107 | WARN_ON(!ret && wdev->iftype != type); | 
|  | 108 |  | 
|  | 109 | return ret; | 
| Johannes Berg | e60c774 | 2008-11-26 23:31:40 +0100 | [diff] [blame] | 110 | } | 
|  | 111 | EXPORT_SYMBOL(cfg80211_wext_siwmode); | 
|  | 112 |  | 
|  | 113 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | 
|  | 114 | u32 *mode, char *extra) | 
|  | 115 | { | 
|  | 116 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 
|  | 117 |  | 
|  | 118 | if (!wdev) | 
|  | 119 | return -EOPNOTSUPP; | 
|  | 120 |  | 
|  | 121 | switch (wdev->iftype) { | 
|  | 122 | case NL80211_IFTYPE_AP: | 
|  | 123 | *mode = IW_MODE_MASTER; | 
|  | 124 | break; | 
|  | 125 | case NL80211_IFTYPE_STATION: | 
|  | 126 | *mode = IW_MODE_INFRA; | 
|  | 127 | break; | 
|  | 128 | case NL80211_IFTYPE_ADHOC: | 
|  | 129 | *mode = IW_MODE_ADHOC; | 
|  | 130 | break; | 
|  | 131 | case NL80211_IFTYPE_MONITOR: | 
|  | 132 | *mode = IW_MODE_MONITOR; | 
|  | 133 | break; | 
|  | 134 | case NL80211_IFTYPE_WDS: | 
|  | 135 | *mode = IW_MODE_REPEAT; | 
|  | 136 | break; | 
|  | 137 | case NL80211_IFTYPE_AP_VLAN: | 
|  | 138 | *mode = IW_MODE_SECOND;		/* FIXME */ | 
|  | 139 | break; | 
|  | 140 | default: | 
|  | 141 | *mode = IW_MODE_AUTO; | 
|  | 142 | break; | 
|  | 143 | } | 
|  | 144 | return 0; | 
|  | 145 | } | 
|  | 146 | EXPORT_SYMBOL(cfg80211_wext_giwmode); | 
| Johannes Berg | 4aa188e | 2009-02-18 19:32:08 +0100 | [diff] [blame] | 147 |  | 
|  | 148 |  | 
|  | 149 | int cfg80211_wext_giwrange(struct net_device *dev, | 
|  | 150 | struct iw_request_info *info, | 
|  | 151 | struct iw_point *data, char *extra) | 
|  | 152 | { | 
|  | 153 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 
|  | 154 | struct iw_range *range = (struct iw_range *) extra; | 
|  | 155 | enum ieee80211_band band; | 
|  | 156 | int c = 0; | 
|  | 157 |  | 
|  | 158 | if (!wdev) | 
|  | 159 | return -EOPNOTSUPP; | 
|  | 160 |  | 
|  | 161 | data->length = sizeof(struct iw_range); | 
|  | 162 | memset(range, 0, sizeof(struct iw_range)); | 
|  | 163 |  | 
|  | 164 | range->we_version_compiled = WIRELESS_EXT; | 
|  | 165 | range->we_version_source = 21; | 
|  | 166 | range->retry_capa = IW_RETRY_LIMIT; | 
|  | 167 | range->retry_flags = IW_RETRY_LIMIT; | 
|  | 168 | range->min_retry = 0; | 
|  | 169 | range->max_retry = 255; | 
|  | 170 | range->min_rts = 0; | 
|  | 171 | range->max_rts = 2347; | 
|  | 172 | range->min_frag = 256; | 
|  | 173 | range->max_frag = 2346; | 
|  | 174 |  | 
|  | 175 | range->encoding_size[0] = 5; | 
|  | 176 | range->encoding_size[1] = 13; | 
|  | 177 | range->num_encoding_sizes = 2; | 
|  | 178 | range->max_encoding_tokens = 4; | 
|  | 179 |  | 
|  | 180 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; | 
|  | 181 |  | 
|  | 182 | switch (wdev->wiphy->signal_type) { | 
|  | 183 | case CFG80211_SIGNAL_TYPE_NONE: | 
|  | 184 | break; | 
|  | 185 | case CFG80211_SIGNAL_TYPE_MBM: | 
|  | 186 | range->max_qual.level = -110; | 
|  | 187 | range->max_qual.qual = 70; | 
|  | 188 | range->avg_qual.qual = 35; | 
|  | 189 | range->max_qual.updated |= IW_QUAL_DBM; | 
|  | 190 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | 
|  | 191 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | 
|  | 192 | break; | 
|  | 193 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 
|  | 194 | range->max_qual.level = 100; | 
|  | 195 | range->max_qual.qual = 100; | 
|  | 196 | range->avg_qual.qual = 50; | 
|  | 197 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | 
|  | 198 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | 
|  | 199 | break; | 
|  | 200 | } | 
|  | 201 |  | 
|  | 202 | range->avg_qual.level = range->max_qual.level / 2; | 
|  | 203 | range->avg_qual.noise = range->max_qual.noise / 2; | 
|  | 204 | range->avg_qual.updated = range->max_qual.updated; | 
|  | 205 |  | 
|  | 206 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | 
|  | 207 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | 
|  | 208 |  | 
|  | 209 |  | 
|  | 210 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | 
|  | 211 | int i; | 
|  | 212 | struct ieee80211_supported_band *sband; | 
|  | 213 |  | 
|  | 214 | sband = wdev->wiphy->bands[band]; | 
|  | 215 |  | 
|  | 216 | if (!sband) | 
|  | 217 | continue; | 
|  | 218 |  | 
|  | 219 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | 
|  | 220 | struct ieee80211_channel *chan = &sband->channels[i]; | 
|  | 221 |  | 
|  | 222 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | 
|  | 223 | range->freq[c].i = | 
|  | 224 | ieee80211_frequency_to_channel( | 
|  | 225 | chan->center_freq); | 
|  | 226 | range->freq[c].m = chan->center_freq; | 
|  | 227 | range->freq[c].e = 6; | 
|  | 228 | c++; | 
|  | 229 | } | 
|  | 230 | } | 
|  | 231 | } | 
|  | 232 | range->num_channels = c; | 
|  | 233 | range->num_frequency = c; | 
|  | 234 |  | 
|  | 235 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | 
|  | 236 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | 
|  | 237 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | 
|  | 238 |  | 
|  | 239 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | 
|  | 240 |  | 
|  | 241 | return 0; | 
|  | 242 | } | 
|  | 243 | EXPORT_SYMBOL(cfg80211_wext_giwrange); |