blob: 440ef24b5fd10a445c525093bf799a65c6d348c4 [file] [log] [blame]
Daniel Drakee85d0912006-06-02 17:11:32 +01001/* zd_netdev.c
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18#include <linux/netdevice.h>
19#include <linux/etherdevice.h>
20#include <linux/skbuff.h>
21#include <net/ieee80211.h>
22#include <net/ieee80211softmac.h>
23#include <net/ieee80211softmac_wx.h>
24#include <net/iw_handler.h>
25
26#include "zd_def.h"
27#include "zd_netdev.h"
28#include "zd_mac.h"
29#include "zd_ieee80211.h"
30
31/* Region 0 means reset regdomain to default. */
32static int zd_set_regdomain(struct net_device *netdev,
33 struct iw_request_info *info,
34 union iwreq_data *req, char *extra)
35{
36 const u8 *regdomain = (u8 *)req;
37 return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
38}
39
40static int zd_get_regdomain(struct net_device *netdev,
41 struct iw_request_info *info,
42 union iwreq_data *req, char *extra)
43{
44 u8 *regdomain = (u8 *)req;
45 if (!regdomain)
46 return -EINVAL;
47 *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
48 return 0;
49}
50
51static const struct iw_priv_args zd_priv_args[] = {
52 {
53 .cmd = ZD_PRIV_SET_REGDOMAIN,
54 .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
55 .name = "set_regdomain",
56 },
57 {
58 .cmd = ZD_PRIV_GET_REGDOMAIN,
59 .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
60 .name = "get_regdomain",
61 },
62};
63
64#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
65
66static const iw_handler zd_priv_handler[] = {
67 PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
68 PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
69};
70
71static int iw_get_name(struct net_device *netdev,
72 struct iw_request_info *info,
73 union iwreq_data *req, char *extra)
74{
Daniel Drake089f99d2006-07-13 17:56:16 +010075 /* FIXME: check whether 802.11a will also supported */
76 strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
77 return 0;
78}
79
80static int iw_get_nick(struct net_device *netdev,
81 struct iw_request_info *info,
82 union iwreq_data *req, char *extra)
83{
84 strcpy(extra, "zd1211");
85 req->data.length = strlen(extra) + 1;
86 req->data.flags = 1;
Daniel Drakee85d0912006-06-02 17:11:32 +010087 return 0;
88}
89
90static int iw_set_freq(struct net_device *netdev,
91 struct iw_request_info *info,
92 union iwreq_data *req, char *extra)
93{
94 int r;
95 struct zd_mac *mac = zd_netdev_mac(netdev);
96 struct iw_freq *freq = &req->freq;
97 u8 channel;
98
99 r = zd_find_channel(&channel, freq);
100 if (r < 0)
101 return r;
102 r = zd_mac_request_channel(mac, channel);
103 return r;
104}
105
106static int iw_get_freq(struct net_device *netdev,
107 struct iw_request_info *info,
108 union iwreq_data *req, char *extra)
109{
110 int r;
111 struct zd_mac *mac = zd_netdev_mac(netdev);
112 struct iw_freq *freq = &req->freq;
113 u8 channel;
114 u8 flags;
115
116 r = zd_mac_get_channel(mac, &channel, &flags);
117 if (r)
118 return r;
119
120 freq->flags = (flags & MAC_FIXED_CHANNEL) ?
121 IW_FREQ_FIXED : IW_FREQ_AUTO;
122 dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
123 (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
124 return zd_channel_to_freq(freq, channel);
125}
126
127static int iw_set_mode(struct net_device *netdev,
128 struct iw_request_info *info,
129 union iwreq_data *req, char *extra)
130{
131 return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
132}
133
134static int iw_get_mode(struct net_device *netdev,
135 struct iw_request_info *info,
136 union iwreq_data *req, char *extra)
137{
138 return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
139}
140
141static int iw_get_range(struct net_device *netdev,
142 struct iw_request_info *info,
143 union iwreq_data *req, char *extra)
144{
145 struct iw_range *range = (struct iw_range *)extra;
146
147 dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
148 req->data.length = sizeof(*range);
149 return zd_mac_get_range(zd_netdev_mac(netdev), range);
150}
151
152static int iw_set_encode(struct net_device *netdev,
153 struct iw_request_info *info,
154 union iwreq_data *data,
155 char *extra)
156{
157 return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
158 data, extra);
159}
160
161static int iw_get_encode(struct net_device *netdev,
162 struct iw_request_info *info,
163 union iwreq_data *data,
164 char *extra)
165{
166 return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
167 data, extra);
168}
169
170static int iw_set_encodeext(struct net_device *netdev,
171 struct iw_request_info *info,
172 union iwreq_data *data,
173 char *extra)
174{
175 return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
176 data, extra);
177}
178
179static int iw_get_encodeext(struct net_device *netdev,
180 struct iw_request_info *info,
181 union iwreq_data *data,
182 char *extra)
183{
184 return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
185 data, extra);
186}
187
188#define WX(x) [(x)-SIOCIWFIRST]
189
190static const iw_handler zd_standard_iw_handlers[] = {
191 WX(SIOCGIWNAME) = iw_get_name,
Daniel Drake089f99d2006-07-13 17:56:16 +0100192 WX(SIOCGIWNICKN) = iw_get_nick,
Daniel Drakee85d0912006-06-02 17:11:32 +0100193 WX(SIOCSIWFREQ) = iw_set_freq,
194 WX(SIOCGIWFREQ) = iw_get_freq,
195 WX(SIOCSIWMODE) = iw_set_mode,
196 WX(SIOCGIWMODE) = iw_get_mode,
197 WX(SIOCGIWRANGE) = iw_get_range,
198 WX(SIOCSIWENCODE) = iw_set_encode,
199 WX(SIOCGIWENCODE) = iw_get_encode,
200 WX(SIOCSIWENCODEEXT) = iw_set_encodeext,
201 WX(SIOCGIWENCODEEXT) = iw_get_encodeext,
202 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
203 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
204 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
205 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
206 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
207 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
208 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
209 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
210 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
211 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
212 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
213 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
214 WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme,
215};
216
217static const struct iw_handler_def iw_handler_def = {
218 .standard = zd_standard_iw_handlers,
219 .num_standard = ARRAY_SIZE(zd_standard_iw_handlers),
220 .private = zd_priv_handler,
221 .num_private = ARRAY_SIZE(zd_priv_handler),
222 .private_args = zd_priv_args,
223 .num_private_args = ARRAY_SIZE(zd_priv_args),
224 .get_wireless_stats = zd_mac_get_wireless_stats,
225};
226
227struct net_device *zd_netdev_alloc(struct usb_interface *intf)
228{
229 int r;
230 struct net_device *netdev;
231 struct zd_mac *mac;
232
233 netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
234 if (!netdev) {
235 dev_dbg_f(&intf->dev, "out of memory\n");
236 return NULL;
237 }
238
239 mac = zd_netdev_mac(netdev);
240 r = zd_mac_init(mac, netdev, intf);
241 if (r) {
242 usb_set_intfdata(intf, NULL);
243 free_ieee80211(netdev);
244 return NULL;
245 }
246
247 SET_MODULE_OWNER(netdev);
248 SET_NETDEV_DEV(netdev, &intf->dev);
249
250 dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
251 dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
252
253 netdev->open = zd_mac_open;
254 netdev->stop = zd_mac_stop;
255 /* netdev->get_stats = */
256 /* netdev->set_multicast_list = */
257 netdev->set_mac_address = zd_mac_set_mac_address;
258 netdev->wireless_handlers = &iw_handler_def;
259 /* netdev->ethtool_ops = */
260
261 return netdev;
262}
263
264void zd_netdev_free(struct net_device *netdev)
265{
266 if (!netdev)
267 return;
268
269 zd_mac_clear(zd_netdev_mac(netdev));
270 free_ieee80211(netdev);
271}
272
273void zd_netdev_disconnect(struct net_device *netdev)
274{
275 unregister_netdev(netdev);
276}