lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 01 Jun 2007 12:39:56 -0400
From:	Dan Williams <dcbw@...hat.com>
To:	MOKUNO Masakazu <mokuno@...sony.co.jp>
Cc:	netdev@...r.kernel.org, Geoff Levand <geoffrey.levand@...sony.com>,
	Geert Uytterhoeven <Geert.Uytterhoeven@...ycom.com>
Subject: Re: [PATCH 2/2] ps3: add wireless LAN support

On Fri, 2007-06-01 at 15:10 +0900, MOKUNO Masakazu wrote:
> Add support of the internal wireless LAN of PS3.

Also, any further patches you send should be sent to:

linux-wireless@...r.kernel.org

which is the list for wireless stuff.

Dan

> Signed-off-by: Masakazu Mokuno <mokuno@...sony.co.jp>
> ---
>  drivers/net/Kconfig          |    7 
>  drivers/net/Makefile         |    4 
>  drivers/net/gelic_net.c      |   30 
>  drivers/net/gelic_net.h      |  227 ++++
>  drivers/net/gelic_wireless.c | 2132 +++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 2396 insertions(+), 4 deletions(-)
> 
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2274,6 +2274,13 @@ config GELIC_NET
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called gelic_net.
>  
> +config GELIC_WIRELESS
> +	bool "Gelic net Wireless Extension"
> +	depends on GELIC_NET
> +	select WIRELESS_EXT
> +	help
> +	  Wireless Extension support for Gelic Gigabit Ethernet driver
> +
>  config GIANFAR
>  	tristate "Gianfar Ethernet"
>  	depends on 85xx || 83xx || PPC_86xx
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -60,7 +60,9 @@ obj-$(CONFIG_TIGON3) += tg3.o
>  obj-$(CONFIG_BNX2) += bnx2.o
>  spidernet-y += spider_net.o spider_net_ethtool.o
>  obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
> -obj-$(CONFIG_GELIC_NET) += gelic_net.o
> +obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
> +gelic-$(CONFIG_GELIC_WIRELESS) += gelic_wireless.o
> +ps3_gelic-objs += gelic_net.o $(gelic-y)
>  obj-$(CONFIG_TC35815) += tc35815.o
>  obj-$(CONFIG_SKGE) += skge.o
>  obj-$(CONFIG_SKY2) += sky2.o
> --- a/drivers/net/gelic_net.c
> +++ b/drivers/net/gelic_net.c
> @@ -550,6 +550,9 @@ static int gelic_net_stop(struct net_dev
>  {
>  	struct gelic_net_card *card = netdev_priv(netdev);
>  
> +#ifdef CONFIG_GELIC_WIRELESS
> +	gelicw_down(netdev);
> +#endif
>  	netif_poll_disable(netdev);
>  	netif_stop_queue(netdev);
>  
> @@ -1024,6 +1027,9 @@ static irqreturn_t gelic_net_interrupt(i
>  		/* start pending DMA */
>  		gelic_net_xmit(NULL, netdev);
>  	}
> +#ifdef CONFIG_GELIC_WIRELESS
> +	gelicw_interrupt(netdev, status);
> +#endif
>  	return IRQ_HANDLED;
>  }
>  
> @@ -1120,13 +1126,18 @@ static int gelic_net_open(struct net_dev
>  
>  	card->tx_dma_progress = 0;
>  	card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT;
> -
> +#ifdef CONFIG_GELIC_WIRELESS
> +	card->ghiintmask |= GELICW_DEVICE_CMD_COMP | GELICW_DEVICE_EVENT_RECV;
> +#endif
>  	gelic_net_set_irq_mask(card, card->ghiintmask);
>  	gelic_net_enable_rxdmac(card);
>  
>  	netif_start_queue(netdev);
>  	netif_carrier_on(netdev);
>  	netif_poll_enable(netdev);
> +#ifdef CONFIG_GELIC_WIRELESS
> +	gelicw_up(netdev);
> +#endif
>  
>  	return 0;
>  
> @@ -1205,7 +1216,12 @@ static u32 gelic_net_get_link(struct net
>  		link = 1;
>  	else
>  		link = 0;
> -
> +#ifdef CONFIG_GELIC_WIRELESS
> +	/* (v1 & GELIC_NET_LINK_UP) is always 0 in wireless mode */
> +	if (gelicw_is_associated(netdev)) {
> +		link = 1;
> +	}
> +#endif
>  	return link;
>  }
>  
> @@ -1396,7 +1412,12 @@ static int gelic_net_setup_netdev(struct
>  	}
>  	if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1])
>  		card->vlan_index = GELIC_NET_VLAN_WIRED - 1;
> -
> +#ifdef CONFIG_GELIC_WIRELESS
> +	card->w.card = card;
> +	/* init wireless extension */
> +	/* No wireless vlan_index:-1 */
> +	gelicw_setup_netdev(netdev, card->vlan_index);
> +#endif
>  	status = register_netdev(netdev);
>  	if (status) {
>  		dev_err(ctodev(card), "%s:Couldn't register net_device: %d\n",
> @@ -1530,6 +1551,9 @@ static int ps3_gelic_driver_remove (stru
>  
>  	card = ps3_system_bus_get_driver_data(dev);
>  
> +#ifdef CONFIG_GELIC_WIRELESS
> +	gelicw_remove(card->netdev);
> +#endif
>  	wait_event(card->waitq,
>  		   atomic_read(&card->tx_timeout_task_counter) == 0);
>  
> --- a/drivers/net/gelic_net.h
> +++ b/drivers/net/gelic_net.h
> @@ -30,6 +30,9 @@
>  #ifndef _GELIC_NET_H
>  #define _GELIC_NET_H
>  
> +#include <linux/wireless.h>
> +#include <net/ieee80211.h>
> +
>  #define GELIC_NET_DRV_NAME "Gelic Network Driver"
>  #define GELIC_NET_DRV_VERSION "1.0"
>  
> @@ -170,6 +173,220 @@ enum gelic_net_descr_status {
>  
>  #define GELIC_NET_PORT                          2 /* for port status */
>  
> +/* wireless */
> +#define GELICW_WIRELESS_NOT_EXIST	0
> +#define GELICW_WIRELESS_SUPPORTED	1
> +#define GELICW_WIRELESS_ON		2
> +#define GELICW_WIRELESS_SHUTDOWN	3
> +/* state */
> +#define GELICW_STATE_DOWN		0
> +#define GELICW_STATE_UP			1
> +#define GELICW_STATE_SCANNING		2
> +#define GELICW_STATE_SCAN_DONE		3
> +#define GELICW_STATE_ASSOCIATED		4
> +
> +/* cmd_send_flg */
> +#define GELICW_CMD_SEND_NONE		0x00
> +#define GELICW_CMD_SEND_COMMON		0x01
> +#define GELICW_CMD_SEND_ENCODE		0x02
> +#define GELICW_CMD_SEND_SCAN		0x04
> +#define GELICW_CMD_SEND_ALL		(GELICW_CMD_SEND_COMMON \
> +					| GELICW_CMD_SEND_ENCODE \
> +					| GELICW_CMD_SEND_SCAN)
> +
> +#define GELICW_SCAN_INTERVAL		(HZ)
> +
> +#ifdef DEBUG
> +#define CH_INFO_FAIL 0x0600 /* debug */
> +#else
> +#define CH_INFO_FAIL 0
> +#endif
> +
> +
> +/* net_control command */
> +#define GELICW_SET_PORT			3 /* control Ether port */
> +#define GELICW_GET_INFO			6 /* get supported channels */
> +#define GELICW_SET_CMD			9 /* set configuration */
> +#define GELICW_GET_RES			10 /* get command response */
> +#define GELICW_GET_EVENT		11 /* get event from device */
> +/* net_control command data buffer */
> +#define GELICW_DATA_BUF_SIZE		0x1000
> +
> +/* GELICW_SET_CMD params */
> +#define GELICW_CMD_START		1
> +#define GELICW_CMD_STOP			2
> +#define GELICW_CMD_SCAN			3
> +#define GELICW_CMD_GET_SCAN		4
> +#define GELICW_CMD_SET_CONFIG		5
> +#define GELICW_CMD_GET_CONFIG		6
> +#define GELICW_CMD_SET_WEP		7
> +#define GELICW_CMD_GET_WEP		8
> +#define GELICW_CMD_SET_WPA		9
> +#define GELICW_CMD_GET_WPA		10
> +#define GELICW_CMD_GET_RSSI		11
> +
> +/* GELICW_SET_PORT params */
> +#define GELICW_ETHER_PORT		2
> +#define GELICW_PORT_DOWN		0 /* Ether port off */
> +#define GELICW_PORT_UP			4 /* Ether port on (auto neg) */
> +
> +/* interrupt status bit */
> +#define GELICW_DEVICE_CMD_COMP		(1UL << 31)
> +#define GELICW_DEVICE_EVENT_RECV	(1UL << 30)
> +
> +/* GELICW_GET_EVENT ID */
> +#define GELICW_EVENT_UNKNOWN		0x00
> +#define GELICW_EVENT_DEVICE_READY	0x01
> +#define GELICW_EVENT_SCAN_COMPLETED	0x02
> +#define GELICW_EVENT_DEAUTH		0x04
> +#define GELICW_EVENT_BEACON_LOST	0x08
> +#define GELICW_EVENT_CONNECTED		0x10
> +#define GELICW_EVENT_WPA_CONNECTED	0x20
> +#define GELICW_EVENT_WPA_ERROR		0x40
> +#define GELICW_EVENT_NO_ENTRY		(-6)
> +
> +#define MAX_IW_PRIV_SIZE		32
> +
> +/* structure of data buffer for lv1_net_contol */
> +/* wep_config: sec */
> +#define GELICW_WEP_SEC_NONE		0
> +#define GELICW_WEP_SEC_40BIT		1
> +#define GELICW_WEP_SEC_104BIT		2
> +struct wep_config {
> +	u16 sec;
> +	u8  key[4][16];
> +} __attribute__ ((packed));
> +
> +/* wpa_config: sec */
> +#define GELICW_WPA_SEC_NONE		0
> +#define GELICW_WPA_SEC_TKIP		1
> +#define GELICW_WPA_SEC_AES		2
> +/* wpa_config: psk_type */
> +#define GELICW_PSK_PASSPHRASE		0
> +#define GELICW_PSK_64HEX		1
> +struct wpa_config {
> +	u16 sec;
> +	u16 psk_type;
> +	u8  psk_material[64]; /* key */
> +} __attribute__ ((packed));
> +
> +/* common_config: bss_type */
> +#define GELICW_BSS_INFRA		0
> +#define GELICW_BSS_ADHOC		1
> +/* common_config: auth_method */
> +#define GELICW_AUTH_OPEN		0
> +#define GELICW_AUTH_SHARED		1
> +/* common_config: op_mode */
> +#define GELICW_OP_MODE_11BG		0
> +#define GELICW_OP_MODE_11B		1
> +#define GELICW_OP_MODE_11G		2
> +struct common_config {
> +	u16 scan_index; /* index of scan_desc list */
> +	u16 bss_type;
> +	u16 auth_method;
> +	u16 op_mode;
> +} __attribute__ ((packed));
> +
> +/* scan_descriptor: security */
> +#define GELICW_SEC_TYPE_NONE		0x0000
> +#define GELICW_SEC_TYPE_WEP		0x0100
> +#define GELICW_SEC_TYPE_WEP40		0x0101
> +#define GELICW_SEC_TYPE_WEP104		0x0102
> +#define GELICW_SEC_TYPE_TKIP		0x0201
> +#define GELICW_SEC_TYPE_AES		0x0202
> +#define GELICW_SEC_TYPE_WEP_MASK	0xFF00
> +struct scan_desc {
> +	u16 size;
> +	u16 rssi;
> +	u16 channel;
> +	u16 beacon_period;
> +	u16 capability;
> +	u16 security;
> +	u64 bssid;
> +	u8  essid[32];
> +	u8  rate[16];
> +	u8  ext_rate[16];
> +	u32 reserved1;
> +	u32 reserved2;
> +	u32 reserved3;
> +	u32 reserved4;
> +} __attribute__ ((packed));
> +
> +/* rssi_descriptor */
> +struct rssi_desc {
> +	u16 rssi; /* max rssi = 100 */
> +} __attribute__ ((packed));
> +
> +
> +struct gelicw_bss {
> +	u8 bssid[ETH_ALEN];
> +	u8 channel;
> +	u8 mode;
> +	u8 essid_len;
> +	u8 essid[IW_ESSID_MAX_SIZE + 1]; /* null terminated for debug msg */
> +
> +	u16 capability;
> +	u16 beacon_interval;
> +
> +	u8 rates_len;
> +	u8 rates[MAX_RATES_LENGTH];
> +	u8 rates_ex_len;
> +	u8 rates_ex[MAX_RATES_EX_LENGTH];
> +	u8 rssi;
> +
> +	/* scan results have sec_info instead of rsn_ie or wpa_ie */
> +	u16 sec_info;
> +};
> +
> +/* max station count of station list which hvc returns */
> +#define MAX_SCAN_BSS	(16)
> +
> +struct gelic_wireless {
> +	struct gelic_net_card *card;
> +	struct completion cmd_done, rssi_done;
> +	struct work_struct work_event, work_start_done;
> +	struct delayed_work work_rssi, work_scan_all, work_scan_essid;
> +	struct delayed_work work_common, work_encode;
> +	struct delayed_work work_start, work_stop, work_roam;
> +	wait_queue_head_t waitq_cmd, waitq_scan;
> +
> +	u64 cmd_tag, cmd_id;
> +	u8 cmd_send_flg;
> +
> +	struct iw_public_data wireless_data;
> +	u8 *data_buf; /* data buffer for lv1_net_control */
> +
> +	u8 wireless; /* wireless support */
> +	u8 state;
> +	u8 scan_all; /* essid scan or all scan */
> +	u8 essid_search; /* essid background scan */
> +	u8 is_assoc;
> +
> +	u16 ch_info; /* supoprted channels */
> +	u8 wireless_mode; /* 11b/g */
> +	u8 channel; /* current ch */
> +	u8 iw_mode; /* INFRA or Ad-hoc */
> +	u8 rssi;
> +	u8 essid_len;
> +	u8 essid[IW_ESSID_MAX_SIZE + 1]; /* null terminated for debug msg */
> +	u8 nick[IW_ESSID_MAX_SIZE + 1];
> +	u8 bssid[ETH_ALEN];
> +
> +	u8 key_index;
> +	u8 key[WEP_KEYS][IW_ENCODING_TOKEN_MAX]; /* 4 * 64byte */
> +	u8 key_len[WEP_KEYS];
> +	u8 key_alg; /* key algorithm  */
> +	u8 auth_mode; /* authenticaton mode */
> +
> +	u8 bss_index; /* current bss in bss_list */
> +	u8 num_bss_list;
> +	u8 bss_key_alg; /* key alg of bss */
> +	u8 wap_bssid[ETH_ALEN];
> +	unsigned long last_scan; /* last scan time */
> +	struct gelicw_bss current_bss;
> +	struct gelicw_bss bss_list[MAX_SCAN_BSS];
> +};
> +
>  /* size of hardware part of gelic descriptor */
>  #define GELIC_NET_DESCR_SIZE	(32)
>  struct gelic_net_descr {
> @@ -225,9 +442,19 @@ struct gelic_net_card {
>  	wait_queue_head_t waitq;
>  
>  	struct gelic_net_descr *tx_top, *rx_top;
> +#ifdef CONFIG_GELIC_WIRELESS
> +	struct gelic_wireless w;
> +#endif
>  	struct gelic_net_descr descr[0];
>  };
>  
> 
>  extern unsigned long p_to_lp(long pa);
> +extern int gelicw_setup_netdev(struct net_device *netdev, int wi);
> +extern void gelicw_up(struct net_device *netdev);
> +extern int gelicw_down(struct net_device *netdev);
> +extern void gelicw_remove(struct net_device *netdev);
> +extern void gelicw_interrupt(struct net_device *netdev, u64 status);
> +extern int gelicw_is_associated(struct net_device *netdev);
> +
>  #endif //_GELIC_NET_H
> --- /dev/null
> +++ b/drivers/net/gelic_wireless.c
> @@ -0,0 +1,2132 @@
> +/*
> + * gelic_wireless.c: wireless extension for gelic_net
> + *
> + * Copyright (C) 2007 Sony Computer Entertainment Inc.
> + * Copyright 2007 Sony Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published
> + * by the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#undef DEBUG
> +
> +#include <linux/kernel.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_vlan.h>
> +#include <linux/completion.h>
> +#include <linux/ctype.h>
> +#include <asm/ps3.h>
> +#include <asm/lv1call.h>
> +
> +#include "gelic_net.h"
> +
> +static struct iw_handler_def gelicw_handler_def;
> +
> +/*
> + * Data tables
> + */
> +static const u32 freq_list[] = {
> +	2412, 2417, 2422, 2427, 2432,
> +	2437, 2442, 2447, 2452, 2457,
> +	2462, 2467, 2472, 2484 };
> +
> +static const u32 bitrate_list[] = {
> +	 1000000,  2000000,  5500000, 11000000, /* 11b */
> +	 6000000,  9000000, 12000000, 18000000,
> +	24000000, 36000000, 48000000, 54000000
> +};
> +#define GELICW_NUM_11B_BITRATES 4 /* 802.11b: 1 ~ 11 Mb/s */
> +
> +static inline struct device * ntodev(struct net_device *netdev)
> +{
> +	return &((struct gelic_net_card *)netdev_priv(netdev))->dev->core;
> +}
> +
> +static inline struct device * wtodev(struct gelic_wireless *w)
> +{
> +	return &w->card->dev->core;
> +}
> +static inline struct gelic_wireless *gelicw_priv(struct net_device *netdev)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +	return &card->w;
> +}
> +static inline unsigned int bus_id(struct gelic_wireless *w)
> +{
> +	return w->card->dev->did.bus_id;
> +}
> +static inline unsigned int dev_id(struct gelic_wireless *w)
> +{
> +	return w->card->dev->did.dev_id;
> +}
> +
> +/* control wired or wireless */
> +static void gelicw_vlan_mode(struct net_device *netdev, int mode)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +
> +	if ((mode < GELIC_NET_VLAN_WIRED) ||
> +	    (mode > GELIC_NET_VLAN_WIRELESS))
> +		return;
> +
> +	card->vlan_index = mode - 1;
> +}
> +
> +/* wireless_send_event */
> +static void notify_assoc_event(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	union iwreq_data wrqu;
> +
> +	cancel_delayed_work(&w->work_scan_all);
> +	cancel_delayed_work(&w->work_scan_essid);
> +
> +	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
> +	if (w->state < GELICW_STATE_ASSOCIATED) {
> +		dev_dbg(ntodev(netdev), "notify disassociated\n");
> +		w->is_assoc = 0;
> +		memset(w->bssid, 0, ETH_ALEN);
> +	} else {
> +		dev_dbg(ntodev(netdev), "notify associated\n");
> +		w->channel = w->current_bss.channel;
> +		w->is_assoc = 1;
> +		memcpy(w->bssid, w->current_bss.bssid, ETH_ALEN);
> +	}
> +	memcpy(wrqu.ap_addr.sa_data, w->bssid, ETH_ALEN);
> +	wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL);
> +}
> +
> +/* association/disassociation */
> +static void gelicw_assoc(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (w->state == GELICW_STATE_ASSOCIATED)
> +		return;
> +	schedule_delayed_work(&w->work_start, 0);
> +}
> +
> +static int gelicw_disassoc(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	memset(w->bssid, 0, ETH_ALEN); /* clear current bssid */
> +	if (w->state < GELICW_STATE_ASSOCIATED)
> +		return 0;
> +
> +	schedule_delayed_work(&w->work_stop, 0);
> +	w->state = GELICW_STATE_SCAN_DONE;
> +	/* notify disassociation */
> +	notify_assoc_event(netdev);
> +
> +	return 0;
> +}
> +
> +static void gelicw_reassoc(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (w->cmd_send_flg != GELICW_CMD_SEND_ALL)
> +		return;
> +
> +	if (!gelicw_disassoc(netdev))
> +		gelicw_assoc(netdev);
> +}
> +
> +
> +/*
> + * lv1_net_control command
> + */
> +/* control Ether port */
> +static int gelicw_cmd_set_port(struct net_device *netdev, int mode)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 tag, val;
> +	int status;
> +
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_PORT, GELICW_ETHER_PORT, mode, 0,
> +			&tag, &val);
> +	if (status)
> +		dev_dbg(ntodev(netdev), "GELICW_SET_PORT failed:%d\n", status);
> +	return status;
> +}
> +
> +/* check support channels */
> +static int gelicw_cmd_get_ch_info(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 ch_info, val;
> +	int status;
> +
> +	if (w->state < GELICW_STATE_UP)
> +		return -EIO;
> +
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_INFO, 0, 0 , 0,
> +			&ch_info, &val);
> +	if (status) {
> +		dev_dbg(ntodev(netdev), "GELICW_GET_INFO failed:%d\n", status);
> +		w->ch_info = CH_INFO_FAIL;
> +	} else {
> +		dev_dbg(ntodev(netdev), "ch_info:%lx val:%lx\n", ch_info, val);
> +		w->ch_info = ch_info >> 48; /* MSB 16bit shows supported channnels */
> +	}
> +	return status;
> +}
> +
> +
> +/*
> + * lv1_net_control GELICW_SET_CMD command
> + * queued using schedule_work()
> + */
> +/* association */
> +static void gelicw_cmd_start(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 val;
> +	int status;
> +
> +	if (w->state < GELICW_STATE_SCAN_DONE)
> +		return;
> +
> +	dev_dbg(ntodev(netdev), "GELICW_CMD_START\n");
> +	w->cmd_id = GELICW_CMD_START;
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_CMD, w->cmd_id, 0, 0,
> +			&w->cmd_tag, &val);
> +	if (status) {
> +		w->cmd_tag = 0;
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_START failed:%d\n", status);
> +	}
> +}
> +
> +/* association done */
> +static void gelicw_cmd_start_done(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 res, val;
> +	int status;
> +
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_RES, w->cmd_tag, 0, 0,
> +			&res, &val);
> +	w->cmd_tag = 0;
> +	wake_up_interruptible(&w->waitq_cmd);
> +
> +	if (status || res)
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_START res:%d,%ld\n", status, res);
> +}
> +
> +/* disassociation */
> +static void gelicw_cmd_stop(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 res, val;
> +	int status;
> +
> +	if (w->state < GELICW_STATE_SCAN_DONE)
> +		return;
> +
> +	dev_dbg(ntodev(netdev), "GELICW_CMD_STOP\n");
> +	init_completion(&w->cmd_done);
> +	w->cmd_id = GELICW_CMD_STOP;
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_CMD, w->cmd_id, 0, 0,
> +			&w->cmd_tag, &val);
> +	if (status) {
> +		w->cmd_tag = 0;
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_STOP failed:%d\n", status);
> +		return;
> +	}
> +	wait_for_completion_interruptible(&w->cmd_done);
> +
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_RES, w->cmd_tag, 0, 0,
> +			&res, &val);
> +	w->cmd_tag = 0;
> +	if (status || res) {
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_STOP res:%d,%ld\n", status, res);
> +		return;
> +	}
> +}
> +
> +/* get rssi */
> +static void gelicw_cmd_rssi(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 lpar, res, val;
> +	int status;
> +	struct rssi_desc *rssi;
> +
> +	if (w->state < GELICW_STATE_ASSOCIATED) {
> +		w->rssi = 0;
> +		complete(&w->rssi_done);
> +		return;
> +	}
> +
> +	lpar = ps3_mm_phys_to_lpar(__pa(w->data_buf));
> +	init_completion(&w->cmd_done);
> +	w->cmd_id = GELICW_CMD_GET_RSSI;
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_CMD, w->cmd_id, 0, 0,
> +			&w->cmd_tag, &val);
> +	if (status) {
> +		w->cmd_tag = 0;
> +		w->rssi = 0;
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_GET_RSSI failed:%d\n", status);
> +	} else {
> +		wait_for_completion_interruptible(&w->cmd_done);
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_RES, w->cmd_tag, lpar, sizeof(*rssi),
> +				&res, &val);
> +		w->cmd_tag = 0;
> +		if (status || res) {
> +			w->rssi = 0;
> +			dev_dbg(ntodev(netdev), "GELICW_CMD_GET_RSSI res:%d,%ld\n", status, res);
> +		}
> +		rssi = (struct rssi_desc *)w->data_buf;
> +		w->rssi = rssi->rssi;
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_GET_RSSI:%d\n", rssi->rssi);
> +	}
> +
> +	complete(&w->rssi_done);
> +}
> +
> +/* set common configuration */
> +static int gelicw_cmd_common(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 lpar, res, val;
> +	int status;
> +	struct common_config *config;
> +
> +	if (w->state < GELICW_STATE_SCAN_DONE)
> +		return -EIO;
> +
> +	lpar = ps3_mm_phys_to_lpar(__pa(w->data_buf));
> +	config = (struct common_config *)w->data_buf;
> +	config->scan_index = w->bss_index;
> +	config->bss_type = (w->iw_mode == IW_MODE_ADHOC) ?
> +				GELICW_BSS_ADHOC : GELICW_BSS_INFRA;
> +	config->auth_method = (w->auth_mode == IW_AUTH_ALG_SHARED_KEY) ?
> +				GELICW_AUTH_SHARED : GELICW_AUTH_OPEN;
> +	switch (w->wireless_mode) {
> +	case IEEE_B:
> +		config->op_mode = GELICW_OP_MODE_11B;
> +		break;
> +	case IEEE_G:
> +		config->op_mode = GELICW_OP_MODE_11G;
> +		break;
> +	case IEEE_B | IEEE_G:
> +	default:
> +		/* default 11bg mode */
> +		config->op_mode = GELICW_OP_MODE_11BG;
> +		break;
> +	}
> +
> +	dev_dbg(ntodev(netdev), "GELICW_CMD_SET_CONFIG: index:%d type:%d auth:%d mode:%d\n",\
> +		config->scan_index, config->bss_type,\
> +		config->auth_method,config->op_mode);
> +	init_completion(&w->cmd_done);
> +	w->cmd_id = GELICW_CMD_SET_CONFIG;
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_CMD, w->cmd_id,
> +			lpar, sizeof(struct common_config),
> +			&w->cmd_tag, &val);
> +	if (status) {
> +		w->cmd_tag = 0;
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SET_CONFIG failed:%d\n", status);
> +		return status;
> +	}
> +	wait_for_completion_interruptible(&w->cmd_done);
> +
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_RES, w->cmd_tag, 0, 0,
> +			&res, &val);
> +	w->cmd_tag = 0;
> +	if (status || res) {
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SET_CONFIG res:%d,%ld\n", status, res);
> +		return -EFAULT;
> +	}
> +
> +	w->cmd_send_flg |= GELICW_CMD_SEND_COMMON;
> +
> +	return 0;
> +}
> +
> +#define h2i(c)    (isdigit(c) ? c - '0' : toupper(c) - 'A' + 10)
> +/* send WEP/WPA configuration */
> +static int gelicw_cmd_encode(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 res, val, lpar;
> +	int status;
> +	struct wep_config *config;
> +	struct wpa_config *wpa_config;
> +
> +	u8 *key, key_len;
> +
> +	if (w->state < GELICW_STATE_SCAN_DONE)
> +		return -EIO;
> +
> +	lpar = ps3_mm_phys_to_lpar(__pa(w->data_buf));
> +
> +	if (w->key_alg == IW_ENCODE_ALG_WEP ||
> +	    w->key_alg == IW_ENCODE_ALG_NONE) {
> +		/* WEP */
> +		config = (struct wep_config *)w->data_buf;
> +		memset(config, 0, sizeof(struct wep_config));
> +
> +		/* check key len */
> +		key_len = w->key_len[w->key_index];
> +		key = w->key[w->key_index];
> +		if (w->key_alg == IW_ENCODE_ALG_NONE)
> +			config->sec = GELICW_WEP_SEC_NONE;
> +		else
> +			config->sec = (key_len == 5) ? GELICW_WEP_SEC_40BIT :
> +							GELICW_WEP_SEC_104BIT;
> +		/* copy key */
> +		memcpy(config->key[w->key_index], key, key_len);
> +
> +		/* send wep config */
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SET_WEP\n");
> +		init_completion(&w->cmd_done);
> +		w->cmd_id = GELICW_CMD_SET_WEP;
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_CMD, w->cmd_id,
> +			lpar, sizeof(struct wep_config),
> +			&w->cmd_tag, &val);
> +		if (status) {
> +			w->cmd_tag = 0;
> +			dev_dbg(ntodev(netdev), "GELICW_CMD_SET_WEP failed:%d\n", status);
> +			goto err;
> +		}
> +		wait_for_completion_interruptible(&w->cmd_done);
> +
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_GET_RES, w->cmd_tag, 0, 0,
> +				&res, &val);
> +		w->cmd_tag = 0;
> +		if (status || res) {
> +			dev_dbg(ntodev(netdev), "GELICW_CMD_SET_WEP res:%d,%ld\n", status, res);
> +			status = -EFAULT;
> +			goto err;
> +		}
> +	} else {
> +		/* WPA */
> +		wpa_config = (struct wpa_config *)w->data_buf;
> +		memset(wpa_config, 0, sizeof(struct wpa_config));
> +
> +		switch (w->key_alg) {
> +		case IW_ENCODE_ALG_TKIP:
> +			wpa_config->sec = GELICW_WPA_SEC_TKIP;
> +			break;
> +		default:
> +		case IW_ENCODE_ALG_CCMP:
> +			wpa_config->sec = GELICW_WPA_SEC_AES;
> +			break;
> +		}
> +		/* check key len */
> +		key = w->key[w->key_index];
> +		key_len = w->key_len[w->key_index];
> +
> +		if (key_len > 64) key_len = 64;
> +		if (key_len != 64) {
> +			/* if key_len isn't 64byte ,it should be passphrase */
> +			/* pass phrase */
> +			memcpy(wpa_config->psk_material, key, key_len);
> +			wpa_config->psk_type = GELICW_PSK_PASSPHRASE;
> +		} else {
> +			int i;
> +			/* 64 hex */
> +			for (i = 0; i < 32; i++)
> +				wpa_config->psk_material[i] =
> +						h2i(key[2 * i]) * 16
> +						+ h2i(key[2 * i + 1]);
> +			wpa_config->psk_type = GELICW_PSK_64HEX;
> +		}
> +
> +		/* send wpa config */
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SET_WPA:type:%d\n", wpa_config->psk_type);
> +		init_completion(&w->cmd_done);
> +		w->cmd_id = GELICW_CMD_SET_WPA;
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_SET_CMD, w->cmd_id,
> +				lpar, sizeof(struct wpa_config),
> +				&w->cmd_tag, &val);
> +		if (status) {
> +			w->cmd_tag = 0;
> +			dev_dbg(ntodev(netdev), "GELICW_CMD_SET_WPA failed:%d\n", status);
> +			goto err;
> +		}
> +		wait_for_completion_interruptible(&w->cmd_done);
> +
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_GET_RES, w->cmd_tag, 0, 0, &res, &val);
> +		w->cmd_tag = 0;
> +		if (status || res) {
> +			dev_dbg(ntodev(netdev), "GELICW_CMD_SET_WPA res:%d,%ld\n", status, res);
> +			status = -EFAULT;
> +			goto err;
> +		}
> +	}
> +
> +	w->cmd_send_flg |= GELICW_CMD_SEND_ENCODE;
> +	/* (re)associate */
> +	gelicw_reassoc(netdev);
> +
> +	return 0;
> +err:
> +	gelicw_disassoc(netdev);
> +	return status;
> +}
> +
> +static int gelicw_is_ap_11b(struct gelicw_bss *list)
> +{
> +	if (list->rates_len + list->rates_ex_len == GELICW_NUM_11B_BITRATES)
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +/* get scan results */
> +static int gelicw_cmd_get_scan(struct gelic_wireless *w)
> +{
> +	u64 lpar, res, val;
> +	int status;
> +	struct scan_desc *desc;
> +	int i, j;
> +	u8 *p;
> +
> +
> +	/* get scan */
> +	dev_dbg(wtodev(w), "GELICW_CMD_GET_SCAN\n");
> +	init_completion(&w->cmd_done);
> +	w->cmd_id = GELICW_CMD_GET_SCAN;
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_SET_CMD, w->cmd_id, 0, 0,
> +			&w->cmd_tag, &val);
> +	if (status) {
> +		w->cmd_tag = 0;
> +		dev_dbg(wtodev(w), "GELICW_CMD_GET_SCAN failed:%d\n", status);
> +		return status;
> +	}
> +	wait_for_completion_interruptible(&w->cmd_done);
> +
> +	lpar = ps3_mm_phys_to_lpar(__pa(w->data_buf));
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_RES, w->cmd_tag, lpar, PAGE_SIZE,
> +			&res, &val);
> +	w->cmd_tag = 0;
> +	if (status || res) {
> +		dev_dbg(wtodev(w), "GELICW_CMD_GET_SCAN res:%d,%ld\n",
> +			status, res);
> +		return -EFAULT;
> +	}
> +
> +	desc = (struct scan_desc *)w->data_buf;
> +	for (i = 0;
> +	     i < val / sizeof(struct scan_desc) && i < MAX_SCAN_BSS;
> +	     i++) {
> +		struct gelicw_bss *bss = &w->bss_list[i];
> +
> +		bss->rates_len = 0;
> +		for (j = 0; j < MAX_RATES_LENGTH; j++)
> +			if (desc[i].rate[j])
> +				bss->rates[bss->rates_len++] = desc[i].rate[j];
> +		bss->rates_ex_len = 0;
> +		for (j = 0; j < MAX_RATES_EX_LENGTH; j++)
> +			if (desc[i].ext_rate[j])
> +				bss->rates_ex[bss->rates_ex_len++]
> +						= desc[i].ext_rate[j];
> +
> +		if (desc[i].capability & 0x3) {
> +			if (desc[i].capability & 0x1)
> +				bss->mode = IW_MODE_INFRA;
> +			else
> +				bss->mode = IW_MODE_ADHOC;
> +		}
> +		bss->channel = desc[i].channel;
> +		bss->essid_len = strnlen(desc[i].essid, IW_ESSID_MAX_SIZE);
> +		bss->rssi = (u8)desc[i].rssi;
> +		bss->capability = desc[i].capability;
> +		bss->beacon_interval = desc[i].beacon_period;
> +		memset(bss->essid, 0, sizeof(bss->essid));
> +		memcpy(bss->essid, desc[i].essid, bss->essid_len);
> +		p = (u8 *)&desc[i].bssid;
> +		memcpy(bss->bssid, &p[2], ETH_ALEN);/* bssid:64bit in desc */
> +		bss->sec_info = desc[i].security;
> +	}
> +	w->num_bss_list = i;
> +
> +	if (w->num_bss_list)
> +		return 0; /* ap found */
> +	else
> +		return -1; /* no ap found */
> +}
> +
> +/* search bssid in bss list */
> +static int gelicw_search_bss_list(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
> +	int i;
> +	int check_bss = 0, check_11g = 0, found_bss, found_11g;
> +
> +	if (!w->num_bss_list)
> +		return -1;	/* no bss list */
> +
> +	if (memcmp(off, w->wap_bssid, ETH_ALEN))
> +		check_bss = 1;
> +
> +	/* wireless op_mode seems not working with CMD_SET_CONFIG */
> +	if (w->wireless_mode == IEEE_G)
> +		check_11g = 1;
> +
> +	if (!check_bss && !check_11g)
> +		return 0;	/* no check bssid, wmode */
> +
> +	for (i = 0; i < w->num_bss_list; i++) {
> +		found_bss = found_11g = 1;
> +		if (check_bss &&
> +		    memcmp(w->bss_list[i].bssid, w->wap_bssid, ETH_ALEN))
> +			found_bss = 0; /* not found */
> +
> +		if (check_11g &&
> +		    gelicw_is_ap_11b(&w->bss_list[i]))
> +			found_11g = 0; /* not found */
> +
> +		if (found_bss && found_11g)
> +			break;
> +	}
> +
> +	if (i == w->num_bss_list)
> +		return -1; /* not found */
> +	else
> +		return i;
> +}
> +
> +/* scan done */
> +static void gelicw_scan_complete(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	int res;
> +	int bss_index;
> +
> +	/* get scan results */
> +	res = gelicw_cmd_get_scan(w);
> +	if (w->is_assoc)
> +		w->state = GELICW_STATE_ASSOCIATED;
> +	else
> +		w->state = GELICW_STATE_SCAN_DONE;
> +
> +	if (res) {
> +		/* No AP found */
> +		if (!w->scan_all) {
> +			/* no specified AP */
> +			gelicw_disassoc(netdev);
> +			/* rescan */
> +			if (w->essid_search && w->essid_len)
> +				schedule_delayed_work(&w->work_scan_essid,
> +							GELICW_SCAN_INTERVAL);
> +			return;
> +		}
> +	}
> +
> +	if (w->scan_all) {
> +		/* all params should be set again after scan */
> +		w->cmd_send_flg = 0;
> +		return;
> +	}
> +
> +	bss_index = gelicw_search_bss_list(netdev);
> +	if (bss_index < 0) {
> +		/* no wap_bssid in bss_list */
> +		if (w->essid_search && w->essid_len)
> +			schedule_delayed_work(&w->work_scan_essid,
> +						GELICW_SCAN_INTERVAL);
> +		return;
> +	}
> +	w->bss_index = (u8)bss_index;
> +	w->current_bss = w->bss_list[w->bss_index];
> +
> +	/* essid search complete */
> +	w->essid_search = 0;
> +	w->cmd_send_flg |= GELICW_CMD_SEND_SCAN;
> +
> +	/* (re)connect to AP */
> +	if (w->is_assoc) {
> +		/* notify disassociation */
> +		w->state = GELICW_STATE_SCAN_DONE;
> +		notify_assoc_event(netdev);
> +	}
> +	schedule_delayed_work(&w->work_common, 0);
> +	schedule_delayed_work(&w->work_encode, 0);
> +}
> +
> +/* start scan */
> +static int gelicw_cmd_set_scan(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 res, val, lpar;
> +	int status;
> +	u8 *p;
> +
> +	if (w->state < GELICW_STATE_UP) {
> +		w->scan_all = 0;
> +		return -EIO;
> +	}
> +	if (!w->scan_all && !w->essid_len)
> +		return -EINVAL; /* unsupported essid ANY */
> +
> +	/* set device wired to wireless when essid is set */
> +	if (!w->scan_all && w->wireless < GELICW_WIRELESS_ON) {
> +		gelicw_vlan_mode(netdev, GELIC_NET_VLAN_WIRELESS);
> +		gelicw_cmd_set_port(netdev, GELICW_PORT_DOWN);
> +		w->wireless = GELICW_WIRELESS_ON;
> +	}
> +
> +	p = (u8 *)w->data_buf;
> +	lpar = ps3_mm_phys_to_lpar(__pa(w->data_buf));
> +
> +	/* avoid frequent scanning */
> +	if (!w->essid_search && /* background scan off */
> +	    w->scan_all &&
> +	    (time_before64(get_jiffies_64(), w->last_scan + 5 * HZ)))
> +		return 0;
> +
> +	w->bss_key_alg = IW_ENCODE_ALG_NONE;
> +
> +	init_completion(&w->cmd_done);
> +	w->state = GELICW_STATE_SCANNING;
> +	w->cmd_id = GELICW_CMD_SCAN;
> +
> +	if (w->scan_all) {
> +		/* scan all ch */
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SCAN all\n");
> +		w->last_scan = get_jiffies_64(); /* last scan time */
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_SET_CMD, w->cmd_id, 0, 0,
> +				&w->cmd_tag, &val);
> +	} else {
> +		/* scan essid */
> +		memset(p, 0, 32);
> +		memcpy(p, w->essid, w->essid_len);
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SCAN essid\n");
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_SET_CMD, w->cmd_id, lpar, 32,
> +				&w->cmd_tag, &val);
> +	}
> +
> +	if (status) {
> +		w->cmd_tag = 0;
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SCAN failed:%d\n", status);
> +		return status;
> +	}
> +	wait_for_completion_interruptible(&w->cmd_done);
> +
> +	status = lv1_net_control(bus_id(w), dev_id(w),
> +			GELICW_GET_RES, w->cmd_tag, 0, 0,
> +			&res, &val);
> +	w->cmd_tag = 0;
> +	if (status || res) {
> +		dev_dbg(ntodev(netdev), "GELICW_CMD_SCAN res:%d,%ld\n", status, res);
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +static void gelicw_send_common_config(struct net_device *netdev,
> +					u8 *cur, u8 mode)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (*cur != mode) {
> +		*cur = mode;
> +		if (w->state < GELICW_STATE_SCAN_DONE)
> +			return;
> +
> +		if (!(w->cmd_send_flg & GELICW_CMD_SEND_SCAN) &&
> +		    w->essid_len)
> +			/* scan essid and set other params */
> +			schedule_delayed_work(&w->work_scan_essid, 0);
> +		else {
> +			schedule_delayed_work(&w->work_common, 0);
> +			if (w->cmd_send_flg
> +			    & GELICW_CMD_SEND_ENCODE)
> +				/* (re)send encode key */
> +				schedule_delayed_work(&w->work_encode, 0);
> +		}
> +	}
> +}
> +
> +
> +/*
> + * work queue
> + */
> +static void gelicw_work_rssi(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_rssi.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag) {
> +		schedule_delayed_work(&w->work_rssi, HZ / 5);
> +		return;
> +	}
> +
> +	gelicw_cmd_rssi(netdev);
> +}
> +
> +static void gelicw_work_scan_all(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_scan_all.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag || w->state == GELICW_STATE_SCANNING) {
> +		schedule_delayed_work(&w->work_scan_all, HZ / 5);
> +		return;
> +	}
> +
> +	w->scan_all = 1;
> +	gelicw_cmd_set_scan(netdev);
> +}
> +
> +static void gelicw_work_scan_essid(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_scan_essid.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag || w->scan_all || w->state == GELICW_STATE_SCANNING) {
> +		schedule_delayed_work(&w->work_scan_essid, HZ / 5);
> +		return;
> +	}
> +	w->bss_index = 0;
> +	w->scan_all = 0;
> +	gelicw_cmd_set_scan(netdev);
> +}
> +
> +static void gelicw_work_common(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_common.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag) {
> +		schedule_delayed_work(&w->work_common, HZ / 5);
> +		return;
> +	}
> +	gelicw_cmd_common(netdev);
> +}
> +
> +static void gelicw_work_encode(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_encode.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag) {
> +		schedule_delayed_work(&w->work_encode, HZ / 5);
> +		return;
> +	}
> +	gelicw_cmd_encode(netdev);
> +}
> +
> +static void gelicw_work_start(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_start.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag) {
> +		schedule_delayed_work(&w->work_start, HZ / 5);
> +		return;
> +	}
> +	gelicw_cmd_start(netdev);
> +}
> +
> +static void gelicw_work_start_done(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_start_done);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	gelicw_cmd_start_done(netdev);
> +}
> +
> +static void gelicw_work_stop(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_stop.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag) {
> +		schedule_delayed_work(&w->work_stop, HZ / 5);
> +		return;
> +	}
> +	gelicw_cmd_stop(netdev);
> +}
> +
> +static void gelicw_work_roam(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_roam.work);
> +	struct net_device *netdev = w->card->netdev;
> +
> +	if (w->cmd_tag || w->scan_all || w->state == GELICW_STATE_SCANNING) {
> +		schedule_delayed_work(&w->work_roam, HZ / 5);
> +		return;
> +	}
> +	gelicw_cmd_stop(netdev);
> +	w->bss_index = 0;
> +	w->scan_all = 0;
> +	gelicw_cmd_set_scan(netdev);
> +}
> +
> +/*
> + * Event handler
> + */
> +#define GELICW_EVENT_LOOP_MAX 16
> +static void gelicw_event(struct work_struct *work)
> +{
> +	struct gelic_wireless *w =
> +		container_of(work, struct gelic_wireless, work_event);
> +	struct net_device *netdev = w->card->netdev;
> +	u64 event_type, val;
> +	int i, status;
> +
> +	for (i = 0; i < GELICW_EVENT_LOOP_MAX; i++) {
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_GET_EVENT, 0, 0 , 0,
> +				&event_type, &val);
> +		if (status == GELICW_EVENT_NO_ENTRY)
> +			/* got all events */
> +			break;
> +		else if (status){
> +			dev_dbg(ntodev(netdev), "GELICW_GET_EVENT failed:%d\n", status);
> +			return;
> +		}
> +		switch(event_type) {
> +		case GELICW_EVENT_DEVICE_READY:
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_DEVICE_READY\n");
> +			break;
> +		case GELICW_EVENT_SCAN_COMPLETED:
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_SCAN_COMPLETED\n");
> +			gelicw_scan_complete(netdev);
> +			break;
> +		case GELICW_EVENT_BEACON_LOST:
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_BEACON_LOST\n");
> +			w->state = GELICW_STATE_SCAN_DONE;
> +			notify_assoc_event(netdev);
> +			/* roaming */
> +			w->essid_search = 1;
> +			schedule_delayed_work(&w->work_roam, 0);
> +			break;
> +		case GELICW_EVENT_CONNECTED:
> +		{
> +			u16 ap_sec;
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_CONNECTED\n");
> +			/* this event ocuured with any key_alg */
> +			ap_sec = w->current_bss.sec_info;
> +			if (w->key_alg == IW_ENCODE_ALG_NONE) {
> +				/* no encryption */
> +				if (ap_sec == 0) {
> +					w->state = GELICW_STATE_ASSOCIATED;
> +					notify_assoc_event(netdev);
> +				}
> +			} else if (w->key_alg == IW_ENCODE_ALG_WEP){
> +				if ((ap_sec & GELICW_SEC_TYPE_WEP_MASK)
> +				    == GELICW_SEC_TYPE_WEP) {
> +					/* wep */
> +					w->state = GELICW_STATE_ASSOCIATED;
> +					notify_assoc_event(netdev);
> +				}
> +			}
> +			break;
> +		}
> +		case GELICW_EVENT_WPA_CONNECTED:
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_WPA_CONNECTED\n");
> +			w->state = GELICW_STATE_ASSOCIATED;
> +			notify_assoc_event(netdev);
> +			break;
> +		case GELICW_EVENT_WPA_ERROR:
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_WPA_ERROR\n");
> +			break;
> +		default:
> +			dev_dbg(ntodev(netdev), "  GELICW_EVENT_UNKNOWN\n");
> +			break;
> +		}
> +	}
> +}
> +
> +static void gelicw_clear_event(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u64 event_type, val;
> +	int i, status;
> +
> +	for (i = 0; i < GELICW_EVENT_LOOP_MAX; i++) {
> +		status = lv1_net_control(bus_id(w), dev_id(w),
> +				GELICW_GET_EVENT, 0, 0 , 0,
> +				&event_type, &val);
> +		if (status)
> +			return;/* got all events */
> +
> +		switch(event_type) {
> +		case GELICW_EVENT_SCAN_COMPLETED:
> +			w->state = GELICW_STATE_SCAN_DONE;
> +			wake_up_interruptible(&w->waitq_scan);
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +}
> +
> +/*
> + * gelic_net support function
> + */
> +static void gelicw_clear_params(struct gelic_wireless *w)
> +{
> +	int i;
> +
> +	/* clear status */
> +	w->state = GELICW_STATE_DOWN;
> +	w->cmd_send_flg = 0;
> +	w->scan_all = 0;
> +	w->is_assoc = 0;
> +	w->essid_search = 0;
> +	w->cmd_tag = 0;
> +	w->cmd_id = 0;
> +	w->last_scan = 0;
> +
> +	/* default mode and settings */
> +	w->essid_len = 0;
> +	w->essid[0] = '\0';
> +	w->nick[0] = '\0';
> +	w->iw_mode = IW_MODE_INFRA;
> +	w->auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
> +	w->wireless_mode = IEEE_B | IEEE_G;
> +	w->bss_index = 0;
> +	memset(w->bssid, 0, ETH_ALEN);
> +	memset(w->wap_bssid, 0, ETH_ALEN);
> +
> +	/* init key */
> +	w->key_index = 0;
> +	for (i = 0; i < WEP_KEYS; i++) {
> +		w->key[i][0] = '\0';
> +		w->key_len[i] = 0;
> +	}
> +	w->key_alg = IW_ENCODE_ALG_NONE;
> +	w->bss_key_alg = IW_ENCODE_ALG_NONE;
> +}
> +
> +int gelicw_setup_netdev(struct net_device *netdev, int wi)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	union ps3_firmware_version ver;
> +	union ps3_firmware_version initial_ver;
> +
> +	if (wi < 0) {
> +		/* PS3 low model has no wireless */
> +		dev_info(ntodev(netdev), "No wireless dvice in this system\n");
> +		w->wireless = 0;
> +		return 0;
> +	}
> +	/* version check */
> +	initial_ver.raw = 0;
> +	initial_ver.major = 1;
> +	initial_ver.minor = 6;
> +	if (ps3_get_firmware_version(&ver) ||
> +	    (ver.raw < initial_ver.raw)) {
> +		dev_info(ntodev(netdev),
> +			 "firmware %d.%d is too old for wireless.\n",
> +			 ver.major, ver.minor);
> +		w->wireless = 0;
> +		return 0;
> +	}
> +	/* we need 4K aligned, 16 units of scan_desc sized */
> +	BUILD_BUG_ON(PAGE_SIZE < sizeof(struct scan_desc) * MAX_SCAN_BSS);
> +	w->data_buf = (u8*)get_zeroed_page(GFP_KERNEL);
> +	if (!w->data_buf) {
> +		w->wireless = 0;
> +		dev_info(ntodev(netdev), "%s:get_page failed\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	w->wireless = GELICW_WIRELESS_SUPPORTED;
> +
> +	w->ch_info = 0;
> +	w->channel = 0;
> +	netdev->wireless_data = &w->wireless_data;
> +	netdev->wireless_handlers = &gelicw_handler_def;
> +	INIT_WORK(&w->work_event, gelicw_event);
> +	INIT_WORK(&w->work_start_done, gelicw_work_start_done);
> +	INIT_DELAYED_WORK(&w->work_rssi, gelicw_work_rssi);
> +	INIT_DELAYED_WORK(&w->work_scan_all, gelicw_work_scan_all);
> +	INIT_DELAYED_WORK(&w->work_scan_essid, gelicw_work_scan_essid);
> +	INIT_DELAYED_WORK(&w->work_common, gelicw_work_common);
> +	INIT_DELAYED_WORK(&w->work_encode, gelicw_work_encode);
> +	INIT_DELAYED_WORK(&w->work_start, gelicw_work_start);
> +	INIT_DELAYED_WORK(&w->work_stop, gelicw_work_stop);
> +	INIT_DELAYED_WORK(&w->work_roam, gelicw_work_roam);
> +	init_waitqueue_head(&w->waitq_cmd);
> +	init_waitqueue_head(&w->waitq_scan);
> +
> +	gelicw_clear_params(w);
> +
> +	return 0;
> +}
> +
> +void gelicw_up(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (!w->wireless)
> +		return;
> +
> +	dev_dbg(ntodev(netdev), "gelicw_up\n");
> +	if (w->state < GELICW_STATE_UP)
> +		w->state = GELICW_STATE_UP;
> +
> +	/* start essid scanning */
> +	if (w->essid_len)
> +		schedule_delayed_work(&w->work_scan_essid, 0);
> +}
> +
> +int gelicw_down(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (!w->wireless || w->state == GELICW_STATE_DOWN)
> +		return 0;
> +
> +	dev_dbg(ntodev(netdev), "gelicw_down\n");
> +	w->wireless = GELICW_WIRELESS_SHUTDOWN;
> +	flush_scheduled_work();
> +
> +	/* check cmd_tag of CMD_START */
> +	if (w->cmd_id == GELICW_CMD_START)
> +		wait_event_interruptible(w->waitq_cmd, !w->cmd_tag);
> +	/* wait scan done */
> +	if (w->state == GELICW_STATE_SCANNING) {
> +		wait_event_interruptible(w->waitq_scan,
> +					w->state != GELICW_STATE_SCANNING);
> +		gelicw_cmd_get_scan(w);
> +	}
> +
> +	gelicw_cmd_stop(netdev);
> +	if (w->is_assoc) {
> +		w->state = GELICW_STATE_DOWN;
> +		notify_assoc_event(netdev);
> +	}
> +	gelicw_clear_params(w);
> +
> +	/* set device wireless to wired */
> +	gelicw_vlan_mode(netdev, GELIC_NET_VLAN_WIRED);
> +	gelicw_cmd_set_port(netdev, GELICW_PORT_UP);
> +	w->wireless = GELICW_WIRELESS_SUPPORTED;
> +
> +	return 0;
> +}
> +
> +void gelicw_remove(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (!w->wireless)
> +		return;
> +
> +	dev_dbg(ntodev(netdev), "gelicw_remove\n");
> +	gelicw_down(netdev);
> +	w->wireless = 0;
> +	netdev->wireless_handlers = NULL;
> +	free_page((unsigned long)w->data_buf);
> +}
> +
> +void gelicw_interrupt(struct net_device *netdev, u64 status)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (!w->wireless)
> +		return;
> +
> +	if (status & GELICW_DEVICE_CMD_COMP) {
> +		dev_dbg(ntodev(netdev), "GELICW_DEVICE_CMD_COMP\n");
> +		if (w->cmd_id == GELICW_CMD_START)
> +			schedule_work(&w->work_start_done);
> +		else
> +			complete(&w->cmd_done);
> +	}
> +	if (status & GELICW_DEVICE_EVENT_RECV) {
> +		dev_dbg(ntodev(netdev), "GELICW_DEVICE_EVENT_RECV\n");
> +		if (w->wireless == GELICW_WIRELESS_SHUTDOWN)
> +			gelicw_clear_event(netdev);
> +		else
> +			schedule_work(&w->work_event);
> +	}
> +}
> +
> +int gelicw_is_associated(struct net_device *netdev)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	if (!w->wireless)
> +		return 0;
> +
> +	return w->is_assoc;
> +}
> +
> +
> +/*
> + * Wireless externsions
> + */
> +static int gelicw_get_name(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx: get_name\n");
> +	if (w->state < GELICW_STATE_UP) {
> +		strcpy(wrqu->name, "radio off");
> +		return 0;
> +	}
> +
> +	if (w->wireless_mode == IEEE_B ||
> +	    (w->is_assoc && gelicw_is_ap_11b(&w->current_bss)))
> +		strcpy(wrqu->name, "IEEE 802.11b");
> +	else {
> +		switch (w->wireless_mode) {
> +		case IEEE_G:
> +			strcpy(wrqu->name, "IEEE 802.11g");
> +			break;
> +		case IEEE_B | IEEE_G:
> +		default:
> +			strcpy(wrqu->name, "IEEE 802.11bg");
> +			break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_freq(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_freq *fwrq = &wrqu->freq;
> +	int ch;
> +
> +	dev_dbg(ntodev(netdev), "wx: set_freq e:%d m:%d\n", fwrq->e, fwrq->m);
> +	if (w->is_assoc || w->state < GELICW_STATE_UP)
> +		return 0;
> +
> +	/* this setting has no effect for INFRA mode */
> +	if (fwrq->e == 1) {
> +		u32 f = fwrq->m / 100000;
> +		int i;
> +		for (i = 0; i < ARRAY_SIZE(freq_list); i++)
> +			if (freq_list[i] == f)
> +				break;
> +		if (i == ARRAY_SIZE(freq_list))
> +			return -EINVAL;
> +		fwrq->m = i + 1; /* ch number */
> +		fwrq->e = 0;
> +	}
> +	if (fwrq->e > 0)
> +		return -EINVAL;
> +
> +	ch = fwrq->m;
> +	if (ch < 1)
> +		w->channel = 0; /* auto */
> +	else if (ch > ARRAY_SIZE(freq_list))
> +		return -EINVAL;
> +	else {
> +		/* check supported channnel */
> +		if (!w->ch_info)
> +			gelicw_cmd_get_ch_info(netdev);
> +		if (w->ch_info & (1 << (ch - 1)))
> +			w->channel = ch;
> +		else
> +			return -EINVAL;
> +	}
> +	dev_dbg(ntodev(netdev), " set cnannel: %d\n", w->channel);
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_freq(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx: get_freq:%d\n", w->channel);
> +	if (w->channel == 0)
> +		wrqu->freq.m = 0;
> +	else
> +		wrqu->freq.m = freq_list[w->channel - 1] * 100000;
> +	wrqu->freq.e = 1;
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_mode(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	int mode = wrqu->mode;
> +	u8 iw_mode = IW_MODE_INFRA;
> +
> +	dev_dbg(ntodev(netdev), "wx: set_mode:%x\n",mode);
> +	switch (mode) {
> +	case IW_MODE_ADHOC:
> +		dev_dbg(ntodev(netdev), "IW_MODE_ADHOC\n");
> +		iw_mode = mode;
> +		return -EOPNOTSUPP; /* adhoc not supported */
> +	case IW_MODE_INFRA:
> +	default:
> +		dev_dbg(ntodev(netdev), "IW_MODE_INFRA\n");
> +		iw_mode = IW_MODE_INFRA;
> +		break;
> +	}
> +
> +	/* send common config */
> +	gelicw_send_common_config(netdev, &w->iw_mode, iw_mode);
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_mode(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx: get_mode\n");
> +	wrqu->mode = w->iw_mode;
> +
> +	return 0;
> +}
> +
> +static inline int gelicw_qual2level(int qual)
> +{
> +	return (qual * 4 - 820)/10; /* FIXME: dummy */
> +}
> +
> +static int gelicw_get_range(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_range *range = (struct iw_range *)extra;
> +	int num_ch, i;
> +
> +	dev_dbg(ntodev(netdev), "wx: get_range\n");
> +	wrqu->data.length = sizeof(*range);
> +	memset(range, 0, sizeof(*range));
> +
> +	/* wireless extension */
> +	range->we_version_compiled = WIRELESS_EXT;
> +	range->we_version_source = 19;
> +
> +	/* supported bitrates */
> +	if (w->wireless_mode == IEEE_B)
> +		range->num_bitrates = GELICW_NUM_11B_BITRATES;
> +	else
> +		range->num_bitrates = ARRAY_SIZE(bitrate_list);
> +	range->throughput = bitrate_list[range->num_bitrates -1] / 2; /* half */
> +	for (i = 0; i < range->num_bitrates; i++)
> +		range->bitrate[i] = bitrate_list[i];
> +
> +	range->max_qual.qual = 100; /* relative value */
> +	range->max_qual.level = 0;
> +	range->avg_qual.qual = 50;
> +	range->avg_qual.level = 0;
> +	range->sensitivity = 0;
> +
> +	/* encryption capabilities */
> +	range->encoding_size[0] = 5;	/* 40bit WEP */
> +	range->encoding_size[1] = 13;	/* 104bit WEP */
> +	range->encoding_size[2] = 64;	/* WPA-PSK */
> +	range->num_encoding_sizes = 3;
> +	range->max_encoding_tokens = WEP_KEYS;
> +	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
> +			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
> +
> +	/* freq */
> +	if (!w->ch_info)
> +		gelicw_cmd_get_ch_info(netdev); /* get supported freq */
> +
> +	num_ch = 0;
> +	for (i = 0; i < ARRAY_SIZE(freq_list); i++)
> +		if (w->ch_info & (1 << i)) {
> +			range->freq[num_ch].i = i + 1;
> +			range->freq[num_ch].m = freq_list[i] * 100000;
> +			range->freq[num_ch].e = 1;
> +			if (++num_ch == IW_MAX_FREQUENCIES)
> +				break;
> +		}
> +
> +	range->num_channels = num_ch;
> +	range->num_frequency = num_ch;
> +
> +	/* event capabilities */
> +	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
> +				IW_EVENT_CAPA_MASK(SIOCGIWAP));
> +	range->event_capa[1] = IW_EVENT_CAPA_K_1;
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_wap(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	static const u8 any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
> +	static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
> +
> +	dev_dbg(ntodev(netdev), "wx: set_wap\n");
> +	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
> +		return -EINVAL;
> +
> +	if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
> +	    !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
> +		if (!memcmp(off, w->wap_bssid, ETH_ALEN))
> +			return 0; /* ap off, no change */
> +		else {
> +			memset(w->wap_bssid, 0, ETH_ALEN);
> +			/* start scan */
> +		}
> +	} else if (!memcmp(w->wap_bssid, wrqu->ap_addr.sa_data, ETH_ALEN))
> +		/* no change */
> +		return 0;
> +	else if (!memcmp(w->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) {
> +		/* current bss */
> +		memcpy(w->wap_bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
> +		return 0;
> +	} else
> +		memcpy(w->wap_bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
> +
> +	/* start scan */
> +	if (w->essid_len && w->state >= GELICW_STATE_SCAN_DONE) {
> +		gelicw_disassoc(netdev);
> +		/* scan essid */
> +		cancel_delayed_work(&w->work_scan_all);
> +		cancel_delayed_work(&w->work_scan_essid);
> +		w->essid_search = 1;
> +		schedule_delayed_work(&w->work_scan_essid, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_wap(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx: get_wap\n");
> +	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
> +	memcpy(wrqu->ap_addr.sa_data, w->bssid, ETH_ALEN);
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_scan(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx: set_scan\n");
> +	if (w->state < GELICW_STATE_UP)
> +		return -EIO;
> +
> +	/* cancel scan */
> +	cancel_delayed_work(&w->work_scan_all);
> +	cancel_delayed_work(&w->work_scan_essid);
> +
> +	schedule_delayed_work(&w->work_scan_all, 0);
> +
> +	return 0;
> +}
> +
> +#define MAX_CUSTOM_LEN 64
> +static char *gelicw_translate_scan(struct net_device *netdev,
> +				char *start, char *stop,
> +				struct gelicw_bss *list)
> +{
> +	char custom[MAX_CUSTOM_LEN];
> +	struct iw_event iwe;
> +	int i;
> +	char *p, *current_val;
> +
> +	/* BSSID */
> +	iwe.cmd = SIOCGIWAP;
> +	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
> +	memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN);
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
> +
> +	/* ESSID */
> +	iwe.cmd = SIOCGIWESSID;
> +	iwe.u.data.flags = 1;
> +	iwe.u.data.length = list->essid_len;
> +	start = iwe_stream_add_point(start, stop, &iwe, list->essid);
> +
> +	/* protocol name */
> +	iwe.cmd = SIOCGIWNAME;
> +	if (gelicw_is_ap_11b(list))
> +		snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b");
> +	else
> +		snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg");
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
> +
> +	/* MODE */
> +	iwe.cmd = SIOCGIWMODE;
> +	iwe.u.mode = list->mode;
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
> +
> +	/* FREQ */
> +	iwe.cmd = SIOCGIWFREQ;
> +	iwe.u.freq.m = list->channel;
> +	iwe.u.freq.e = 0;
> +	iwe.u.freq.i = 0;
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
> +
> +	/* ENCODE */
> +	iwe.cmd = SIOCGIWENCODE;
> +	if (list->capability & WLAN_CAPABILITY_PRIVACY)
> +		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
> +	else
> +		iwe.u.data.flags = IW_ENCODE_DISABLED;
> +	iwe.u.data.length = 0;
> +	start = iwe_stream_add_point(start, stop, &iwe, list->essid);
> +
> +	/* QUAL */
> +	iwe.cmd = IWEVQUAL;
> +	iwe.u.qual.updated  = IW_QUAL_QUAL_UPDATED |
> +			IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID;
> +	iwe.u.qual.qual = list->rssi;
> +	iwe.u.qual.level = gelicw_qual2level(list->rssi);
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
> +
> +	/* RATE */
> +	current_val = start + IW_EV_LCP_LEN;
> +	iwe.cmd = SIOCGIWRATE;
> +	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
> +	for (i = 0; i < list->rates_len; i++) {
> +		iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000);
> +		current_val = iwe_stream_add_value(start, current_val, stop,
> +					&iwe, IW_EV_PARAM_LEN);
> +	}
> +	for (i = 0; i < list->rates_ex_len; i++) {
> +		iwe.u.bitrate.value = ((list->rates_ex[i] & 0x7f) * 500000);
> +		current_val = iwe_stream_add_value(start, current_val, stop,
> +					&iwe, IW_EV_PARAM_LEN);
> +	}
> +	if ((current_val - start) > IW_EV_LCP_LEN)
> +		start = current_val;
> +
> +	/* Extra */
> +	/* BEACON */
> +	memset(&iwe, 0, sizeof(iwe));
> +	iwe.cmd = IWEVCUSTOM;
> +	p = custom;
> +	p += snprintf(p, MAX_CUSTOM_LEN, "bcn_int=%d", list->beacon_interval);
> +	iwe.u.data.length = p - custom;
> +	start = iwe_stream_add_point(start, stop, &iwe, custom);
> +
> +	/* AP security */
> +	memset(&iwe, 0, sizeof(iwe));
> +	iwe.cmd = IWEVCUSTOM;
> +	p = custom;
> +	p += snprintf(p, MAX_CUSTOM_LEN, "ap_sec=%04X", list->sec_info);
> +	iwe.u.data.length = p - custom;
> +	start = iwe_stream_add_point(start, stop, &iwe, custom);
> +
> +	return start;
> +}
> +
> +static int gelicw_get_scan(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	int i;
> +	char *ev = extra;
> +	char *stop = ev + wrqu->data.length;
> +
> +	dev_dbg(ntodev(netdev), "wx: get_scan \n");
> +	switch (w->state) {
> +	case GELICW_STATE_DOWN:
> +	case GELICW_STATE_UP:
> +		return 0; /* no scan results */
> +	case GELICW_STATE_SCANNING:
> +		return -EAGAIN; /* now scanning */
> +	case GELICW_STATE_SCAN_DONE:
> +		if (!w->scan_all) /* essid scan */
> +			return -EAGAIN;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	w->scan_all = 0;
> +	for (i = 0; i < w->num_bss_list; i++)
> +		ev = gelicw_translate_scan(netdev, ev, stop, &w->bss_list[i]);
> +	wrqu->data.length = ev - extra;
> +	wrqu->data.flags = 0;
> +
> +	/* start background scan */
> +	if (w->essid_search)
> +		schedule_delayed_work(&w->work_scan_essid,
> +					GELICW_SCAN_INTERVAL);
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_essid(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u16 length = 0;
> +
> +	dev_dbg(ntodev(netdev), "wx:set_essid\n");
> +	/* cancel scan */
> +	w->essid_search = 0;
> +	cancel_delayed_work(&w->work_scan_all);
> +	cancel_delayed_work(&w->work_scan_essid);
> +
> +	if (wrqu->essid.flags && wrqu->essid.length)
> +		length = wrqu->essid.length;
> +
> +	if (length == 0) {
> +		/* essid ANY scan not supported */
> +		dev_dbg(ntodev(netdev), "ESSID ANY\n");
> +		w->essid_len = 0; /* clear essid */
> +		w->essid[0] = '\0';
> +		return 0;
> +	} else {
> +		/* check essid */
> +		if (length > IW_ESSID_MAX_SIZE)
> +			return -EINVAL;
> +		if (w->essid_len == length &&
> +		    !strncmp(w->essid, extra, length)) {
> +			/* same essid */
> +			if (w->is_assoc)
> +				return 0;
> +		} else {
> +			/* set new essid */
> +			w->essid_len = length;
> +			memcpy(w->essid, extra, length);
> +		}
> +	}
> +	/* start essid scan */
> +	w->essid_search = 1;
> +	schedule_delayed_work(&w->work_scan_essid, 0);
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_essid(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx:get_essid\n");
> +	if (w->essid_len) {
> +		memcpy(extra, w->essid, w->essid_len);
> +		wrqu->essid.length = w->essid_len;
> +		wrqu->essid.flags = 1;
> +	} else {
> +		wrqu->essid.length = 0;
> +		wrqu->essid.flags = 0;
> +	}
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_nick(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	u32 len = wrqu->data.length;
> +
> +	dev_dbg(ntodev(netdev), "wx:set_nick\n");
> +	if (len > IW_ESSID_MAX_SIZE)
> +		return -EINVAL;
> +
> +	memset(w->nick, 0, sizeof(w->nick));
> +	memcpy(w->nick, extra, len);
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_nick(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx:get_nick\n");
> +	wrqu->data.length = strlen(w->nick);
> +	memcpy(extra, w->nick, wrqu->data.length);
> +	wrqu->data.flags = 1;
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_rate(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	dev_dbg(ntodev(netdev), "wx:set_rate:%d\n", wrqu->bitrate.value);
> +	if (wrqu->bitrate.value == -1)
> +		return 0;	/* auto rate only */
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +static int gelicw_get_rate(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx:get_rate\n");
> +
> +	if (w->wireless_mode == IEEE_B ||
> +	    (w->is_assoc && gelicw_is_ap_11b(&w->current_bss)))
> +		wrqu->bitrate.value = bitrate_list[GELICW_NUM_11B_BITRATES -1];
> +	else
> +		wrqu->bitrate.value = bitrate_list[ARRAY_SIZE(bitrate_list) -1];
> +
> +	wrqu->bitrate.fixed = 0;
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_encode(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_point *enc = &wrqu->encoding;
> +	int i, index, key_index;
> +
> +	dev_dbg(ntodev(netdev), "wx:set_encode: flags:%x\n", enc->flags );
> +	index = enc->flags & IW_ENCODE_INDEX;
> +	if (index < 0 || index > WEP_KEYS)
> +		return -EINVAL;
> +	index--;
> +
> +	if (enc->length > IW_ENCODING_TOKEN_MAX)
> +		return -EINVAL;
> +
> +	if (index != -1)
> +		w->key_index = index;
> +	key_index = w->key_index;
> +
> +	if (enc->flags & IW_ENCODE_DISABLED) {
> +		/* disable encryption */
> +		if (index == -1) {
> +			/* disable all */
> +			w->key_alg = IW_ENCODE_ALG_NONE;
> +			for (i = 0; i < WEP_KEYS; i++)
> +				w->key_len[i] = 0;
> +		} else
> +			w->key_len[key_index] = 0;
> +	} else if (enc->flags & IW_ENCODE_NOKEY) {
> +		/* key not changed */
> +		if (w->key_alg == IW_ENCODE_ALG_NONE)
> +			w->key_alg = IW_ENCODE_ALG_WEP; /* default wep */
> +	} else {
> +		/* enable encryption */
> +		w->key_len[key_index] = enc->length;
> +		if (w->key_alg == IW_ENCODE_ALG_NONE)
> +			w->key_alg = IW_ENCODE_ALG_WEP; /* default wep */
> +		memcpy(w->key[key_index], extra, w->key_len[key_index]);
> +	}
> +	dev_dbg(ntodev(netdev), "key %d len:%d alg:%x\n",\
> +		key_index, w->key_len[key_index], w->key_alg);
> +
> +	if (w->state >= GELICW_STATE_SCAN_DONE &&
> +	    w->cmd_send_flg == 0 && w->essid_len)
> +		/* scan essid and set other params */
> +		schedule_delayed_work(&w->work_scan_essid, 0);
> +	else
> +		schedule_delayed_work(&w->work_encode, 0);
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_encode(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_point *enc = &wrqu->encoding;
> +	int index, key_index;
> +
> +	dev_dbg(ntodev(netdev), "wx:get_encode\n");
> +	index = enc->flags & IW_ENCODE_INDEX;
> +	if (index < 0 || index > WEP_KEYS)
> +		return -EINVAL;
> +
> +	index--;
> +	key_index = (index == -1 ? w->key_index : index);
> +	enc->flags = key_index + 1;
> +
> +	if (w->key_alg == IW_ENCODE_ALG_NONE || !w->key_len[key_index]) {
> +		/* no encryption */
> +		enc->flags |= IW_ENCODE_DISABLED;
> +		enc->length = 0;
> +	} else {
> +		enc->flags |= IW_ENCODE_NOKEY;
> +		enc->length = w->key_len[key_index];
> +		memset(extra, 0, w->key_len[key_index]);
> +	}
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_auth(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_param *param = &wrqu->param;
> +	int value = param->value;
> +	int ret = 0;
> +
> +	dev_dbg(ntodev(netdev), "wx:set_auth:%x\n", param->flags & IW_AUTH_INDEX);
> +	switch(param->flags & IW_AUTH_INDEX) {
> +	case IW_AUTH_WPA_VERSION:
> +	case IW_AUTH_CIPHER_PAIRWISE:
> +	case IW_AUTH_CIPHER_GROUP:
> +	case IW_AUTH_KEY_MGMT:
> +	case IW_AUTH_TKIP_COUNTERMEASURES:
> +	case IW_AUTH_DROP_UNENCRYPTED:
> +	case IW_AUTH_WPA_ENABLED:
> +	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
> +	case IW_AUTH_ROAMING_CONTROL:
> +	case IW_AUTH_PRIVACY_INVOKED:
> +		/* ignore */
> +		dev_dbg(ntodev(netdev), "IW_AUTH(%x)\n", param->flags & IW_AUTH_INDEX);
> +		break;
> +	case IW_AUTH_80211_AUTH_ALG:
> +		dev_dbg(ntodev(netdev), "IW_AUTH_80211_AUTH_ALG:\n");
> +		if (value & IW_AUTH_ALG_SHARED_KEY)
> +			w->auth_mode = IW_AUTH_ALG_SHARED_KEY;
> +		else if (value & IW_AUTH_ALG_OPEN_SYSTEM)
> +			w->auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
> +		else
> +			ret = -EINVAL;
> +		break;
> +	default:
> +		dev_dbg(ntodev(netdev), "IW_AUTH_UNKNOWN flags:%x\n", param->flags);
> +		ret = -EOPNOTSUPP;
> +	}
> +
> +	return ret;
> +}
> +
> +static int gelicw_get_auth(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_param *param = &wrqu->param;
> +
> +	dev_dbg(ntodev(netdev), "wx:get_auth\n");
> +	switch(param->flags & IW_AUTH_INDEX) {
> +	case IW_AUTH_80211_AUTH_ALG:
> +		param->value = w->auth_mode;
> +		break;
> +	case IW_AUTH_WPA_ENABLED:
> +		if ((w->key_alg & IW_ENCODE_ALG_TKIP) ||
> +		    (w->key_alg & IW_ENCODE_ALG_CCMP))
> +			param->value = 1;
> +		else
> +			param->value = 0;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return 0;
> +}
> +
> +static int gelicw_set_encodeext(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_point *enc = &wrqu->encoding;
> +	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
> +	int i, index, key_index;
> +
> +	dev_dbg(ntodev(netdev), "wx:set_encodeext\n");
> +	index = enc->flags & IW_ENCODE_INDEX;
> +	if (index < 0 || index > WEP_KEYS)
> +		return -EINVAL;
> +
> +	index--;
> +	if (ext->key_len > IW_ENCODING_TOKEN_MAX)
> +		return -EINVAL;
> +
> +	if (index != -1)
> +		w->key_index = index;
> +	key_index = w->key_index;
> +
> +	if (enc->flags & IW_ENCODE_DISABLED) {
> +		/* disable encryption */
> +		if (index == -1) {
> +			/* disable all */
> +			w->key_alg = IW_ENCODE_ALG_NONE;
> +			for (i = 0; i < WEP_KEYS; i++)
> +				w->key_len[i] = 0;
> +		} else
> +			w->key_len[key_index] = 0;
> +	} else if (enc->flags & IW_ENCODE_NOKEY)
> +		/* key not changed */
> +		w->key_alg = ext->alg;
> +	else {
> +		w->key_len[key_index] = ext->key_len;
> +		w->key_alg = ext->alg;
> +		if (w->key_alg != IW_ENCODE_ALG_NONE && w->key_len[key_index])
> +			memcpy(w->key[key_index], ext->key, w->key_len[key_index]);
> +	}
> +	dev_dbg(ntodev(netdev), "key %d len:%d alg:%x\n",\
> +		key_index, w->key_len[key_index], w->key_alg);
> +
> +	if (w->state >= GELICW_STATE_SCAN_DONE &&
> +	    w->cmd_send_flg == 0 && w->essid_len)
> +		/* scan essid and set other params */
> +		schedule_delayed_work(&w->work_scan_essid, 0);
> +	else
> +		schedule_delayed_work(&w->work_encode, 0);
> +
> +	return 0;
> +}
> +
> +static int gelicw_get_encodeext(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	struct iw_point *enc = &wrqu->encoding;
> +	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
> +	int index, key_index, key_len;
> +
> +	dev_dbg(ntodev(netdev), "wx:get_encodeext\n");
> +	key_len = enc->length - sizeof(*ext);
> +	if (key_len < 0)
> +		return -EINVAL;
> +
> +	index = enc->flags & IW_ENCODE_INDEX;
> +	if (index < 0 || index > WEP_KEYS)
> +		return -EINVAL;
> +
> +	index--;
> +	key_index = (index == -1 ? w->key_index : index);
> +
> +	memset(ext, 0, sizeof(*ext));
> +	enc->flags = key_index + 1;
> +
> +	if (w->key_alg == IW_ENCODE_ALG_NONE || !w->key_len[key_index]) {
> +		/* no encryption */
> +		enc->flags |= IW_ENCODE_DISABLED;
> +		ext->alg = IW_ENCODE_ALG_NONE;
> +		ext->key_len = 0;
> +	} else {
> +		enc->flags |= IW_ENCODE_NOKEY;
> +		ext->alg = w->key_alg;
> +		ext->key_len = w->key_len[key_index];
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * wireless stats
> + */
> +static struct iw_statistics *gelicw_get_wireless_stats(struct net_device *netdev)
> +{
> +	static struct iw_statistics wstats;
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +
> +	dev_dbg(ntodev(netdev), "wx:wireless_stats\n");
> +	if (w->state < GELICW_STATE_ASSOCIATED) {
> +		wstats.qual.updated  = IW_QUAL_QUAL_UPDATED |
> +				IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID;
> +		wstats.qual.qual = 0;
> +		wstats.qual.level = 0;
> +		return &wstats;
> +	}
> +	init_completion(&w->rssi_done);
> +	schedule_delayed_work(&w->work_rssi, 0);
> +
> +	wait_for_completion_interruptible(&w->rssi_done);
> +	wstats.qual.updated  = IW_QUAL_QUAL_UPDATED |
> +			IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID;
> +	wstats.qual.qual = w->rssi;
> +	wstats.qual.level = gelicw_qual2level(w->rssi);
> +
> +	return &wstats;
> +}
> +
> +/*
> + * private handler
> + */
> +static int gelicw_priv_set_alg_mode(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	int mode = *(int *)extra;
> +
> +	dev_dbg(ntodev(netdev), "wx:priv_set_alg\n");
> +	switch (mode) {
> +	case IW_ENCODE_ALG_NONE:
> +	case IW_ENCODE_ALG_WEP:
> +	case IW_ENCODE_ALG_TKIP:
> +	case IW_ENCODE_ALG_CCMP:
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	/* send common config */
> +	gelicw_send_common_config(netdev, &w->key_alg, (u8)mode);
> +
> +	return 0;
> +}
> +
> +static int gelicw_priv_get_alg_mode(struct net_device *netdev,
> +			   struct iw_request_info *info,
> +			   union iwreq_data *wrqu, char *extra)
> +{
> +	struct gelic_wireless *w = gelicw_priv(netdev);
> +	char *p;
> +
> +	dev_dbg(ntodev(netdev), "wx:priv_get_alg\n");
> +	switch (w->key_alg) {
> +	case IW_ENCODE_ALG_NONE:
> +		strncpy(extra, "OFF", MAX_IW_PRIV_SIZE);
> +		break;
> +	case IW_ENCODE_ALG_WEP:
> +		strncpy(extra, "WEP", MAX_IW_PRIV_SIZE);
> +		break;
> +	case IW_ENCODE_ALG_TKIP:
> +		strncpy(extra, "TKIP", MAX_IW_PRIV_SIZE);
> +		break;
> +	case IW_ENCODE_ALG_CCMP:
> +		strncpy(extra, "AES-CCMP", MAX_IW_PRIV_SIZE);
> +		break;
> +	default:
> +		break;
> +	}
> +	p = extra + strlen(extra);
> +
> +	if (w->key_alg == IW_ENCODE_ALG_TKIP ||
> +	    w->key_alg == IW_ENCODE_ALG_CCMP) {
> +		if (w->key_len[w->key_index] == 64) /* current key index */
> +			strncpy(p, " hex", MAX_IW_PRIV_SIZE);
> +		else
> +			strncpy(p, " passphrase", MAX_IW_PRIV_SIZE);
> +	}
> +	wrqu->data.length = strlen(extra);
> +
> +	return 0;
> +}
> +
> +
> +/*
> + * Wireless handlers
> + */
> +static const iw_handler gelicw_handler[] =
> +{
> +	[IW_IOCTL_IDX(SIOCGIWNAME)]      = gelicw_get_name,
> +	[IW_IOCTL_IDX(SIOCSIWFREQ)]      = gelicw_set_freq,
> +	[IW_IOCTL_IDX(SIOCGIWFREQ)]      = gelicw_get_freq,
> +	[IW_IOCTL_IDX(SIOCSIWMODE)]      = gelicw_set_mode,
> +	[IW_IOCTL_IDX(SIOCGIWMODE)]      = gelicw_get_mode,
> +	[IW_IOCTL_IDX(SIOCGIWRANGE)]     = gelicw_get_range,
> +	[IW_IOCTL_IDX(SIOCSIWAP)]        = gelicw_set_wap,
> +	[IW_IOCTL_IDX(SIOCGIWAP)]        = gelicw_get_wap,
> +	[IW_IOCTL_IDX(SIOCSIWSCAN)]      = gelicw_set_scan,
> +	[IW_IOCTL_IDX(SIOCGIWSCAN)]      = gelicw_get_scan,
> +	[IW_IOCTL_IDX(SIOCSIWESSID)]     = gelicw_set_essid,
> +	[IW_IOCTL_IDX(SIOCGIWESSID)]     = gelicw_get_essid,
> +	[IW_IOCTL_IDX(SIOCSIWNICKN)]     = gelicw_set_nick,
> +	[IW_IOCTL_IDX(SIOCGIWNICKN)]     = gelicw_get_nick,
> +	[IW_IOCTL_IDX(SIOCSIWRATE)]      = gelicw_set_rate,
> +	[IW_IOCTL_IDX(SIOCGIWRATE)]      = gelicw_get_rate,
> +	[IW_IOCTL_IDX(SIOCSIWENCODE)]    = gelicw_set_encode,
> +	[IW_IOCTL_IDX(SIOCGIWENCODE)]    = gelicw_get_encode,
> +	[IW_IOCTL_IDX(SIOCSIWAUTH)]      = gelicw_set_auth,
> +	[IW_IOCTL_IDX(SIOCGIWAUTH)]      = gelicw_get_auth,
> +	[IW_IOCTL_IDX(SIOCSIWENCODEEXT)] = gelicw_set_encodeext,
> +	[IW_IOCTL_IDX(SIOCGIWENCODEEXT)] = gelicw_get_encodeext,
> +};
> +
> +/*
> + * Private wireless handlers
> + */
> +enum {
> +	GELICW_PRIV_SET_AUTH  = SIOCIWFIRSTPRIV,
> +	GELICW_PRIV_GET_AUTH
> +};
> +
> +static struct iw_priv_args gelicw_private_args[] = {
> +	{
> +	 .cmd = GELICW_PRIV_SET_AUTH,
> +	 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
> +	 .name = "set_alg"
> +	},
> +	{
> +	 .cmd = GELICW_PRIV_GET_AUTH,
> +	 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_IW_PRIV_SIZE,
> +	 .name = "get_alg"
> +	},
> +};
> +
> +static const iw_handler gelicw_private_handler[] =
> +{
> +	gelicw_priv_set_alg_mode,
> +	gelicw_priv_get_alg_mode,
> +};
> +
> +static struct iw_handler_def gelicw_handler_def =
> +{
> +	.num_standard	= ARRAY_SIZE(gelicw_handler),
> +	.num_private	= ARRAY_SIZE(gelicw_private_handler),
> +	.num_private_args = ARRAY_SIZE(gelicw_private_args),
> +	.standard	= (iw_handler *)gelicw_handler,
> +	.private	= (iw_handler *)gelicw_private_handler,
> +	.private_args	= (struct iw_priv_args *)gelicw_private_args,
> +	.get_wireless_stats = gelicw_get_wireless_stats
> +};
> 
> --
> Masakazu MOKUNO
> 
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists