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