blob: 5acb8140ee5813920cc0ab8e36f20b3a1d2dd558 [file] [log] [blame]
Jiri Bencf0706e82007-05-05 11:45:53 -07001/*
2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/netdevice.h>
13#include <linux/types.h>
14#include <linux/slab.h>
15#include <linux/skbuff.h>
16#include <linux/etherdevice.h>
17#include <linux/if_arp.h>
18#include <linux/wireless.h>
19#include <net/iw_handler.h>
20#include <asm/uaccess.h>
21
22#include <net/mac80211.h>
23#include "ieee80211_i.h"
Johannes Berg2c8dccc2008-04-08 15:14:40 -040024#include "led.h"
25#include "rate.h"
Jiri Bencf0706e82007-05-05 11:45:53 -070026#include "wpa.h"
27#include "aes_ccm.h"
Jiri Bencf0706e82007-05-05 11:45:53 -070028
Johannes Bergb708e612007-09-14 11:10:25 -040029
Jiri Bencf0706e82007-05-05 11:45:53 -070030static int ieee80211_ioctl_siwfreq(struct net_device *dev,
31 struct iw_request_info *info,
32 struct iw_freq *freq, char *extra)
33{
Jiri Bencf0706e82007-05-05 11:45:53 -070034 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Johannes Berg7e9debe2009-06-15 13:42:25 +020035 struct ieee80211_local *local = sdata->local;
36 struct ieee80211_channel *chan;
Jiri Bencf0706e82007-05-05 11:45:53 -070037
Johannes Berg46900292009-02-15 12:44:28 +010038 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
Johannes Bergaf8cdcd2009-04-19 21:25:43 +020039 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
Johannes Berg46900292009-02-15 12:44:28 +010040 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
Johannes Bergf2129352009-07-01 21:26:56 +020041 return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
Jiri Bencf0706e82007-05-05 11:45:53 -070042
43 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
44 if (freq->e == 0) {
Johannes Bergf2129352009-07-01 21:26:56 +020045 if (freq->m < 0)
46 return -EINVAL;
47 else
Johannes Berg7e9debe2009-06-15 13:42:25 +020048 chan = ieee80211_get_channel(local->hw.wiphy,
Johannes Berg8318d782008-01-24 19:38:38 +010049 ieee80211_channel_to_frequency(freq->m));
Jiri Bencf0706e82007-05-05 11:45:53 -070050 } else {
51 int i, div = 1000000;
52 for (i = 0; i < freq->e; i++)
53 div /= 10;
Johannes Berg7e9debe2009-06-15 13:42:25 +020054 if (div <= 0)
Jiri Bencf0706e82007-05-05 11:45:53 -070055 return -EINVAL;
Johannes Berg7e9debe2009-06-15 13:42:25 +020056 chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div);
Jiri Bencf0706e82007-05-05 11:45:53 -070057 }
Johannes Berg7e9debe2009-06-15 13:42:25 +020058
59 if (!chan)
60 return -EINVAL;
61
62 if (chan->flags & IEEE80211_CHAN_DISABLED)
63 return -EINVAL;
64
65 /*
66 * no change except maybe auto -> fixed, ignore the HT
67 * setting so you can fix a channel you're on already
68 */
69 if (local->oper_channel == chan)
70 return 0;
71
Johannes Berg7e9debe2009-06-15 13:42:25 +020072 local->oper_channel = chan;
73 local->oper_channel_type = NL80211_CHAN_NO_HT;
74 ieee80211_hw_config(local, 0);
75
76 return 0;
Jiri Bencf0706e82007-05-05 11:45:53 -070077}
78
79
80static int ieee80211_ioctl_giwfreq(struct net_device *dev,
81 struct iw_request_info *info,
82 struct iw_freq *freq, char *extra)
83{
84 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
Johannes Bergaf8cdcd2009-04-19 21:25:43 +020085 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
86
87 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
88 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
Johannes Bergf2129352009-07-01 21:26:56 +020089 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
90 return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
Jiri Bencf0706e82007-05-05 11:45:53 -070091
Johannes Berg77382312009-05-04 17:52:10 +020092 freq->m = local->oper_channel->center_freq;
Jiri Bencf0706e82007-05-05 11:45:53 -070093 freq->e = 6;
94
95 return 0;
96}
97
98
99static int ieee80211_ioctl_siwessid(struct net_device *dev,
100 struct iw_request_info *info,
101 struct iw_point *data, char *ssid)
102{
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200103 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Jiri Bencf0706e82007-05-05 11:45:53 -0700104
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200105 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
106 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
Johannes Bergf2129352009-07-01 21:26:56 +0200107 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
108 return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
Jiri Bencf0706e82007-05-05 11:45:53 -0700109
Jiri Bencf0706e82007-05-05 11:45:53 -0700110 return -EOPNOTSUPP;
111}
112
113
114static int ieee80211_ioctl_giwessid(struct net_device *dev,
115 struct iw_request_info *info,
116 struct iw_point *data, char *ssid)
117{
Jiri Bencf0706e82007-05-05 11:45:53 -0700118 struct ieee80211_sub_if_data *sdata;
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200119
Jiri Bencf0706e82007-05-05 11:45:53 -0700120 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200121
122 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
123 return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
Johannes Bergf2129352009-07-01 21:26:56 +0200124 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
125 return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
Jiri Bencf0706e82007-05-05 11:45:53 -0700126
Jiri Bencf0706e82007-05-05 11:45:53 -0700127 return -EOPNOTSUPP;
128}
129
130
131static int ieee80211_ioctl_siwap(struct net_device *dev,
132 struct iw_request_info *info,
133 struct sockaddr *ap_addr, char *extra)
134{
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200135 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Jiri Bencf0706e82007-05-05 11:45:53 -0700136
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200137 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
138 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
139
Johannes Bergf2129352009-07-01 21:26:56 +0200140 if (sdata->vif.type == NL80211_IFTYPE_STATION)
141 return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
Johannes Berg7986cf92009-03-21 17:08:43 +0100142
Johannes Bergab737a42009-07-01 21:26:58 +0200143 if (sdata->vif.type == NL80211_IFTYPE_WDS)
144 return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
Jiri Bencf0706e82007-05-05 11:45:53 -0700145 return -EOPNOTSUPP;
146}
147
148
149static int ieee80211_ioctl_giwap(struct net_device *dev,
150 struct iw_request_info *info,
151 struct sockaddr *ap_addr, char *extra)
152{
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200153 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Jiri Bencf0706e82007-05-05 11:45:53 -0700154
Johannes Bergaf8cdcd2009-04-19 21:25:43 +0200155 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
156 return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
157
Johannes Bergf2129352009-07-01 21:26:56 +0200158 if (sdata->vif.type == NL80211_IFTYPE_STATION)
159 return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
160
Johannes Bergab737a42009-07-01 21:26:58 +0200161 if (sdata->vif.type == NL80211_IFTYPE_WDS)
162 return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
Jiri Bencf0706e82007-05-05 11:45:53 -0700163
164 return -EOPNOTSUPP;
165}
166
167
Jiri Bencf0706e82007-05-05 11:45:53 -0700168/* Structures to export the Wireless Handlers */
169
170static const iw_handler ieee80211_handler[] =
171{
172 (iw_handler) NULL, /* SIOCSIWCOMMIT */
Johannes Bergfee52672008-11-26 22:36:31 +0100173 (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
Jiri Bencf0706e82007-05-05 11:45:53 -0700174 (iw_handler) NULL, /* SIOCSIWNWID */
175 (iw_handler) NULL, /* SIOCGIWNWID */
176 (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
177 (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
Johannes Berge60c7742008-11-26 23:31:40 +0100178 (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
179 (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
Jiri Bencf0706e82007-05-05 11:45:53 -0700180 (iw_handler) NULL, /* SIOCSIWSENS */
181 (iw_handler) NULL, /* SIOCGIWSENS */
182 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
Johannes Berg4aa188e2009-02-18 19:32:08 +0100183 (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
Jiri Bencf0706e82007-05-05 11:45:53 -0700184 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
185 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
186 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
187 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
Johannes Berg5d4ecd92007-09-14 11:10:24 -0400188 (iw_handler) NULL, /* SIOCSIWSPY */
189 (iw_handler) NULL, /* SIOCGIWSPY */
190 (iw_handler) NULL, /* SIOCSIWTHRSPY */
191 (iw_handler) NULL, /* SIOCGIWTHRSPY */
Jiri Bencf0706e82007-05-05 11:45:53 -0700192 (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
193 (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
Johannes Berg691597c2009-04-19 19:57:45 +0200194 (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */
Jiri Bencf0706e82007-05-05 11:45:53 -0700195 (iw_handler) NULL, /* SIOCGIWAPLIST */
Johannes Berg2a519312009-02-10 21:25:55 +0100196 (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
197 (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
Jiri Bencf0706e82007-05-05 11:45:53 -0700198 (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
199 (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
200 (iw_handler) NULL, /* SIOCSIWNICKN */
201 (iw_handler) NULL, /* SIOCGIWNICKN */
202 (iw_handler) NULL, /* -- hole -- */
203 (iw_handler) NULL, /* -- hole -- */
Johannes Berg99303802009-07-01 21:26:59 +0200204 (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */
205 (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200206 (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
207 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
208 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
209 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
Johannes Berg7643a2c2009-06-02 13:01:39 +0200210 (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
211 (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200212 (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
213 (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
Johannes Berg08645122009-05-11 13:54:58 +0200214 (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
215 (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
Johannes Bergbc92afd2009-07-01 21:26:57 +0200216 (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
217 (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
Jiri Bencf0706e82007-05-05 11:45:53 -0700218 (iw_handler) NULL, /* -- hole -- */
219 (iw_handler) NULL, /* -- hole -- */
Johannes Bergf2129352009-07-01 21:26:56 +0200220 (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
Jiri Bencf0706e82007-05-05 11:45:53 -0700221 (iw_handler) NULL, /* SIOCGIWGENIE */
Johannes Bergf2129352009-07-01 21:26:56 +0200222 (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
223 (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
Johannes Berg08645122009-05-11 13:54:58 +0200224 (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
Jiri Bencf0706e82007-05-05 11:45:53 -0700225 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
226 (iw_handler) NULL, /* SIOCSIWPMKSA */
227 (iw_handler) NULL, /* -- hole -- */
228};
229
Jiri Bencf0706e82007-05-05 11:45:53 -0700230const struct iw_handler_def ieee80211_iw_handler_def =
231{
232 .num_standard = ARRAY_SIZE(ieee80211_handler),
Jiri Bencf0706e82007-05-05 11:45:53 -0700233 .standard = (iw_handler *) ieee80211_handler,
Johannes Berg89906462009-07-01 21:27:00 +0200234 .get_wireless_stats = cfg80211_wireless_stats,
Jiri Bencf0706e82007-05-05 11:45:53 -0700235};