• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/linux/linux-2.6/drivers/net/wireless/zd1211rw/
1/* 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{
75	strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
76	return 0;
77}
78
79static int iw_get_nick(struct net_device *netdev,
80	               struct iw_request_info *info,
81		       union iwreq_data *req, char *extra)
82{
83	strcpy(extra, "zd1211");
84	req->data.length = strlen(extra);
85	req->data.flags = 1;
86	return 0;
87}
88
89static int iw_set_freq(struct net_device *netdev,
90	               struct iw_request_info *info,
91		       union iwreq_data *req, char *extra)
92{
93	int r;
94	struct zd_mac *mac = zd_netdev_mac(netdev);
95	struct iw_freq *freq = &req->freq;
96	u8 channel;
97
98	r = zd_find_channel(&channel, freq);
99	if (r < 0)
100		return r;
101	r = zd_mac_request_channel(mac, channel);
102	return r;
103}
104
105static int iw_get_freq(struct net_device *netdev,
106	           struct iw_request_info *info,
107		   union iwreq_data *req, char *extra)
108{
109	struct zd_mac *mac = zd_netdev_mac(netdev);
110	struct iw_freq *freq = &req->freq;
111
112	return zd_channel_to_freq(freq, zd_mac_get_channel(mac));
113}
114
115static int iw_set_mode(struct net_device *netdev,
116	               struct iw_request_info *info,
117		       union iwreq_data *req, char *extra)
118{
119	return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
120}
121
122static int iw_get_mode(struct net_device *netdev,
123	               struct iw_request_info *info,
124		       union iwreq_data *req, char *extra)
125{
126	return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
127}
128
129static int iw_get_range(struct net_device *netdev,
130	               struct iw_request_info *info,
131		       union iwreq_data *req, char *extra)
132{
133	struct iw_range *range = (struct iw_range *)extra;
134
135	dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
136	req->data.length = sizeof(*range);
137	return zd_mac_get_range(zd_netdev_mac(netdev), range);
138}
139
140static int iw_set_encode(struct net_device *netdev,
141			 struct iw_request_info *info,
142			 union iwreq_data *data,
143			 char *extra)
144{
145	return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
146		data, extra);
147}
148
149static int iw_get_encode(struct net_device *netdev,
150			 struct iw_request_info *info,
151			 union iwreq_data *data,
152			 char *extra)
153{
154	return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
155		data, extra);
156}
157
158static int iw_set_encodeext(struct net_device *netdev,
159			 struct iw_request_info *info,
160			 union iwreq_data *data,
161			 char *extra)
162{
163	return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
164		data, extra);
165}
166
167static int iw_get_encodeext(struct net_device *netdev,
168			 struct iw_request_info *info,
169			 union iwreq_data *data,
170			 char *extra)
171{
172	return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
173		data, extra);
174}
175
176#define WX(x) [(x)-SIOCIWFIRST]
177
178static const iw_handler zd_standard_iw_handlers[] = {
179	WX(SIOCGIWNAME)		= iw_get_name,
180	WX(SIOCGIWNICKN)	= iw_get_nick,
181	WX(SIOCSIWFREQ)		= iw_set_freq,
182	WX(SIOCGIWFREQ)		= iw_get_freq,
183	WX(SIOCSIWMODE)		= iw_set_mode,
184	WX(SIOCGIWMODE)		= iw_get_mode,
185	WX(SIOCGIWRANGE)	= iw_get_range,
186	WX(SIOCSIWENCODE)	= iw_set_encode,
187	WX(SIOCGIWENCODE)	= iw_get_encode,
188	WX(SIOCSIWENCODEEXT)	= iw_set_encodeext,
189	WX(SIOCGIWENCODEEXT)	= iw_get_encodeext,
190	WX(SIOCSIWAUTH)		= ieee80211_wx_set_auth,
191	WX(SIOCGIWAUTH)		= ieee80211_wx_get_auth,
192	WX(SIOCSIWSCAN)		= ieee80211softmac_wx_trigger_scan,
193	WX(SIOCGIWSCAN)		= ieee80211softmac_wx_get_scan_results,
194	WX(SIOCSIWESSID)	= ieee80211softmac_wx_set_essid,
195	WX(SIOCGIWESSID)	= ieee80211softmac_wx_get_essid,
196	WX(SIOCSIWAP)		= ieee80211softmac_wx_set_wap,
197	WX(SIOCGIWAP)		= ieee80211softmac_wx_get_wap,
198	WX(SIOCSIWRATE)		= ieee80211softmac_wx_set_rate,
199	WX(SIOCGIWRATE)		= ieee80211softmac_wx_get_rate,
200	WX(SIOCSIWGENIE)	= ieee80211softmac_wx_set_genie,
201	WX(SIOCGIWGENIE)	= ieee80211softmac_wx_get_genie,
202	WX(SIOCSIWMLME)		= ieee80211softmac_wx_set_mlme,
203};
204
205static const struct iw_handler_def iw_handler_def = {
206	.standard		= zd_standard_iw_handlers,
207	.num_standard		= ARRAY_SIZE(zd_standard_iw_handlers),
208	.private		= zd_priv_handler,
209	.num_private		= ARRAY_SIZE(zd_priv_handler),
210	.private_args		= zd_priv_args,
211	.num_private_args	= ARRAY_SIZE(zd_priv_args),
212	.get_wireless_stats	= zd_mac_get_wireless_stats,
213};
214
215struct net_device *zd_netdev_alloc(struct usb_interface *intf)
216{
217	int r;
218	struct net_device *netdev;
219	struct zd_mac *mac;
220
221	netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
222	if (!netdev) {
223		dev_dbg_f(&intf->dev, "out of memory\n");
224		return NULL;
225	}
226
227	mac = zd_netdev_mac(netdev);
228	r = zd_mac_init(mac, netdev, intf);
229	if (r) {
230		usb_set_intfdata(intf, NULL);
231		free_ieee80211(netdev);
232		return NULL;
233	}
234
235	SET_MODULE_OWNER(netdev);
236	SET_NETDEV_DEV(netdev, &intf->dev);
237
238	dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
239	dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
240
241	netdev->open = zd_mac_open;
242	netdev->stop = zd_mac_stop;
243	/* netdev->get_stats = */
244	netdev->set_multicast_list = zd_mac_set_multicast_list;
245	netdev->set_mac_address = zd_mac_set_mac_address;
246	netdev->wireless_handlers = &iw_handler_def;
247	/* netdev->ethtool_ops = */
248
249	return netdev;
250}
251
252void zd_netdev_free(struct net_device *netdev)
253{
254	if (!netdev)
255		return;
256
257	zd_mac_clear(zd_netdev_mac(netdev));
258	free_ieee80211(netdev);
259}
260
261void zd_netdev_disconnect(struct net_device *netdev)
262{
263	unregister_netdev(netdev);
264}
265