#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <net/iw_handler.h>
-#include <net/ieee80211.h>
#include <linux/dma-mapping.h>
#include <net/checksum.h>
#include "ps3_gelic_wireless.h"
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan);
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+ u8 *essid, size_t essid_len);
static int gelic_wl_try_associate(struct net_device *netdev);
/*
[GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1},
+ [GELIC_EURUS_CMD_START_SCAN] = { .pre_arg = 1},
[GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1},
};
card = port_to_card(wl_port(wl));
if (cmd_info[cmd->cmd].pre_arg) {
- arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
+ arg1 = (cmd->buffer) ?
+ ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
+ 0;
arg2 = cmd->buf_size;
} else {
arg1 = 0;
range->num_encoding_sizes = 3;
range->max_encoding_tokens = GELIC_WEP_KEYS;
+ /* scan capability */
+ range->scan_capa = IW_SCAN_CAPA_ESSID;
+
pr_debug("%s: ->\n", __func__);
return 0;
union iwreq_data *wrqu, char *extra)
{
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-
- return gelic_wl_start_scan(wl, 1);
+ struct iw_scan_req *req;
+ u8 *essid = NULL;
+ size_t essid_len = 0;
+
+ if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+ wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ req = (struct iw_scan_req*)extra;
+ essid = req->essid;
+ essid_len = req->essid_len;
+ pr_debug("%s: ESSID scan =%s\n", __func__, essid);
+ }
+ return gelic_wl_start_scan(wl, 1, essid, essid_len);
}
#define OUI_LEN 3
/* element id */
if (rsn)
- *buf++ = MFIE_TYPE_RSN;
+ *buf++ = WLAN_EID_RSN;
else
- *buf++ = MFIE_TYPE_GENERIC;
+ *buf++ = WLAN_EID_GENERIC;
/* length filed; set later */
buf++;
break;
switch (item_id) {
- case MFIE_TYPE_GENERIC:
+ case WLAN_EID_GENERIC:
if ((OUI_LEN + 1 <= item_len) &&
!memcmp(pos, wpa_oui, OUI_LEN) &&
pos[OUI_LEN] == 0x01) {
ie_info->wpa.len = item_len + 2;
}
break;
- case MFIE_TYPE_RSN:
+ case WLAN_EID_RSN:
ie_info->rsn.data = pos - 2;
/* length includes the header */
ie_info->rsn.len = item_len + 2;
* independent format
*/
static char *gelic_wl_translate_scan(struct net_device *netdev,
+ struct iw_request_info *info,
char *ev,
char *stop,
struct gelic_wl_scan_info *network)
char *tmp;
u8 rate;
unsigned int i, j, len;
- u8 buf[MAX_WPA_IE_LEN];
+ u8 buf[64]; /* arbitrary size large enough */
pr_debug("%s: <-\n", __func__);
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
- ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN);
+ ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN);
/* ESSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
iwe.u.data.length = strnlen(scan->essid, 32);
- ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
+ ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
/* FREQUENCY */
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = be16_to_cpu(scan->channel);
iwe.u.freq.e = 0; /* table value in MHz */
iwe.u.freq.i = 0;
- ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN);
+ ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN);
/* RATES */
iwe.cmd = SIOCGIWRATE;
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
/* to stuff multiple values in one event */
- tmp = ev + IW_EV_LCP_LEN;
+ tmp = ev + iwe_stream_lcp_len(info);
/* put them in ascendant order (older is first) */
i = 0;
j = 0;
else
rate = scan->rate[i++] & 0x7f;
iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
- tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
+ tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
IW_EV_PARAM_LEN);
}
while (j < network->rate_ext_len) {
iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
- tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
+ tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
IW_EV_PARAM_LEN);
}
/* Check if we added any rate */
- if (IW_EV_LCP_LEN < (tmp - ev))
+ if (iwe_stream_lcp_len(info) < (tmp - ev))
ev = tmp;
/* ENCODE */
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
- ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
+ ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
/* MODE */
iwe.cmd = SIOCGIWMODE;
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
- ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN);
+ ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN);
}
/* QUAL */
iwe.u.qual.level = be16_to_cpu(scan->rssi);
iwe.u.qual.qual = be16_to_cpu(scan->rssi);
iwe.u.qual.noise = 0;
- ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN);
+ ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN);
/* RSN */
memset(&iwe, 0, sizeof(iwe));
if (len) {
iwe.cmd = IWEVGENIE;
iwe.u.data.length = len;
- ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+ ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
}
} else {
/* this scan info has IE data */
memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = ie_info.wpa.len;
- ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+ ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
}
if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = ie_info.rsn.len;
- ev = iwe_stream_add_point(ev, stop, &iwe, buf);
+ ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
}
}
if (wl->scan_age == 0 ||
time_after(scan_info->last_scanned + wl->scan_age,
this_time))
- ev = gelic_wl_translate_scan(netdev, ev, stop,
+ ev = gelic_wl_translate_scan(netdev, info,
+ ev, stop,
scan_info);
else
pr_debug("%s:entry too old\n", __func__);
{
struct gelic_wl_scan_info *scan_info;
int i;
- DECLARE_MAC_BUF(mac);
i = 0;
list_for_each_entry(scan_info, &wl->network_list, list) {
scan_info->rate_len, scan_info->rate_ext_len,
scan_info->essid_len);
/* -- */
- pr_debug("bssid=%s\n",
- print_mac(mac, &scan_info->hwinfo->bssid[2]));
+ pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]);
pr_debug("essid=%s\n", scan_info->hwinfo->essid);
}
}
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
struct iw_point *enc = &data->encoding;
__u16 flags;
- unsigned int irqflag;
+ unsigned long irqflag;
int key_index, index_specified;
int ret = 0;
{
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
struct iw_point *enc = &data->encoding;
- unsigned int irqflag;
+ unsigned long irqflag;
unsigned int key_index, index_specified;
int ret = 0;
ETH_ALEN);
set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
- pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n",
- __func__,
- wl->bssid[0], wl->bssid[1],
- wl->bssid[2], wl->bssid[3],
- wl->bssid[4], wl->bssid[5]);
+ pr_debug("%s: bss=%pM\n", __func__, wl->bssid);
} else {
pr_debug("%s: clear bssid\n", __func__);
clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
__u16 alg;
__u16 flags;
- unsigned int irqflag;
+ unsigned long irqflag;
int key_index;
int ret = 0;
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
struct iw_point *enc = &data->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- unsigned int irqflag;
+ unsigned long irqflag;
int key_index;
int ret = 0;
int max_key_len;
return 0;
}
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
/* SIOCIWFIRSTPRIV */
static int hex2bin(u8 *str, u8 *bin, unsigned int len)
{
{
struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
unsigned int len;
- unsigned int irqflag;
+ unsigned long irqflag;
int ret = 0;
pr_debug("%s:<- len=%d\n", __func__, data->data.length);
{
struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
char *p;
- unsigned int irqflag;
+ unsigned long irqflag;
unsigned int i;
pr_debug("%s:<-\n", __func__);
pr_debug("%s:-> %d\n", __func__, data->data.length);
return 0;
}
+#endif
/* SIOCGIWNICKN */
static int gelic_wl_get_nick(struct net_device *net_dev,
/*
* scanning helpers
*/
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+ u8 *essid, size_t essid_len)
{
struct gelic_eurus_cmd *cmd;
int ret = 0;
+ void *buf = NULL;
+ size_t len;
pr_debug("%s: <- always=%d\n", __func__, always_scan);
if (mutex_lock_interruptible(&wl->scan_lock))
complete(&wl->scan_done);
goto out;
}
+
+ /* ESSID scan ? */
+ if (essid_len && essid) {
+ buf = (void *)__get_free_page(GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
+ memset(buf, 0, len);
+ memcpy(buf, essid, essid_len);
+ pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
+ } else
+ len = 0;
+
/*
* issue start scan request
*/
wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
- NULL, 0);
+ buf, len);
if (!cmd || cmd->status || cmd->cmd_status) {
wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
complete(&wl->scan_done);
}
kfree(cmd);
out:
+ free_page((unsigned long)buf);
mutex_unlock(&wl->scan_lock);
pr_debug("%s: ->\n", __func__);
return ret;
unsigned long this_time = jiffies;
unsigned int data_len, i, found, r;
void *buf;
- DECLARE_MAC_BUF(mac);
pr_debug("%s:start\n", __func__);
mutex_lock(&wl->scan_lock);
scan_info_size < data_len;
i++, scan_info_size += be16_to_cpu(scan_info->size),
scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
- pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__,
+ pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__,
be16_to_cpu(scan_info->size),
- print_mac(mac, &scan_info->bssid[2]), scan_info);
+ &scan_info->bssid[2], scan_info);
/*
* The wireless firmware may return invalid channel 0 and/or
target->essid_len = strnlen(scan_info->essid,
sizeof(scan_info->essid));
target->rate_len = 0;
- for (r = 0; r < MAX_RATES_LENGTH; r++)
+ for (r = 0; r < 12; r++)
if (scan_info->rate[r])
target->rate_len++;
if (8 < target->rate_len)
pr_info("%s: AP returns %d rates\n", __func__,
target->rate_len);
target->rate_ext_len = 0;
- for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
+ for (r = 0; r < 16; r++)
if (scan_info->ext_rate[r])
target->rate_ext_len++;
list_move_tail(&target->list, &wl->network_list);
struct gelic_wl_scan_info *best_bss;
int weight, best_weight;
u16 security;
- DECLARE_MAC_BUF(mac);
pr_debug("%s: <-\n", __func__);
#ifdef DEBUG
pr_debug("%s: -> bss=%p\n", __func__, best_bss);
if (best_bss) {
- pr_debug("%s:addr=%s\n", __func__,
- print_mac(mac, &best_bss->hwinfo->bssid[2]));
+ pr_debug("%s:addr=%pM\n", __func__,
+ &best_bss->hwinfo->bssid[2]);
}
#endif
return best_bss;
if (ret) {
pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
ret);
+ ret = -EPERM;
+ gelic_wl_send_iwap_event(wl, NULL);
+ goto out;
}
/* start association */
complete(&wl->assoc_done);
netif_carrier_on(port_to_netdev(wl_port(wl)));
} else
- pr_debug("%s: event %#lx under wpa\n",
+ pr_debug("%s: event %#llx under wpa\n",
__func__, event);
}
struct gelic_wl_scan_info *best_bss;
int ret;
+ unsigned long irqflag;
+ u8 *essid;
+ size_t essid_len;
wl = container_of(work, struct gelic_wl_info, assoc_work.work);
if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
goto out;
- ret = gelic_wl_start_scan(wl, 0);
+ spin_lock_irqsave(&wl->lock, irqflag);
+ if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
+ pr_debug("%s: assoc ESSID configured %s\n", __func__,
+ wl->essid);
+ essid = wl->essid;
+ essid_len = wl->essid_len;
+ } else {
+ essid = NULL;
+ essid_len = 0;
+ }
+ spin_unlock_irqrestore(&wl->lock, irqflag);
+
+ ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
if (ret == -ERESTARTSYS) {
pr_debug("%s: scan start failed association\n", __func__);
schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick,
};
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
static struct iw_priv_args gelic_wl_private_args[] =
{
{
gelic_wl_priv_set_psk,
gelic_wl_priv_get_psk,
};
+#endif
static const struct iw_handler_def gelic_wl_wext_handler_def = {
.num_standard = ARRAY_SIZE(gelic_wl_wext_handler),
.standard = gelic_wl_wext_handler,
.get_wireless_stats = gelic_wl_get_wireless_stats,
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
.num_private = ARRAY_SIZE(gelic_wl_private_handler),
.num_private_args = ARRAY_SIZE(gelic_wl_private_args),
.private = gelic_wl_private_handler,
.private_args = gelic_wl_private_args,
+#endif
};
-static struct net_device *gelic_wl_alloc(struct gelic_card *card)
+static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
{
struct net_device *netdev;
struct gelic_port *port;
/* -- */
-static struct ethtool_ops gelic_wl_ethtool_ops = {
+static const struct net_device_ops gelic_wl_netdevice_ops = {
+ .ndo_open = gelic_wl_open,
+ .ndo_stop = gelic_wl_stop,
+ .ndo_start_xmit = gelic_net_xmit,
+ .ndo_set_multicast_list = gelic_net_set_multi,
+ .ndo_change_mtu = gelic_net_change_mtu,
+ .ndo_tx_timeout = gelic_net_tx_timeout,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = gelic_net_poll_controller,
+#endif
+};
+
+static const struct ethtool_ops gelic_wl_ethtool_ops = {
.get_drvinfo = gelic_net_get_drvinfo,
.get_link = gelic_wl_get_link,
.get_tx_csum = ethtool_op_get_tx_csum,
.set_rx_csum = gelic_net_set_rx_csum,
};
-static void gelic_wl_setup_netdev_ops(struct net_device *netdev)
+static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev)
{
struct gelic_wl_info *wl;
wl = port_wl(netdev_priv(netdev));
BUG_ON(!wl);
- netdev->open = &gelic_wl_open;
- netdev->stop = &gelic_wl_stop;
- netdev->hard_start_xmit = &gelic_net_xmit;
- netdev->set_multicast_list = &gelic_net_set_multi;
- netdev->change_mtu = &gelic_net_change_mtu;
- netdev->wireless_data = &wl->wireless_data;
- netdev->wireless_handlers = &gelic_wl_wext_handler_def;
- /* tx watchdog */
- netdev->tx_timeout = &gelic_net_tx_timeout;
netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
netdev->ethtool_ops = &gelic_wl_ethtool_ops;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- netdev->poll_controller = gelic_net_poll_controller;
-#endif
+ netdev->netdev_ops = &gelic_wl_netdevice_ops;
+ netdev->wireless_data = &wl->wireless_data;
+ netdev->wireless_handlers = &gelic_wl_wext_handler_def;
}
/*
* driver probe/remove
*/
-int gelic_wl_driver_probe(struct gelic_card *card)
+int __devinit gelic_wl_driver_probe(struct gelic_card *card)
{
int ret;
struct net_device *netdev;