2002-02-04 19:02:30

by Jean Tourrilhes

[permalink] [raw]
Subject: [PATCH 2.5.3] wavelan_cs.c : new WE api

Jeff,

Same story, just forward to Linus...

This update the wavelan_cs driver in 2.5.3 to the new wireless
API. This also fixes the copy_to/from_user() done with irq disabled
(so Alan will be happy). Tested on 2.5.3.

Have fun...

Jean

-----------------------------------------------------

diff -u -p -r linux/drivers/net/wireless-w12/wavelan_cs.c linux/drivers/net/wireless/wavelan_cs.c
--- linux/drivers/net/wireless-w12/wavelan_cs.c Wed Jan 23 16:41:28 2002
+++ linux/drivers/net/wireless/wavelan_cs.c Wed Jan 23 16:59:27 2002
@@ -1884,557 +1884,1234 @@ wl_his_gather(device * dev,

/*------------------------------------------------------------------*/
/*
- * Perform ioctl : config & info stuff
- * This is here that are treated the wireless extensions (iwconfig)
+ * Wireless Handler : get protocol name
*/
-static int
-wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
- struct ifreq * rq, /* Data passed */
- int cmd) /* Ioctl number */
+static int wavelan_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
{
- ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *)dev->priv; /* lp is not unused */
- struct iwreq * wrq = (struct iwreq *) rq;
- psa_t psa;
- mm_t m;
- unsigned long flags;
- int ret = 0;
-
-#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
-#endif
-
- /* Disable interrupts & save flags */
- wv_splhi(lp, &flags);
-
- /* Look what is the request */
- switch(cmd)
- {
- /* --------------- WIRELESS EXTENSIONS --------------- */
-
- case SIOCGIWNAME:
- strcpy(wrq->u.name, "Wavelan");
- break;
+ strcpy(wrqu->name, "WaveLAN");
+ return 0;
+}

- case SIOCSIWNWID:
- /* Set NWID in wavelan */
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set NWID
+ */
+static int wavelan_set_nwid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ mm_t m;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Set NWID in WaveLAN. */
#if WIRELESS_EXT > 8
- if(!wrq->u.nwid.disabled)
- {
- /* Set NWID in psa */
- psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
- psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+ if (!wrqu->nwid.disabled) {
+ /* Set NWID in psa */
+ psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
+ psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
#else /* WIRELESS_EXT > 8 */
- if(wrq->u.nwid.on)
- {
- /* Set NWID in psa */
- psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
- psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
+ if(wrq->u.nwid.on) {
+ /* Set NWID in psa */
+ psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
+ psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
#endif /* WIRELESS_EXT > 8 */
- psa.psa_nwid_select = 0x01;
- psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
- (unsigned char *)psa.psa_nwid, 3);
-
- /* Set NWID in mmc */
- m.w.mmw_netw_id_l = psa.psa_nwid[1];
- m.w.mmw_netw_id_h = psa.psa_nwid[0];
- mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m,
- (unsigned char *)&m.w.mmw_netw_id_l, 2);
- mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
+ psa.psa_nwid_select = 0x01;
+ psa_write(dev,
+ (char *) psa.psa_nwid - (char *) &psa,
+ (unsigned char *) psa.psa_nwid, 3);
+
+ /* Set NWID in mmc. */
+ m.w.mmw_netw_id_l = psa.psa_nwid[1];
+ m.w.mmw_netw_id_h = psa.psa_nwid[0];
+ mmc_write(base,
+ (char *) &m.w.mmw_netw_id_l -
+ (char *) &m,
+ (unsigned char *) &m.w.mmw_netw_id_l, 2);
+ mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
+ } else {
+ /* Disable NWID in the psa. */
+ psa.psa_nwid_select = 0x00;
+ psa_write(dev,
+ (char *) &psa.psa_nwid_select -
+ (char *) &psa,
+ (unsigned char *) &psa.psa_nwid_select,
+ 1);
+
+ /* Disable NWID in the mmc (no filtering). */
+ mmc_out(base, mmwoff(0, mmw_loopt_sel),
+ MMW_LOOPT_SEL_DIS_NWID);
}
- else
- {
- /* Disable nwid in the psa */
- psa.psa_nwid_select = 0x00;
- psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
- (unsigned char *)&psa.psa_nwid_select, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev);

- /* Disable nwid in the mmc (no filtering) */
- mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
- }
- /* update the Wavelan checksum */
- update_psa_checksum(dev);
- break;
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);

- case SIOCGIWNWID:
- /* Read the NWID */
- psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
- (unsigned char *)psa.psa_nwid, 3);
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get NWID
+ */
+static int wavelan_get_nwid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Read the NWID. */
+ psa_read(dev,
+ (char *) psa.psa_nwid - (char *) &psa,
+ (unsigned char *) psa.psa_nwid, 3);
#if WIRELESS_EXT > 8
- wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
- wrq->u.nwid.disabled = !(psa.psa_nwid_select);
- wrq->u.nwid.fixed = 1; /* Superfluous */
+ wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+ wrqu->nwid.disabled = !(psa.psa_nwid_select);
+ wrqu->nwid.fixed = 1; /* Superfluous */
#else /* WIRELESS_EXT > 8 */
- wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
- wrq->u.nwid.on = psa.psa_nwid_select;
+ wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+ wrq->u.nwid.on = psa.psa_nwid_select;
#endif /* WIRELESS_EXT > 8 */
- break;

- case SIOCSIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
- if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- ret = wv_set_frequency(base, &(wrq->u.freq));
- else
- ret = -EOPNOTSUPP;
- break;
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);

- case SIOCGIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ? - especially old cards...) */
- if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- {
- unsigned short freq;
-
- /* Ask the EEprom to read the frequency from the first area */
- fee_read(base, 0x00 /* 1st area - frequency... */,
- &freq, 1);
- wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
- wrq->u.freq.e = 1;
- }
- else
- {
- psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
- (unsigned char *)&psa.psa_subband, 1);
+ return ret;
+}

- if(psa.psa_subband <= 4)
- {
- wrq->u.freq.m = fixed_bands[psa.psa_subband];
- wrq->u.freq.e = (psa.psa_subband != 0);
- }
- else
- ret = -EOPNOTSUPP;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set frequency
+ */
+static int wavelan_set_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ unsigned long flags;
+ int ret;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+ if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+ ret = wv_set_frequency(base, &(wrqu->freq));
+ else
+ ret = -EOPNOTSUPP;
+
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get frequency
+ */
+static int wavelan_get_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+ * Does it work for everybody, especially old cards? */
+ if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+ unsigned short freq;
+
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(base, 0x00, &freq, 1);
+ wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+ wrqu->freq.e = 1;
+ } else {
+ psa_read(dev,
+ (char *) &psa.psa_subband - (char *) &psa,
+ (unsigned char *) &psa.psa_subband, 1);
+
+ if (psa.psa_subband <= 4) {
+ wrqu->freq.m = fixed_bands[psa.psa_subband];
+ wrqu->freq.e = (psa.psa_subband != 0);
+ } else
+ ret = -EOPNOTSUPP;
}
- break;

- case SIOCSIWSENS:
- /* Set the level threshold */
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set level threshold
+ */
+static int wavelan_set_sens(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Set the level threshold. */
#if WIRELESS_EXT > 7
- /* We should complain loudly if wrq->u.sens.fixed = 0, because we
- * can't set auto mode... */
- psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+ /* We should complain loudly if wrqu->sens.fixed = 0, because we
+ * can't set auto mode... */
+ psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
#else /* WIRELESS_EXT > 7 */
- psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
+ psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
#endif /* WIRELESS_EXT > 7 */
- psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
- (unsigned char *)&psa.psa_thr_pre_set, 1);
- /* update the Wavelan checksum */
- update_psa_checksum(dev);
- mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
- break;
+ psa_write(dev,
+ (char *) &psa.psa_thr_pre_set - (char *) &psa,
+ (unsigned char *) &psa.psa_thr_pre_set, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev);
+ mmc_out(base, mmwoff(0, mmw_thr_pre_set),
+ psa.psa_thr_pre_set);

- case SIOCGIWSENS:
- /* Read the level threshold */
- psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
- (unsigned char *)&psa.psa_thr_pre_set, 1);
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get level threshold
+ */
+static int wavelan_get_sens(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Read the level threshold. */
+ psa_read(dev,
+ (char *) &psa.psa_thr_pre_set - (char *) &psa,
+ (unsigned char *) &psa.psa_thr_pre_set, 1);
#if WIRELESS_EXT > 7
- wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
- wrq->u.sens.fixed = 1;
+ wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
+ wrqu->sens.fixed = 1;
#else /* WIRELESS_EXT > 7 */
- wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
+ wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
#endif /* WIRELESS_EXT > 7 */
- break;
+
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}

#if WIRELESS_EXT > 8
- case SIOCSIWENCODE:
- /* Set encryption key */
- if(!mmc_encr(base))
- {
- ret = -EOPNOTSUPP;
- break;
- }
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set encryption key
+ */
+static int wavelan_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ unsigned long flags;
+ psa_t psa;
+ int ret = 0;

- /* Basic checking... */
- if(wrq->u.encoding.pointer != (caddr_t) 0)
- {
- /* Check the size of the key */
- if(wrq->u.encoding.length != 8)
- {
- ret = -EINVAL;
- break;
- }
-
- /* Copy the key in the driver */
- if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
- wrq->u.encoding.length))
- {
- ret = -EFAULT;
- break;
- }
-
- psa.psa_encryption_select = 1;
- psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
- (unsigned char *) &psa.psa_encryption_select, 8+1);
-
- mmc_out(base, mmwoff(0, mmw_encr_enable),
- MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
- mmc_write(base, mmwoff(0, mmw_encr_key),
- (unsigned char *) &psa.psa_encryption_key, 8);
- }
-
- if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
- { /* disable encryption */
- psa.psa_encryption_select = 0;
- psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
- (unsigned char *) &psa.psa_encryption_select, 1);
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);

- mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
+ /* Check if capable of encryption */
+ if (!mmc_encr(base)) {
+ ret = -EOPNOTSUPP;
}
- /* update the Wavelan checksum */
- update_psa_checksum(dev);
- break;

- case SIOCGIWENCODE:
- /* Read the encryption key */
- if(!mmc_encr(base))
- {
- ret = -EOPNOTSUPP;
- break;
+ /* Check the size of the key */
+ if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
+ ret = -EINVAL;
}

- /* only super-user can see encryption key */
- if(!capable(CAP_NET_ADMIN))
- {
- ret = -EPERM;
- break;
+ if(!ret) {
+ /* Basic checking... */
+ if (wrqu->encoding.length == 8) {
+ /* Copy the key in the driver */
+ memcpy(psa.psa_encryption_key, extra,
+ wrqu->encoding.length);
+ psa.psa_encryption_select = 1;
+
+ psa_write(dev,
+ (char *) &psa.psa_encryption_select -
+ (char *) &psa,
+ (unsigned char *) &psa.
+ psa_encryption_select, 8 + 1);
+
+ mmc_out(base, mmwoff(0, mmw_encr_enable),
+ MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+ mmc_write(base, mmwoff(0, mmw_encr_key),
+ (unsigned char *) &psa.
+ psa_encryption_key, 8);
+ }
+
+ /* disable encryption */
+ if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
+ psa.psa_encryption_select = 0;
+ psa_write(dev,
+ (char *) &psa.psa_encryption_select -
+ (char *) &psa,
+ (unsigned char *) &psa.
+ psa_encryption_select, 1);
+
+ mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
+ }
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev);
}

- /* Basic checking... */
- if(wrq->u.encoding.pointer != (caddr_t) 0)
- {
- psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
- (unsigned char *) &psa.psa_encryption_select, 1+8);
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);

- /* encryption is enabled ? */
- if(psa.psa_encryption_select)
- wrq->u.encoding.flags = IW_ENCODE_ENABLED;
- else
- wrq->u.encoding.flags = IW_ENCODE_DISABLED;
- wrq->u.encoding.flags |= mmc_encr(base);
-
- /* Copy the key to the user buffer */
- wrq->u.encoding.length = 8;
- if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
- ret = -EFAULT;
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get encryption key
+ */
+static int wavelan_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Check if encryption is available */
+ if (!mmc_encr(base)) {
+ ret = -EOPNOTSUPP;
+ } else {
+ /* Read the encryption key */
+ psa_read(dev,
+ (char *) &psa.psa_encryption_select -
+ (char *) &psa,
+ (unsigned char *) &psa.
+ psa_encryption_select, 1 + 8);
+
+ /* encryption is enabled ? */
+ if (psa.psa_encryption_select)
+ wrqu->encoding.flags = IW_ENCODE_ENABLED;
+ else
+ wrqu->encoding.flags = IW_ENCODE_DISABLED;
+ wrqu->encoding.flags |= mmc_encr(base);
+
+ /* Copy the key to the user buffer */
+ wrqu->encoding.length = 8;
+ memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
}
- break;
+
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
#endif /* WIRELESS_EXT > 8 */

#ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5
- case SIOCSIWESSID:
- /* Check if disable */
- if(wrq->u.data.flags == 0)
- lp->filter_domains = 0;
- else
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- char essid[IW_ESSID_MAX_SIZE + 1];
- char * endp;
-
- /* Check the size of the string */
- if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
- {
- ret = -E2BIG;
- break;
- }
-
- /* Copy the string in the driver */
- if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
- {
- ret = -EFAULT;
- break;
- }
- essid[IW_ESSID_MAX_SIZE] = '\0';
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set ESSID (domain)
+ */
+static int wavelan_set_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Check if disable */
+ if(wrqu->data.flags == 0)
+ lp->filter_domains = 0;
+ else {
+ char essid[IW_ESSID_MAX_SIZE + 1];
+ char * endp;
+
+ /* Terminate the string */
+ memcpy(essid, extra, wrqu->data.length);
+ essid[IW_ESSID_MAX_SIZE] = '\0';

#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
+ printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
#endif /* DEBUG_IOCTL_INFO */

- /* Convert to a number (note : Wavelan specific) */
- lp->domain_id = simple_strtoul(essid, &endp, 16);
- /* Has it worked ? */
- if(endp > essid)
- lp->filter_domains = 1;
- else
- {
- lp->filter_domains = 0;
- ret = -EINVAL;
- }
- }
- break;
+ /* Convert to a number (note : Wavelan specific) */
+ lp->domain_id = simple_strtoul(essid, &endp, 16);
+ /* Has it worked ? */
+ if(endp > essid)
+ lp->filter_domains = 1;
+ else {
+ lp->filter_domains = 0;
+ ret = -EINVAL;
+ }
+ }

- case SIOCGIWESSID:
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- char essid[IW_ESSID_MAX_SIZE + 1];
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get ESSID (domain)
+ */
+static int wavelan_get_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */

- /* Is the domain ID active ? */
- wrq->u.data.flags = lp->filter_domains;
+ /* Is the domain ID active ? */
+ wrqu->data.flags = lp->filter_domains;

- /* Copy Domain ID into a string (Wavelan specific) */
- /* Sound crazy, be we can't have a snprintf in the kernel !!! */
- sprintf(essid, "%lX", lp->domain_id);
- essid[IW_ESSID_MAX_SIZE] = '\0';
+ /* Copy Domain ID into a string (Wavelan specific) */
+ /* Sound crazy, be we can't have a snprintf in the kernel !!! */
+ sprintf(extra, "%lX", lp->domain_id);
+ extra[IW_ESSID_MAX_SIZE] = '\0';

- /* Set the length */
- wrq->u.data.length = strlen(essid) + 1;
+ /* Set the length */
+ wrqu->data.length = strlen(extra) + 1;

- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
- ret = -EFAULT;
- }
- break;
+ return 0;
+}

- case SIOCSIWAP:
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set AP address
+ */
+static int wavelan_set_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
- wrq->u.ap_addr.sa_data[0],
- wrq->u.ap_addr.sa_data[1],
- wrq->u.ap_addr.sa_data[2],
- wrq->u.ap_addr.sa_data[3],
- wrq->u.ap_addr.sa_data[4],
- wrq->u.ap_addr.sa_data[5]);
+ printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
+ wrqu->ap_addr.sa_data[0],
+ wrqu->ap_addr.sa_data[1],
+ wrqu->ap_addr.sa_data[2],
+ wrqu->ap_addr.sa_data[3],
+ wrqu->ap_addr.sa_data[4],
+ wrqu->ap_addr.sa_data[5]);
#endif /* DEBUG_IOCTL_INFO */

- ret = -EOPNOTSUPP; /* Not supported yet */
- break;
+ return -EOPNOTSUPP;
+}

- case SIOCGIWAP:
- /* Should get the real McCoy instead of own Ethernet address */
- memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
- wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get AP address
+ */
+static int wavelan_get_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ /* Should get the real McCoy instead of own Ethernet address */
+ memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
+ wrqu->ap_addr.sa_family = ARPHRD_ETHER;

- ret = -EOPNOTSUPP; /* Not supported yet */
- break;
+ return -EOPNOTSUPP;
+}
#endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */

#if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING
- case SIOCSIWMODE:
- switch(wrq->u.mode)
- {
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set mode
+ */
+static int wavelan_set_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ unsigned long flags;
+ int ret = 0;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Check mode */
+ switch(wrqu->mode) {
case IW_MODE_ADHOC:
- if(do_roaming)
- {
- wv_roam_cleanup(dev);
- do_roaming = 0;
- }
- break;
+ if(do_roaming) {
+ wv_roam_cleanup(dev);
+ do_roaming = 0;
+ }
+ break;
case IW_MODE_INFRA:
- if(!do_roaming)
- {
- wv_roam_init(dev);
- do_roaming = 1;
- }
- break;
+ if(!do_roaming) {
+ wv_roam_init(dev);
+ do_roaming = 1;
+ }
+ break;
default:
- ret = -EINVAL;
+ ret = -EINVAL;
}
- break;

- case SIOCGIWMODE:
- if(do_roaming)
- wrq->u.mode = IW_MODE_INFRA;
- else
- wrq->u.mode = IW_MODE_ADHOC;
- break;
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get mode
+ */
+static int wavelan_get_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ if(do_roaming)
+ wrqu->mode = IW_MODE_INFRA;
+ else
+ wrqu->mode = IW_MODE_ADHOC;
+
+ return 0;
+}
#endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */

- case SIOCGIWRANGE:
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- struct iw_range range;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get range info
+ */
+static int wavelan_get_range(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ struct iw_range *range = (struct iw_range *) extra;
+ unsigned long flags;
+ int ret = 0;

- /* Set the length (very important for backward compatibility) */
- wrq->u.data.length = sizeof(struct iw_range);
+ /* Set the length (very important for backward compatibility) */
+ wrqu->data.length = sizeof(struct iw_range);

- /* Set all the info we don't care or don't know about to zero */
- memset(&range, 0, sizeof(range));
+ /* Set all the info we don't care or don't know about to zero */
+ memset(range, 0, sizeof(struct iw_range));

#if WIRELESS_EXT > 10
- /* Set the Wireless Extension versions */
- range.we_version_compiled = WIRELESS_EXT;
- range.we_version_source = 9; /* Nothing for us in v10 and v11 */
+ /* Set the Wireless Extension versions */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 9;
#endif /* WIRELESS_EXT > 10 */

- /* Set information in the range struct */
- range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
- range.min_nwid = 0x0000;
- range.max_nwid = 0xFFFF;
-
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
- if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- {
- range.num_channels = 10;
- range.num_frequency = wv_frequency_list(base, range.freq,
- IW_MAX_FREQUENCIES);
- }
- else
- range.num_channels = range.num_frequency = 0;
-
- range.sensitivity = 0x3F;
- range.max_qual.qual = MMR_SGNL_QUAL;
- range.max_qual.level = MMR_SIGNAL_LVL;
- range.max_qual.noise = MMR_SILENCE_LVL;
+ /* Set information in the range struct. */
+ range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
+ range->min_nwid = 0x0000;
+ range->max_nwid = 0xFFFF;
+
+ range->sensitivity = 0x3F;
+ range->max_qual.qual = MMR_SGNL_QUAL;
+ range->max_qual.level = MMR_SIGNAL_LVL;
+ range->max_qual.noise = MMR_SILENCE_LVL;
#if WIRELESS_EXT > 11
- range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
- /* Need to get better values for those two */
- range.avg_qual.level = 30;
- range.avg_qual.noise = 8;
+ range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
+ /* Need to get better values for those two */
+ range->avg_qual.level = 30;
+ range->avg_qual.noise = 8;
#endif /* WIRELESS_EXT > 11 */

#if WIRELESS_EXT > 7
- range.num_bitrates = 1;
- range.bitrate[0] = 2000000; /* 2 Mb/s */
+ range->num_bitrates = 1;
+ range->bitrate[0] = 2000000; /* 2 Mb/s */
#endif /* WIRELESS_EXT > 7 */

+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+ if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+ range->num_channels = 10;
+ range->num_frequency = wv_frequency_list(base, range->freq,
+ IW_MAX_FREQUENCIES);
+ } else
+ range->num_channels = range->num_frequency = 0;
+
#if WIRELESS_EXT > 8
- /* Encryption supported ? */
- if(mmc_encr(base))
- {
- range.encoding_size[0] = 8; /* DES = 64 bits key */
- range.num_encoding_sizes = 1;
- range.max_encoding_tokens = 1; /* Only one key possible */
- }
- else
- {
- range.num_encoding_sizes = 0;
- range.max_encoding_tokens = 0;
- }
+ /* Encryption supported ? */
+ if (mmc_encr(base)) {
+ range->encoding_size[0] = 8; /* DES = 64 bits key */
+ range->num_encoding_sizes = 1;
+ range->max_encoding_tokens = 1; /* Only one key possible */
+ } else {
+ range->num_encoding_sizes = 0;
+ range->max_encoding_tokens = 0;
+ }
#endif /* WIRELESS_EXT > 8 */

- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, &range,
- sizeof(struct iw_range)))
- ret = -EFAULT;
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return ret;
+}
+
+#ifdef WIRELESS_SPY
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set spy list
+ */
+static int wavelan_set_spy(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ struct sockaddr *address = (struct sockaddr *) extra;
+ int i;
+ int ret = 0;
+
+ /* Disable spy while we copy the addresses.
+ * As we don't disable interrupts, we need to do this */
+ lp->spy_number = 0;
+
+ /* Are there are addresses to copy? */
+ if (wrqu->data.length > 0) {
+ /* Copy addresses to the lp structure. */
+ for (i = 0; i < wrqu->data.length; i++) {
+ memcpy(lp->spy_address[i], address[i].sa_data,
+ WAVELAN_ADDR_SIZE);
+ }
+
+ /* Reset structure. */
+ memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+ printk(KERN_DEBUG
+ "SetSpy: set of new addresses is: \n");
+ for (i = 0; i < wrqu->data.length; i++)
+ printk(KERN_DEBUG
+ "%02X:%02X:%02X:%02X:%02X:%02X \n",
+ lp->spy_address[i][0],
+ lp->spy_address[i][1],
+ lp->spy_address[i][2],
+ lp->spy_address[i][3],
+ lp->spy_address[i][4],
+ lp->spy_address[i][5]);
+#endif /* DEBUG_IOCTL_INFO */
}
+
+ /* Now we can set the number of addresses */
+ lp->spy_number = wrqu->data.length;
+
+ return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get spy list
+ */
+static int wavelan_get_spy(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ struct sockaddr *address = (struct sockaddr *) extra;
+ int i;
+
+ /* Set the number of addresses */
+ wrqu->data.length = lp->spy_number;
+
+ /* Copy addresses from the lp structure. */
+ for (i = 0; i < lp->spy_number; i++) {
+ memcpy(address[i].sa_data,
+ lp->spy_address[i],
+ WAVELAN_ADDR_SIZE);
+ address[i].sa_family = AF_UNIX;
+ }
+ /* Copy stats to the user buffer (just after). */
+ if(lp->spy_number > 0)
+ memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number),
+ lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
+
+ /* Reset updated flags. */
+ for (i = 0; i < lp->spy_number; i++)
+ lp->spy_stat[i].updated = 0x0;
+
+ return(0);
+}
+#endif /* WIRELESS_SPY */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : set quality threshold
+ */
+static int wavelan_set_qthr(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ ioaddr_t base = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ psa.psa_quality_thr = *(extra) & 0x0F;
+ psa_write(dev,
+ (char *) &psa.psa_quality_thr - (char *) &psa,
+ (unsigned char *) &psa.psa_quality_thr, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev);
+ mmc_out(base, mmwoff(0, mmw_quality_thr),
+ psa.psa_quality_thr);
+
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get quality threshold
+ */
+static int wavelan_get_qthr(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ psa_t psa;
+ unsigned long flags;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ psa_read(dev,
+ (char *) &psa.psa_quality_thr - (char *) &psa,
+ (unsigned char *) &psa.psa_quality_thr, 1);
+ *(extra) = psa.psa_quality_thr & 0x0F;
+
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return 0;
+}
+
+#ifdef WAVELAN_ROAMING
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : set roaming
+ */
+static int wavelan_set_roam(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ unsigned long flags;
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
+
+ /* Note : should check if user == root */
+ if(do_roaming && (*extra)==0)
+ wv_roam_cleanup(dev);
+ else if(do_roaming==0 && (*extra)!=0)
+ wv_roam_init(dev);
+
+ do_roaming = (*extra);
+
+ /* Enable interrupts and restore flags. */
+ wv_splx(lp, &flags);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get quality threshold
+ */
+static int wavelan_get_roam(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ *(extra) = do_roaming;
+
+ return 0;
+}
+#endif /* WAVELAN_ROAMING */
+
+#ifdef HISTOGRAM
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : set histogram
+ */
+static int wavelan_set_histo(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+
+ /* Check the number of intervals. */
+ if (wrqu->data.length > 16) {
+ return(-E2BIG);
+ }
+
+ /* Disable histo while we copy the addresses.
+ * As we don't disable interrupts, we need to do this */
+ lp->his_number = 0;
+
+ /* Are there ranges to copy? */
+ if (wrqu->data.length > 0) {
+ /* Copy interval ranges to the driver */
+ memcpy(lp->his_range, extra, wrqu->data.length);
+
+ {
+ int i;
+ printk(KERN_DEBUG "Histo :");
+ for(i = 0; i < wrqu->data.length; i++)
+ printk(" %d", lp->his_range[i]);
+ printk("\n");
+ }
+
+ /* Reset result structure. */
+ memset(lp->his_sum, 0x00, sizeof(long) * 16);
+ }
+
+ /* Now we can set the number of ranges */
+ lp->his_number = wrqu->data.length;
+
+ return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get histogram
+ */
+static int wavelan_get_histo(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+
+ /* Set the number of intervals. */
+ wrqu->data.length = lp->his_number;
+
+ /* Give back the distribution statistics */
+ if(lp->his_number > 0)
+ memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number);
+
+ return(0);
+}
+#endif /* HISTOGRAM */
+
+/*------------------------------------------------------------------*/
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const struct iw_priv_args wavelan_private_args[] = {
+/*{ cmd, set_args, get_args, name } */
+ { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
+ { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
+ { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" },
+ { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
+ { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
+ { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
+};
+
+#if WIRELESS_EXT > 12
+
+static const iw_handler wavelan_handler[] =
+{
+ NULL, /* SIOCSIWNAME */
+ wavelan_get_name, /* SIOCGIWNAME */
+ wavelan_set_nwid, /* SIOCSIWNWID */
+ wavelan_get_nwid, /* SIOCGIWNWID */
+ wavelan_set_freq, /* SIOCSIWFREQ */
+ wavelan_get_freq, /* SIOCGIWFREQ */
+#ifdef WAVELAN_ROAMING
+ wavelan_set_mode, /* SIOCSIWMODE */
+ wavelan_get_mode, /* SIOCGIWMODE */
+#else /* WAVELAN_ROAMING */
+ NULL, /* SIOCSIWMODE */
+ NULL, /* SIOCGIWMODE */
+#endif /* WAVELAN_ROAMING */
+ wavelan_set_sens, /* SIOCSIWSENS */
+ wavelan_get_sens, /* SIOCGIWSENS */
+ NULL, /* SIOCSIWRANGE */
+ wavelan_get_range, /* SIOCGIWRANGE */
+ NULL, /* SIOCSIWPRIV */
+ NULL, /* SIOCGIWPRIV */
+ NULL, /* SIOCSIWSTATS */
+ NULL, /* SIOCGIWSTATS */
+#ifdef WIRELESS_SPY
+ wavelan_set_spy, /* SIOCSIWSPY */
+ wavelan_get_spy, /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+ NULL, /* SIOCSIWSPY */
+ NULL, /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+#ifdef WAVELAN_ROAMING_EXT
+ wavelan_set_wap, /* SIOCSIWAP */
+ wavelan_get_wap, /* SIOCGIWAP */
+ NULL, /* -- hole -- */
+ NULL, /* SIOCGIWAPLIST */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ wavelan_set_essid, /* SIOCSIWESSID */
+ wavelan_get_essid, /* SIOCGIWESSID */
+#else /* WAVELAN_ROAMING_EXT */
+ NULL, /* SIOCSIWAP */
+ NULL, /* SIOCGIWAP */
+ NULL, /* -- hole -- */
+ NULL, /* SIOCGIWAPLIST */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ NULL, /* SIOCSIWESSID */
+ NULL, /* SIOCGIWESSID */
+#endif /* WAVELAN_ROAMING_EXT */
+#if WIRELESS_EXT > 8
+ NULL, /* SIOCSIWNICKN */
+ NULL, /* SIOCGIWNICKN */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ NULL, /* SIOCSIWRATE */
+ NULL, /* SIOCGIWRATE */
+ NULL, /* SIOCSIWRTS */
+ NULL, /* SIOCGIWRTS */
+ NULL, /* SIOCSIWFRAG */
+ NULL, /* SIOCGIWFRAG */
+ NULL, /* SIOCSIWTXPOW */
+ NULL, /* SIOCGIWTXPOW */
+ NULL, /* SIOCSIWRETRY */
+ NULL, /* SIOCGIWRETRY */
+ wavelan_set_encode, /* SIOCSIWENCODE */
+ wavelan_get_encode, /* SIOCGIWENCODE */
+#endif /* WIRELESS_EXT > 8 */
+};
+
+static const iw_handler wavelan_private_handler[] =
+{
+ wavelan_set_qthr, /* SIOCIWFIRSTPRIV */
+ wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */
+#ifdef WAVELAN_ROAMING
+ wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */
+ wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */
+#else /* WAVELAN_ROAMING */
+ NULL, /* SIOCIWFIRSTPRIV + 2 */
+ NULL, /* SIOCIWFIRSTPRIV + 3 */
+#endif /* WAVELAN_ROAMING */
+#ifdef HISTOGRAM
+ wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */
+ wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */
+#endif /* HISTOGRAM */
+};
+
+static const struct iw_handler_def wavelan_handler_def =
+{
+ num_standard: sizeof(wavelan_handler)/sizeof(iw_handler),
+ num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler),
+ num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+ standard: (iw_handler *) wavelan_handler,
+ private: (iw_handler *) wavelan_private_handler,
+ private_args: (struct iw_priv_args *) wavelan_private_args,
+};
+
+#else /* WIRELESS_EXT > 12 */
+/*------------------------------------------------------------------*/
+/*
+ * Perform ioctl : config & info stuff
+ * This is here that are treated the wireless extensions (iwconfig)
+ */
+static int
+wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
+ struct ifreq * rq, /* Data passed */
+ int cmd) /* Ioctl number */
+{
+ struct iwreq * wrq = (struct iwreq *) rq;
+ int ret = 0;
+
+#ifdef DEBUG_IOCTL_TRACE
+ printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
+#endif
+
+ /* Look what is the request */
+ switch(cmd)
+ {
+ /* --------------- WIRELESS EXTENSIONS --------------- */
+
+ case SIOCGIWNAME:
+ wavelan_get_name(dev, NULL, &(wrq->u), NULL);
break;

- case SIOCGIWPRIV:
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- struct iw_priv_args priv[] =
- { /* cmd, set_args, get_args, name */
- { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
- { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
- { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
- { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
- { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" },
- { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
- };
+ case SIOCSIWNWID:
+ ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL);
+ break;

- /* Set the number of ioctl available */
- wrq->u.data.length = 6;
+ case SIOCGIWNWID:
+ ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL);
+ break;

- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
- sizeof(priv)))
+ case SIOCSIWFREQ:
+ ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL);
+ break;
+
+ case SIOCGIWFREQ:
+ ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL);
+ break;
+
+ case SIOCSIWSENS:
+ ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL);
+ break;
+
+ case SIOCGIWSENS:
+ ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL);
+ break;
+
+#if WIRELESS_EXT > 8
+ case SIOCSIWENCODE:
+ {
+ char keybuf[8];
+ if (wrq->u.encoding.pointer) {
+ /* We actually have a key to set */
+ if (wrq->u.encoding.length != 8) {
+ ret = -EINVAL;
+ break;
+ }
+ if (copy_from_user(keybuf,
+ wrq->u.encoding.pointer,
+ wrq->u.encoding.length)) {
ret = -EFAULT;
+ break;
+ }
+ } else if (wrq->u.encoding.length != 0) {
+ ret = -EINVAL;
+ break;
}
+ ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf);
+ }
break;

-#ifdef WIRELESS_SPY
- case SIOCSIWSPY:
- /* Set the spy list */
+ case SIOCGIWENCODE:
+ if (! capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ break;
+ }
+ {
+ char keybuf[8];
+ ret = wavelan_get_encode(dev, NULL,
+ &(wrq->u),
+ keybuf);
+ if (wrq->u.encoding.pointer) {
+ if (copy_to_user(wrq->u.encoding.pointer,
+ keybuf,
+ wrq->u.encoding.length))
+ ret = -EFAULT;
+ }
+ }
+ break;
+#endif /* WIRELESS_EXT > 8 */

- /* Check the number of addresses */
- if(wrq->u.data.length > IW_MAX_SPY)
- {
+#ifdef WAVELAN_ROAMING_EXT
+#if WIRELESS_EXT > 5
+ case SIOCSIWESSID:
+ {
+ char essidbuf[IW_ESSID_MAX_SIZE+1];
+ if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
break;
}
- lp->spy_number = wrq->u.data.length;
-
- /* If there is some addresses to copy */
- if(lp->spy_number > 0)
- {
- struct sockaddr address[IW_MAX_SPY];
- int i;
-
- /* Copy addresses to the driver */
- if(copy_from_user(address, wrq->u.data.pointer,
- sizeof(struct sockaddr) * lp->spy_number))
- {
- ret = -EFAULT;
- break;
- }
+ if (copy_from_user(essidbuf, wrq->u.essid.pointer,
+ wrq->u.essid.length)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = wavelan_set_essid(dev, NULL,
+ &(wrq->u),
+ essidbuf);
+ }
+ break;

- /* Copy addresses to the lp structure */
- for(i = 0; i < lp->spy_number; i++)
- {
- memcpy(lp->spy_address[i], address[i].sa_data,
- WAVELAN_ADDR_SIZE);
- }
+ case SIOCGIWESSID:
+ {
+ char essidbuf[IW_ESSID_MAX_SIZE+1];
+ ret = wavelan_get_essid(dev, NULL,
+ &(wrq->u),
+ essidbuf);
+ if (wrq->u.essid.pointer)
+ if ( copy_to_user(wrq->u.essid.pointer,
+ essidbuf,
+ wrq->u.essid.length) )
+ ret = -EFAULT;
+ }
+ break;

- /* Reset structure... */
- memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+ case SIOCSIWAP:
+ ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL);
+ break;

-#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
- for(i = 0; i < wrq->u.data.length; i++)
- printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
- lp->spy_address[i][0],
- lp->spy_address[i][1],
- lp->spy_address[i][2],
- lp->spy_address[i][3],
- lp->spy_address[i][4],
- lp->spy_address[i][5]);
-#endif /* DEBUG_IOCTL_INFO */
- }
+ case SIOCGIWAP:
+ ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL);
+ break;
+#endif /* WIRELESS_EXT > 5 */
+#endif /* WAVELAN_ROAMING_EXT */

+#if WIRELESS_EXT > 8
+#ifdef WAVELAN_ROAMING
+ case SIOCSIWMODE:
+ ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL);
break;

- case SIOCGIWSPY:
- /* Get the spy list and spy stats */
+ case SIOCGIWMODE:
+ ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL);
+ break;
+#endif /* WAVELAN_ROAMING */
+#endif /* WIRELESS_EXT > 8 */

- /* Set the number of addresses */
- wrq->u.data.length = lp->spy_number;
+ case SIOCGIWRANGE:
+ {
+ struct iw_range range;
+ ret = wavelan_get_range(dev, NULL,
+ &(wrq->u),
+ (char *) &range);
+ if (copy_to_user(wrq->u.data.pointer, &range,
+ sizeof(struct iw_range)))
+ ret = -EFAULT;
+ }
+ break;

- /* If the user want to have the addresses back... */
- if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+ case SIOCGIWPRIV:
+ /* Basic checking... */
+ if(wrq->u.data.pointer != (caddr_t) 0)
{
- struct sockaddr address[IW_MAX_SPY];
- int i;
+ /* Set the number of ioctl available */
+ wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]);

- /* Copy addresses from the lp structure */
- for(i = 0; i < lp->spy_number; i++)
- {
- memcpy(address[i].sa_data, lp->spy_address[i],
- WAVELAN_ADDR_SIZE);
- address[i].sa_family = ARPHRD_ETHER;
- }
-
- /* Copy addresses to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, address,
- sizeof(struct sockaddr) * lp->spy_number))
- {
- ret = -EFAULT;
- break;
- }
-
- /* Copy stats to the user buffer (just after) */
- if(copy_to_user(wrq->u.data.pointer +
- (sizeof(struct sockaddr) * lp->spy_number),
- lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
- {
- ret = -EFAULT;
- break;
- }
-
- /* Reset updated flags */
- for(i = 0; i < lp->spy_number; i++)
- lp->spy_stat[i].updated = 0x0;
- } /* if(pointer != NULL) */
+ /* Copy structure to the user buffer */
+ if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args,
+ sizeof(wavelan_private_args)))
+ ret = -EFAULT;
+ }
+ break;
+
+#ifdef WIRELESS_SPY
+ case SIOCSIWSPY:
+ {
+ struct sockaddr address[IW_MAX_SPY];
+ /* Check the number of addresses */
+ if (wrq->u.data.length > IW_MAX_SPY) {
+ ret = -E2BIG;
+ break;
+ }
+ /* Get the data in the driver */
+ if (wrq->u.data.pointer) {
+ if (copy_from_user((char *) address,
+ wrq->u.data.pointer,
+ sizeof(struct sockaddr) *
+ wrq->u.data.length)) {
+ ret = -EFAULT;
+ break;
+ }
+ } else if (wrq->u.data.length != 0) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = wavelan_set_spy(dev, NULL, &(wrq->u),
+ (char *) address);
+ }
+ break;

+ case SIOCGIWSPY:
+ {
+ char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
+ sizeof(struct iw_quality))];
+ ret = wavelan_get_spy(dev, NULL, &(wrq->u),
+ buffer);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer,
+ buffer,
+ (wrq->u.data.length *
+ (sizeof(struct sockaddr) +
+ sizeof(struct iw_quality)))
+ ))
+ ret = -EFAULT;
+ }
+ }
break;
#endif /* WIRELESS_SPY */

@@ -2446,34 +3123,21 @@ wavelan_ioctl(struct net_device * dev, /
ret = -EPERM;
break;
}
- psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
- psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
- (unsigned char *)&psa.psa_quality_thr, 1);
- /* update the Wavelan checksum */
- update_psa_checksum(dev);
- mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
+ ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL);
break;

case SIOCGIPQTHR:
- psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
- (unsigned char *)&psa.psa_quality_thr, 1);
- *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+ ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL);
break;

#ifdef WAVELAN_ROAMING
case SIOCSIPROAM:
/* Note : should check if user == root */
- if(do_roaming && (*wrq->u.name)==0)
- wv_roam_cleanup(dev);
- else if(do_roaming==0 && (*wrq->u.name)!=0)
- wv_roam_init(dev);
-
- do_roaming = (*wrq->u.name);
-
+ ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL);
break;

case SIOCGIPROAM:
- *(wrq->u.name) = do_roaming;
+ ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WAVELAN_ROAMING */

@@ -2484,44 +3148,44 @@ wavelan_ioctl(struct net_device * dev, /
{
ret = -EPERM;
}
-
- /* Check the number of intervals */
- if(wrq->u.data.length > 16)
- {
- ret = -E2BIG;
- break;
+ {
+ char buffer[16];
+ /* Check the number of intervals */
+ if(wrq->u.data.length > 16)
+ {
+ ret = -E2BIG;
+ break;
}
- lp->his_number = wrq->u.data.length;
-
- /* If there is some addresses to copy */
- if(lp->his_number > 0)
- {
- /* Copy interval ranges to the driver */
- if(copy_from_user(lp->his_range, wrq->u.data.pointer,
- sizeof(char) * lp->his_number))
- {
- ret = -EFAULT;
- break;
- }
-
- /* Reset structure... */
- memset(lp->his_sum, 0x00, sizeof(long) * 16);
+ /* Get the data in the driver */
+ if (wrq->u.data.pointer) {
+ if (copy_from_user(buffer,
+ wrq->u.data.pointer,
+ sizeof(struct sockaddr) *
+ wrq->u.data.length)) {
+ ret = -EFAULT;
+ break;
+ }
+ } else if (wrq->u.data.length != 0) {
+ ret = -EINVAL;
+ break;
}
+ ret = wavelan_set_histo(dev, NULL, &(wrq->u),
+ buffer);
+ }
break;

case SIOCGIPHISTO:
- /* Set the number of intervals */
- wrq->u.data.length = lp->his_number;
-
- /* Give back the distribution statistics */
- if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
- {
- /* Copy data to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
- sizeof(long) * lp->his_number))
+ {
+ long buffer[16];
+ ret = wavelan_get_histo(dev, NULL, &(wrq->u),
+ (char *) buffer);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer,
+ buffer,
+ (wrq->u.data.length * sizeof(long))))
ret = -EFAULT;
-
- } /* if(pointer != NULL) */
+ }
+ }
break;
#endif /* HISTOGRAM */

@@ -2531,14 +3195,12 @@ wavelan_ioctl(struct net_device * dev, /
ret = -EOPNOTSUPP;
}

- /* ReEnable interrupts & restore flags */
- wv_splx(lp, &flags);
-
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif
return ret;
}
+#endif /* WIRELESS_EXT > 12 */

/*------------------------------------------------------------------*/
/*
@@ -4530,7 +5192,11 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES;

#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#if WIRELESS_EXT > 12
+ dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
+#else /* WIRELESS_EXT > 12 */
dev->do_ioctl = wavelan_ioctl; /* wireless extensions */
+#endif /* WIRELESS_EXT > 12 */
dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif

diff -u -p -r linux/drivers/net/wireless-w12/wavelan_cs.p.h linux/drivers/net/wireless/wavelan_cs.p.h
--- linux/drivers/net/wireless-w12/wavelan_cs.p.h Wed Jan 23 16:19:56 2002
+++ linux/drivers/net/wireless/wavelan_cs.p.h Wed Jan 23 16:59:19 2002
@@ -394,6 +394,12 @@
* o control first busy loop in wv_82593_cmd()
* o Extend spinlock protection in wv_hw_config()
*
+ * Changes made for release in 3.1.33 :
+ * ----------------------------------
+ * - Optional use new driver API for Wireless Extensions :
+ * o got rid of wavelan_ioctl()
+ * o use a bunch of iw_handler instead
+ *
* Wishes & dreams:
* ----------------
* - Cleanup and integrate the roaming code
@@ -430,6 +436,9 @@

#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Wireless extensions */
+#if WIRELESS_EXT > 12
+#include <net/iw_handler.h>
+#endif /* WIRELESS_EXT > 12 */
#endif

/* Pcmcia headers that we need */
@@ -498,7 +507,7 @@
/************************ CONSTANTS & MACROS ************************/

#ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
+static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n";
#endif

/* Watchdog temporisation */
@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs
#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */
#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */

-#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */
-#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */
+#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */
+#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */

/*************************** WaveLAN Roaming **************************/
#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */
@@ -588,6 +597,16 @@ typedef struct iw_quality iw_qual;
typedef struct iw_freq iw_freq;
typedef struct net_local net_local;
typedef struct timer_list timer_list;
+
+#if WIRELESS_EXT <= 12
+/* Wireless extensions backward compatibility */
+/* Part of iw_handler prototype we need */
+struct iw_request_info
+{
+ __u16 cmd; /* Wireless Extension command */
+ __u16 flags; /* More to come ;-) */
+};
+#endif /* WIRELESS_EXT <= 12 */

/* Basic types */
typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */


2002-02-05 02:36:46

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH 2.5.3] wavelan_cs.c : new WE api

Comments pertaining to all three of wavelan, wavelan_cs, and netwave_cs:
* wv_splhi should really just be spin_lock_irqsave. calling
spin_lock_irqsave with 'flags' from another function is non-portable.
doing so to an inline function is just barely portable, and is
discouraged :)
* I still see a couple save_flags/restore_flags in there...

otherwise looks ok to me.

--
Jeff Garzik | "I went through my candy like hot oatmeal
Building 1024 | through an internally-buttered weasel."
MandrakeSoft | - goats.com

2002-02-05 03:12:09

by Jean Tourrilhes

[permalink] [raw]
Subject: Re: [PATCH 2.5.3] wavelan_cs.c : new WE api

On Mon, Feb 04, 2002 at 09:36:18PM -0500, Jeff Garzik wrote:
> Comments pertaining to all three of wavelan, wavelan_cs, and netwave_cs:
> * wv_splhi should really just be spin_lock_irqsave. calling
> spin_lock_irqsave with 'flags' from another function is non-portable.
> doing so to an inline function is just barely portable, and is
> discouraged :)

We will have to agree to disagree. I won't oppose a patch (as
long as the driver still works after it).

> * I still see a couple save_flags/restore_flags in there...

Of course, I haven't removed them, just moved them around.

Old code (simplified) :
---------------------------
xxx_ioctl()
{
save_flags();
switch(cmd) {
[...]
copy_from_user(extra, ...);
outsb(..., extra);
[...]
}
restore_flags();
}
----------------------------
Alan told me that this is a no-no.

New code :
-----------------------
xxx_set_xxx(... , char *extra)
{
save_flags();
[...]
outsb(..., extra);
[...]
restore_flags();
}
-----------------------
copy_to/from_user is handled before reaching the wireless
handler. What is nice is that the new API *enforce* the proper
behaviour.

Actually, you may want to add that to the list of cleanups for
the kernel janitors, check that all copy_to/from_user in device ioctl
functions are not done with irq disabled. Actually, I think it was
mostly in Wireless drivers...

> otherwise looks ok to me.

Good. If I understood the new "official" procedure from Linus
himself, you are supposed to forward my patches to hin ;-)

> Jeff Garzik

Have fun...

Jean