diff options
author | Christoph Hellwig <hch@lst.de> | 2005-06-18 19:27:33 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-27 00:23:54 -0400 |
commit | 620554e406e3cc01434c658a1e597162d7e56fd6 (patch) | |
tree | c78c04de8b3809927de6ac0721a3cf5d2a4de8a6 /drivers/net/wireless/orinoco.c | |
parent | 5d558b7f36cc577d31b770d8987681ec6e6545e7 (diff) |
[PATCH] orinoco: wireless API 15 support
(patch from Moustafa Youssef, updated by Jim Carter and Pavel Roskin).
Diffstat (limited to 'drivers/net/wireless/orinoco.c')
-rw-r--r-- | drivers/net/wireless/orinoco.c | 1118 |
1 files changed, 547 insertions, 571 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 7cf3b9822792..0e1edce91021 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -463,6 +463,7 @@ | |||
463 | #include <linux/if_arp.h> | 463 | #include <linux/if_arp.h> |
464 | #include <linux/etherdevice.h> | 464 | #include <linux/etherdevice.h> |
465 | #include <linux/wireless.h> | 465 | #include <linux/wireless.h> |
466 | #include <net/iw_handler.h> | ||
466 | #include <net/ieee80211.h> | 467 | #include <net/ieee80211.h> |
467 | 468 | ||
468 | #include <asm/uaccess.h> | 469 | #include <asm/uaccess.h> |
@@ -538,6 +539,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer | |||
538 | | HERMES_EV_WTERR | HERMES_EV_INFO \ | 539 | | HERMES_EV_WTERR | HERMES_EV_INFO \ |
539 | | HERMES_EV_INFDROP ) | 540 | | HERMES_EV_INFDROP ) |
540 | 541 | ||
542 | #define MAX_RID_LEN 1024 | ||
543 | |||
544 | static const struct iw_handler_def orinoco_handler_def; | ||
545 | |||
541 | /********************************************************************/ | 546 | /********************************************************************/ |
542 | /* Data tables */ | 547 | /* Data tables */ |
543 | /********************************************************************/ | 548 | /********************************************************************/ |
@@ -605,7 +610,6 @@ struct hermes_rx_descriptor { | |||
605 | /* Function prototypes */ | 610 | /* Function prototypes */ |
606 | /********************************************************************/ | 611 | /********************************************************************/ |
607 | 612 | ||
608 | static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | ||
609 | static int __orinoco_program_rids(struct net_device *dev); | 613 | static int __orinoco_program_rids(struct net_device *dev); |
610 | static void __orinoco_set_multicast_list(struct net_device *dev); | 614 | static void __orinoco_set_multicast_list(struct net_device *dev); |
611 | 615 | ||
@@ -1870,55 +1874,6 @@ __orinoco_set_multicast_list(struct net_device *dev) | |||
1870 | dev->flags &= ~IFF_PROMISC; | 1874 | dev->flags &= ~IFF_PROMISC; |
1871 | } | 1875 | } |
1872 | 1876 | ||
1873 | static int orinoco_reconfigure(struct net_device *dev) | ||
1874 | { | ||
1875 | struct orinoco_private *priv = netdev_priv(dev); | ||
1876 | struct hermes *hw = &priv->hw; | ||
1877 | unsigned long flags; | ||
1878 | int err = 0; | ||
1879 | |||
1880 | if (priv->broken_disableport) { | ||
1881 | schedule_work(&priv->reset_work); | ||
1882 | return 0; | ||
1883 | } | ||
1884 | |||
1885 | if (orinoco_lock(priv, &flags) != 0) | ||
1886 | return -EBUSY; | ||
1887 | |||
1888 | err = hermes_disable_port(hw, 0); | ||
1889 | if (err) { | ||
1890 | printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", | ||
1891 | dev->name); | ||
1892 | priv->broken_disableport = 1; | ||
1893 | goto out; | ||
1894 | } | ||
1895 | |||
1896 | err = __orinoco_program_rids(dev); | ||
1897 | if (err) { | ||
1898 | printk(KERN_WARNING "%s: Unable to reconfigure card\n", | ||
1899 | dev->name); | ||
1900 | goto out; | ||
1901 | } | ||
1902 | |||
1903 | err = hermes_enable_port(hw, 0); | ||
1904 | if (err) { | ||
1905 | printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", | ||
1906 | dev->name); | ||
1907 | goto out; | ||
1908 | } | ||
1909 | |||
1910 | out: | ||
1911 | if (err) { | ||
1912 | printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); | ||
1913 | schedule_work(&priv->reset_work); | ||
1914 | err = 0; | ||
1915 | } | ||
1916 | |||
1917 | orinoco_unlock(priv, &flags); | ||
1918 | return err; | ||
1919 | |||
1920 | } | ||
1921 | |||
1922 | /* This must be called from user context, without locks held - use | 1877 | /* This must be called from user context, without locks held - use |
1923 | * schedule_work() */ | 1878 | * schedule_work() */ |
1924 | static void orinoco_reset(struct net_device *dev) | 1879 | static void orinoco_reset(struct net_device *dev) |
@@ -2458,7 +2413,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, | |||
2458 | dev->watchdog_timeo = HZ; /* 1 second timeout */ | 2413 | dev->watchdog_timeo = HZ; /* 1 second timeout */ |
2459 | dev->get_stats = orinoco_get_stats; | 2414 | dev->get_stats = orinoco_get_stats; |
2460 | dev->get_wireless_stats = orinoco_get_wireless_stats; | 2415 | dev->get_wireless_stats = orinoco_get_wireless_stats; |
2461 | dev->do_ioctl = orinoco_ioctl; | 2416 | dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def; |
2462 | dev->change_mtu = orinoco_change_mtu; | 2417 | dev->change_mtu = orinoco_change_mtu; |
2463 | dev->set_multicast_list = orinoco_set_multicast_list; | 2418 | dev->set_multicast_list = orinoco_set_multicast_list; |
2464 | /* we use the default eth_mac_addr for setting the MAC addr */ | 2419 | /* we use the default eth_mac_addr for setting the MAC addr */ |
@@ -2491,24 +2446,6 @@ void free_orinocodev(struct net_device *dev) | |||
2491 | /* Wireless extensions */ | 2446 | /* Wireless extensions */ |
2492 | /********************************************************************/ | 2447 | /********************************************************************/ |
2493 | 2448 | ||
2494 | static int orinoco_hw_get_bssid(struct orinoco_private *priv, | ||
2495 | char buf[ETH_ALEN]) | ||
2496 | { | ||
2497 | hermes_t *hw = &priv->hw; | ||
2498 | int err = 0; | ||
2499 | unsigned long flags; | ||
2500 | |||
2501 | if (orinoco_lock(priv, &flags) != 0) | ||
2502 | return -EBUSY; | ||
2503 | |||
2504 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | ||
2505 | ETH_ALEN, NULL, buf); | ||
2506 | |||
2507 | orinoco_unlock(priv, &flags); | ||
2508 | |||
2509 | return err; | ||
2510 | } | ||
2511 | |||
2512 | static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, | 2449 | static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, |
2513 | char buf[IW_ESSID_MAX_SIZE+1]) | 2450 | char buf[IW_ESSID_MAX_SIZE+1]) |
2514 | { | 2451 | { |
@@ -2634,140 +2571,201 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | |||
2634 | return 0; | 2571 | return 0; |
2635 | } | 2572 | } |
2636 | 2573 | ||
2637 | static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) | 2574 | static int orinoco_ioctl_getname(struct net_device *dev, |
2575 | struct iw_request_info *info, | ||
2576 | char *name, | ||
2577 | char *extra) | ||
2638 | { | 2578 | { |
2639 | struct orinoco_private *priv = netdev_priv(dev); | 2579 | struct orinoco_private *priv = netdev_priv(dev); |
2640 | int err = 0; | ||
2641 | int mode; | ||
2642 | struct iw_range range; | ||
2643 | int numrates; | 2580 | int numrates; |
2644 | int i, k; | 2581 | int err; |
2582 | |||
2583 | err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0); | ||
2584 | |||
2585 | if (!err && (numrates > 2)) | ||
2586 | strcpy(name, "IEEE 802.11b"); | ||
2587 | else | ||
2588 | strcpy(name, "IEEE 802.11-DS"); | ||
2589 | |||
2590 | return 0; | ||
2591 | } | ||
2592 | |||
2593 | static int orinoco_ioctl_getwap(struct net_device *dev, | ||
2594 | struct iw_request_info *info, | ||
2595 | struct sockaddr *ap_addr, | ||
2596 | char *extra) | ||
2597 | { | ||
2598 | struct orinoco_private *priv = netdev_priv(dev); | ||
2599 | |||
2600 | hermes_t *hw = &priv->hw; | ||
2601 | int err = 0; | ||
2645 | unsigned long flags; | 2602 | unsigned long flags; |
2646 | 2603 | ||
2647 | TRACE_ENTER(dev->name); | 2604 | if (orinoco_lock(priv, &flags) != 0) |
2605 | return -EBUSY; | ||
2648 | 2606 | ||
2649 | if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range))) | 2607 | ap_addr->sa_family = ARPHRD_ETHER; |
2650 | return -EFAULT; | 2608 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, |
2609 | ETH_ALEN, NULL, ap_addr->sa_data); | ||
2651 | 2610 | ||
2652 | rrq->length = sizeof(range); | 2611 | orinoco_unlock(priv, &flags); |
2612 | |||
2613 | return err; | ||
2614 | } | ||
2615 | |||
2616 | static int orinoco_ioctl_setmode(struct net_device *dev, | ||
2617 | struct iw_request_info *info, | ||
2618 | u32 *mode, | ||
2619 | char *extra) | ||
2620 | { | ||
2621 | struct orinoco_private *priv = netdev_priv(dev); | ||
2622 | int err = -EINPROGRESS; /* Call commit handler */ | ||
2623 | unsigned long flags; | ||
2624 | |||
2625 | if (priv->iw_mode == *mode) | ||
2626 | return 0; | ||
2653 | 2627 | ||
2654 | if (orinoco_lock(priv, &flags) != 0) | 2628 | if (orinoco_lock(priv, &flags) != 0) |
2655 | return -EBUSY; | 2629 | return -EBUSY; |
2656 | 2630 | ||
2657 | mode = priv->iw_mode; | 2631 | switch (*mode) { |
2632 | case IW_MODE_ADHOC: | ||
2633 | if (!priv->has_ibss && !priv->has_port3) | ||
2634 | err = -EOPNOTSUPP; | ||
2635 | break; | ||
2636 | |||
2637 | case IW_MODE_INFRA: | ||
2638 | break; | ||
2639 | |||
2640 | default: | ||
2641 | err = -EOPNOTSUPP; | ||
2642 | break; | ||
2643 | } | ||
2644 | |||
2645 | if (err == -EINPROGRESS) { | ||
2646 | priv->iw_mode = *mode; | ||
2647 | set_port_type(priv); | ||
2648 | } | ||
2649 | |||
2658 | orinoco_unlock(priv, &flags); | 2650 | orinoco_unlock(priv, &flags); |
2659 | 2651 | ||
2660 | memset(&range, 0, sizeof(range)); | 2652 | return err; |
2653 | } | ||
2654 | |||
2655 | static int orinoco_ioctl_getmode(struct net_device *dev, | ||
2656 | struct iw_request_info *info, | ||
2657 | u32 *mode, | ||
2658 | char *extra) | ||
2659 | { | ||
2660 | struct orinoco_private *priv = netdev_priv(dev); | ||
2661 | 2661 | ||
2662 | /* Much of this shamelessly taken from wvlan_cs.c. No idea | 2662 | *mode = priv->iw_mode; |
2663 | * what it all means -dgibson */ | 2663 | return 0; |
2664 | range.we_version_compiled = WIRELESS_EXT; | 2664 | } |
2665 | range.we_version_source = 11; | ||
2666 | 2665 | ||
2667 | range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ | 2666 | static int orinoco_ioctl_getiwrange(struct net_device *dev, |
2667 | struct iw_request_info *info, | ||
2668 | struct iw_point *rrq, | ||
2669 | char *extra) | ||
2670 | { | ||
2671 | struct orinoco_private *priv = netdev_priv(dev); | ||
2672 | int err = 0; | ||
2673 | struct iw_range *range = (struct iw_range *) extra; | ||
2674 | int numrates; | ||
2675 | int i, k; | ||
2676 | |||
2677 | TRACE_ENTER(dev->name); | ||
2678 | |||
2679 | rrq->length = sizeof(struct iw_range); | ||
2680 | memset(range, 0, sizeof(struct iw_range)); | ||
2681 | |||
2682 | range->we_version_compiled = WIRELESS_EXT; | ||
2683 | range->we_version_source = 14; | ||
2668 | 2684 | ||
2669 | /* Set available channels/frequencies */ | 2685 | /* Set available channels/frequencies */ |
2670 | range.num_channels = NUM_CHANNELS; | 2686 | range->num_channels = NUM_CHANNELS; |
2671 | k = 0; | 2687 | k = 0; |
2672 | for (i = 0; i < NUM_CHANNELS; i++) { | 2688 | for (i = 0; i < NUM_CHANNELS; i++) { |
2673 | if (priv->channel_mask & (1 << i)) { | 2689 | if (priv->channel_mask & (1 << i)) { |
2674 | range.freq[k].i = i + 1; | 2690 | range->freq[k].i = i + 1; |
2675 | range.freq[k].m = channel_frequency[i] * 100000; | 2691 | range->freq[k].m = channel_frequency[i] * 100000; |
2676 | range.freq[k].e = 1; | 2692 | range->freq[k].e = 1; |
2677 | k++; | 2693 | k++; |
2678 | } | 2694 | } |
2679 | 2695 | ||
2680 | if (k >= IW_MAX_FREQUENCIES) | 2696 | if (k >= IW_MAX_FREQUENCIES) |
2681 | break; | 2697 | break; |
2682 | } | 2698 | } |
2683 | range.num_frequency = k; | 2699 | range->num_frequency = k; |
2700 | range->sensitivity = 3; | ||
2684 | 2701 | ||
2685 | range.sensitivity = 3; | 2702 | if (priv->has_wep) { |
2703 | range->max_encoding_tokens = ORINOCO_MAX_KEYS; | ||
2704 | range->encoding_size[0] = SMALL_KEY_SIZE; | ||
2705 | range->num_encoding_sizes = 1; | ||
2686 | 2706 | ||
2687 | if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ | 2707 | if (priv->has_big_wep) { |
2708 | range->encoding_size[1] = LARGE_KEY_SIZE; | ||
2709 | range->num_encoding_sizes = 2; | ||
2710 | } | ||
2711 | } | ||
2712 | |||
2713 | if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ | ||
2688 | /* Quality stats meaningless in ad-hoc mode */ | 2714 | /* Quality stats meaningless in ad-hoc mode */ |
2689 | range.max_qual.qual = 0; | ||
2690 | range.max_qual.level = 0; | ||
2691 | range.max_qual.noise = 0; | ||
2692 | range.avg_qual.qual = 0; | ||
2693 | range.avg_qual.level = 0; | ||
2694 | range.avg_qual.noise = 0; | ||
2695 | } else { | 2715 | } else { |
2696 | range.max_qual.qual = 0x8b - 0x2f; | 2716 | range->max_qual.qual = 0x8b - 0x2f; |
2697 | range.max_qual.level = 0x2f - 0x95 - 1; | 2717 | range->max_qual.level = 0x2f - 0x95 - 1; |
2698 | range.max_qual.noise = 0x2f - 0x95 - 1; | 2718 | range->max_qual.noise = 0x2f - 0x95 - 1; |
2699 | /* Need to get better values */ | 2719 | /* Need to get better values */ |
2700 | range.avg_qual.qual = 0x24; | 2720 | range->avg_qual.qual = 0x24; |
2701 | range.avg_qual.level = 0xC2; | 2721 | range->avg_qual.level = 0xC2; |
2702 | range.avg_qual.noise = 0x9E; | 2722 | range->avg_qual.noise = 0x9E; |
2703 | } | 2723 | } |
2704 | 2724 | ||
2705 | err = orinoco_hw_get_bitratelist(priv, &numrates, | 2725 | err = orinoco_hw_get_bitratelist(priv, &numrates, |
2706 | range.bitrate, IW_MAX_BITRATES); | 2726 | range->bitrate, IW_MAX_BITRATES); |
2707 | if (err) | 2727 | if (err) |
2708 | return err; | 2728 | return err; |
2709 | range.num_bitrates = numrates; | 2729 | range->num_bitrates = numrates; |
2710 | 2730 | ||
2711 | /* Set an indication of the max TCP throughput in bit/s that we can | 2731 | /* Set an indication of the max TCP throughput in bit/s that we can |
2712 | * expect using this interface. May be use for QoS stuff... | 2732 | * expect using this interface. May be use for QoS stuff... |
2713 | * Jean II */ | 2733 | * Jean II */ |
2714 | if(numrates > 2) | 2734 | if (numrates > 2) |
2715 | range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ | 2735 | range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ |
2716 | else | 2736 | else |
2717 | range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ | 2737 | range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ |
2718 | 2738 | ||
2719 | range.min_rts = 0; | 2739 | range->min_rts = 0; |
2720 | range.max_rts = 2347; | 2740 | range->max_rts = 2347; |
2721 | range.min_frag = 256; | 2741 | range->min_frag = 256; |
2722 | range.max_frag = 2346; | 2742 | range->max_frag = 2346; |
2723 | 2743 | ||
2724 | if (orinoco_lock(priv, &flags) != 0) | 2744 | range->min_pmp = 0; |
2725 | return -EBUSY; | 2745 | range->max_pmp = 65535000; |
2726 | if (priv->has_wep) { | 2746 | range->min_pmt = 0; |
2727 | range.max_encoding_tokens = ORINOCO_MAX_KEYS; | 2747 | range->max_pmt = 65535 * 1000; /* ??? */ |
2728 | 2748 | range->pmp_flags = IW_POWER_PERIOD; | |
2729 | range.encoding_size[0] = SMALL_KEY_SIZE; | 2749 | range->pmt_flags = IW_POWER_TIMEOUT; |
2730 | range.num_encoding_sizes = 1; | 2750 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; |
2731 | 2751 | ||
2732 | if (priv->has_big_wep) { | 2752 | range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; |
2733 | range.encoding_size[1] = LARGE_KEY_SIZE; | 2753 | range->retry_flags = IW_RETRY_LIMIT; |
2734 | range.num_encoding_sizes = 2; | 2754 | range->r_time_flags = IW_RETRY_LIFETIME; |
2735 | } | 2755 | range->min_retry = 0; |
2736 | } else { | 2756 | range->max_retry = 65535; /* ??? */ |
2737 | range.num_encoding_sizes = 0; | 2757 | range->min_r_time = 0; |
2738 | range.max_encoding_tokens = 0; | 2758 | range->max_r_time = 65535 * 1000; /* ??? */ |
2739 | } | ||
2740 | orinoco_unlock(priv, &flags); | ||
2741 | |||
2742 | range.min_pmp = 0; | ||
2743 | range.max_pmp = 65535000; | ||
2744 | range.min_pmt = 0; | ||
2745 | range.max_pmt = 65535 * 1000; /* ??? */ | ||
2746 | range.pmp_flags = IW_POWER_PERIOD; | ||
2747 | range.pmt_flags = IW_POWER_TIMEOUT; | ||
2748 | range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; | ||
2749 | |||
2750 | range.num_txpower = 1; | ||
2751 | range.txpower[0] = 15; /* 15dBm */ | ||
2752 | range.txpower_capa = IW_TXPOW_DBM; | ||
2753 | |||
2754 | range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; | ||
2755 | range.retry_flags = IW_RETRY_LIMIT; | ||
2756 | range.r_time_flags = IW_RETRY_LIFETIME; | ||
2757 | range.min_retry = 0; | ||
2758 | range.max_retry = 65535; /* ??? */ | ||
2759 | range.min_r_time = 0; | ||
2760 | range.max_r_time = 65535 * 1000; /* ??? */ | ||
2761 | |||
2762 | if (copy_to_user(rrq->pointer, &range, sizeof(range))) | ||
2763 | return -EFAULT; | ||
2764 | 2759 | ||
2765 | TRACE_EXIT(dev->name); | 2760 | TRACE_EXIT(dev->name); |
2766 | 2761 | ||
2767 | return 0; | 2762 | return 0; |
2768 | } | 2763 | } |
2769 | 2764 | ||
2770 | static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) | 2765 | static int orinoco_ioctl_setiwencode(struct net_device *dev, |
2766 | struct iw_request_info *info, | ||
2767 | struct iw_point *erq, | ||
2768 | char *keybuf) | ||
2771 | { | 2769 | { |
2772 | struct orinoco_private *priv = netdev_priv(dev); | 2770 | struct orinoco_private *priv = netdev_priv(dev); |
2773 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | 2771 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; |
@@ -2775,8 +2773,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er | |||
2775 | int enable = priv->wep_on; | 2773 | int enable = priv->wep_on; |
2776 | int restricted = priv->wep_restrict; | 2774 | int restricted = priv->wep_restrict; |
2777 | u16 xlen = 0; | 2775 | u16 xlen = 0; |
2778 | int err = 0; | 2776 | int err = -EINPROGRESS; /* Call commit handler */ |
2779 | char keybuf[ORINOCO_MAX_KEY_SIZE]; | ||
2780 | unsigned long flags; | 2777 | unsigned long flags; |
2781 | 2778 | ||
2782 | if (! priv->has_wep) | 2779 | if (! priv->has_wep) |
@@ -2789,9 +2786,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er | |||
2789 | 2786 | ||
2790 | if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) | 2787 | if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) |
2791 | return -E2BIG; | 2788 | return -E2BIG; |
2792 | |||
2793 | if (copy_from_user(keybuf, erq->pointer, erq->length)) | ||
2794 | return -EFAULT; | ||
2795 | } | 2789 | } |
2796 | 2790 | ||
2797 | if (orinoco_lock(priv, &flags) != 0) | 2791 | if (orinoco_lock(priv, &flags) != 0) |
@@ -2865,12 +2859,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er | |||
2865 | return err; | 2859 | return err; |
2866 | } | 2860 | } |
2867 | 2861 | ||
2868 | static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) | 2862 | static int orinoco_ioctl_getiwencode(struct net_device *dev, |
2863 | struct iw_request_info *info, | ||
2864 | struct iw_point *erq, | ||
2865 | char *keybuf) | ||
2869 | { | 2866 | { |
2870 | struct orinoco_private *priv = netdev_priv(dev); | 2867 | struct orinoco_private *priv = netdev_priv(dev); |
2871 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | 2868 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; |
2872 | u16 xlen = 0; | 2869 | u16 xlen = 0; |
2873 | char keybuf[ORINOCO_MAX_KEY_SIZE]; | ||
2874 | unsigned long flags; | 2870 | unsigned long flags; |
2875 | 2871 | ||
2876 | if (! priv->has_wep) | 2872 | if (! priv->has_wep) |
@@ -2899,51 +2895,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er | |||
2899 | memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); | 2895 | memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); |
2900 | 2896 | ||
2901 | orinoco_unlock(priv, &flags); | 2897 | orinoco_unlock(priv, &flags); |
2902 | |||
2903 | if (erq->pointer) { | ||
2904 | if (copy_to_user(erq->pointer, keybuf, xlen)) | ||
2905 | return -EFAULT; | ||
2906 | } | ||
2907 | |||
2908 | return 0; | 2898 | return 0; |
2909 | } | 2899 | } |
2910 | 2900 | ||
2911 | static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) | 2901 | static int orinoco_ioctl_setessid(struct net_device *dev, |
2902 | struct iw_request_info *info, | ||
2903 | struct iw_point *erq, | ||
2904 | char *essidbuf) | ||
2912 | { | 2905 | { |
2913 | struct orinoco_private *priv = netdev_priv(dev); | 2906 | struct orinoco_private *priv = netdev_priv(dev); |
2914 | char essidbuf[IW_ESSID_MAX_SIZE+1]; | ||
2915 | unsigned long flags; | 2907 | unsigned long flags; |
2916 | 2908 | ||
2917 | /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it | 2909 | /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it |
2918 | * anyway... - Jean II */ | 2910 | * anyway... - Jean II */ |
2919 | 2911 | ||
2920 | memset(&essidbuf, 0, sizeof(essidbuf)); | 2912 | /* Hum... Should not use Wireless Extension constant (may change), |
2921 | 2913 | * should use our own... - Jean II */ | |
2922 | if (erq->flags) { | 2914 | if (erq->length > IW_ESSID_MAX_SIZE) |
2923 | /* iwconfig includes the NUL in the specified length */ | 2915 | return -E2BIG; |
2924 | if (erq->length > IW_ESSID_MAX_SIZE+1) | ||
2925 | return -E2BIG; | ||
2926 | |||
2927 | if (copy_from_user(&essidbuf, erq->pointer, erq->length)) | ||
2928 | return -EFAULT; | ||
2929 | |||
2930 | essidbuf[IW_ESSID_MAX_SIZE] = '\0'; | ||
2931 | } | ||
2932 | 2916 | ||
2933 | if (orinoco_lock(priv, &flags) != 0) | 2917 | if (orinoco_lock(priv, &flags) != 0) |
2934 | return -EBUSY; | 2918 | return -EBUSY; |
2935 | 2919 | ||
2936 | memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid)); | 2920 | /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ |
2921 | memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); | ||
2922 | |||
2923 | /* If not ANY, get the new ESSID */ | ||
2924 | if (erq->flags) { | ||
2925 | memcpy(priv->desired_essid, essidbuf, erq->length); | ||
2926 | } | ||
2937 | 2927 | ||
2938 | orinoco_unlock(priv, &flags); | 2928 | orinoco_unlock(priv, &flags); |
2939 | 2929 | ||
2940 | return 0; | 2930 | return -EINPROGRESS; /* Call commit handler */ |
2941 | } | 2931 | } |
2942 | 2932 | ||
2943 | static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) | 2933 | static int orinoco_ioctl_getessid(struct net_device *dev, |
2934 | struct iw_request_info *info, | ||
2935 | struct iw_point *erq, | ||
2936 | char *essidbuf) | ||
2944 | { | 2937 | { |
2945 | struct orinoco_private *priv = netdev_priv(dev); | 2938 | struct orinoco_private *priv = netdev_priv(dev); |
2946 | char essidbuf[IW_ESSID_MAX_SIZE+1]; | ||
2947 | int active; | 2939 | int active; |
2948 | int err = 0; | 2940 | int err = 0; |
2949 | unsigned long flags; | 2941 | unsigned long flags; |
@@ -2957,51 +2949,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) | |||
2957 | } else { | 2949 | } else { |
2958 | if (orinoco_lock(priv, &flags) != 0) | 2950 | if (orinoco_lock(priv, &flags) != 0) |
2959 | return -EBUSY; | 2951 | return -EBUSY; |
2960 | memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf)); | 2952 | memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1); |
2961 | orinoco_unlock(priv, &flags); | 2953 | orinoco_unlock(priv, &flags); |
2962 | } | 2954 | } |
2963 | 2955 | ||
2964 | erq->flags = 1; | 2956 | erq->flags = 1; |
2965 | erq->length = strlen(essidbuf) + 1; | 2957 | erq->length = strlen(essidbuf) + 1; |
2966 | if (erq->pointer) | ||
2967 | if (copy_to_user(erq->pointer, essidbuf, erq->length)) | ||
2968 | return -EFAULT; | ||
2969 | 2958 | ||
2970 | TRACE_EXIT(dev->name); | 2959 | TRACE_EXIT(dev->name); |
2971 | 2960 | ||
2972 | return 0; | 2961 | return 0; |
2973 | } | 2962 | } |
2974 | 2963 | ||
2975 | static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) | 2964 | static int orinoco_ioctl_setnick(struct net_device *dev, |
2965 | struct iw_request_info *info, | ||
2966 | struct iw_point *nrq, | ||
2967 | char *nickbuf) | ||
2976 | { | 2968 | { |
2977 | struct orinoco_private *priv = netdev_priv(dev); | 2969 | struct orinoco_private *priv = netdev_priv(dev); |
2978 | char nickbuf[IW_ESSID_MAX_SIZE+1]; | ||
2979 | unsigned long flags; | 2970 | unsigned long flags; |
2980 | 2971 | ||
2981 | if (nrq->length > IW_ESSID_MAX_SIZE) | 2972 | if (nrq->length > IW_ESSID_MAX_SIZE) |
2982 | return -E2BIG; | 2973 | return -E2BIG; |
2983 | 2974 | ||
2984 | memset(nickbuf, 0, sizeof(nickbuf)); | ||
2985 | |||
2986 | if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) | ||
2987 | return -EFAULT; | ||
2988 | |||
2989 | nickbuf[nrq->length] = '\0'; | ||
2990 | |||
2991 | if (orinoco_lock(priv, &flags) != 0) | 2975 | if (orinoco_lock(priv, &flags) != 0) |
2992 | return -EBUSY; | 2976 | return -EBUSY; |
2993 | 2977 | ||
2994 | memcpy(priv->nick, nickbuf, sizeof(priv->nick)); | 2978 | memset(priv->nick, 0, sizeof(priv->nick)); |
2979 | memcpy(priv->nick, nickbuf, nrq->length); | ||
2995 | 2980 | ||
2996 | orinoco_unlock(priv, &flags); | 2981 | orinoco_unlock(priv, &flags); |
2997 | 2982 | ||
2998 | return 0; | 2983 | return -EINPROGRESS; /* Call commit handler */ |
2999 | } | 2984 | } |
3000 | 2985 | ||
3001 | static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) | 2986 | static int orinoco_ioctl_getnick(struct net_device *dev, |
2987 | struct iw_request_info *info, | ||
2988 | struct iw_point *nrq, | ||
2989 | char *nickbuf) | ||
3002 | { | 2990 | { |
3003 | struct orinoco_private *priv = netdev_priv(dev); | 2991 | struct orinoco_private *priv = netdev_priv(dev); |
3004 | char nickbuf[IW_ESSID_MAX_SIZE+1]; | ||
3005 | unsigned long flags; | 2992 | unsigned long flags; |
3006 | 2993 | ||
3007 | if (orinoco_lock(priv, &flags) != 0) | 2994 | if (orinoco_lock(priv, &flags) != 0) |
@@ -3012,17 +2999,18 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) | |||
3012 | 2999 | ||
3013 | nrq->length = strlen(nickbuf)+1; | 3000 | nrq->length = strlen(nickbuf)+1; |
3014 | 3001 | ||
3015 | if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) | ||
3016 | return -EFAULT; | ||
3017 | |||
3018 | return 0; | 3002 | return 0; |
3019 | } | 3003 | } |
3020 | 3004 | ||
3021 | static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) | 3005 | static int orinoco_ioctl_setfreq(struct net_device *dev, |
3006 | struct iw_request_info *info, | ||
3007 | struct iw_freq *frq, | ||
3008 | char *extra) | ||
3022 | { | 3009 | { |
3023 | struct orinoco_private *priv = netdev_priv(dev); | 3010 | struct orinoco_private *priv = netdev_priv(dev); |
3024 | int chan = -1; | 3011 | int chan = -1; |
3025 | unsigned long flags; | 3012 | unsigned long flags; |
3013 | int err = -EINPROGRESS; /* Call commit handler */ | ||
3026 | 3014 | ||
3027 | /* We can only use this in Ad-Hoc demo mode to set the operating | 3015 | /* We can only use this in Ad-Hoc demo mode to set the operating |
3028 | * frequency, or in IBSS mode to set the frequency where the IBSS | 3016 | * frequency, or in IBSS mode to set the frequency where the IBSS |
@@ -3055,10 +3043,33 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) | |||
3055 | priv->channel = chan; | 3043 | priv->channel = chan; |
3056 | orinoco_unlock(priv, &flags); | 3044 | orinoco_unlock(priv, &flags); |
3057 | 3045 | ||
3046 | return err; | ||
3047 | } | ||
3048 | |||
3049 | static int orinoco_ioctl_getfreq(struct net_device *dev, | ||
3050 | struct iw_request_info *info, | ||
3051 | struct iw_freq *frq, | ||
3052 | char *extra) | ||
3053 | { | ||
3054 | struct orinoco_private *priv = netdev_priv(dev); | ||
3055 | int tmp; | ||
3056 | |||
3057 | /* Locking done in there */ | ||
3058 | tmp = orinoco_hw_get_freq(priv); | ||
3059 | if (tmp < 0) { | ||
3060 | return tmp; | ||
3061 | } | ||
3062 | |||
3063 | frq->m = tmp; | ||
3064 | frq->e = 1; | ||
3065 | |||
3058 | return 0; | 3066 | return 0; |
3059 | } | 3067 | } |
3060 | 3068 | ||
3061 | static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) | 3069 | static int orinoco_ioctl_getsens(struct net_device *dev, |
3070 | struct iw_request_info *info, | ||
3071 | struct iw_param *srq, | ||
3072 | char *extra) | ||
3062 | { | 3073 | { |
3063 | struct orinoco_private *priv = netdev_priv(dev); | 3074 | struct orinoco_private *priv = netdev_priv(dev); |
3064 | hermes_t *hw = &priv->hw; | 3075 | hermes_t *hw = &priv->hw; |
@@ -3084,7 +3095,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) | |||
3084 | return 0; | 3095 | return 0; |
3085 | } | 3096 | } |
3086 | 3097 | ||
3087 | static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) | 3098 | static int orinoco_ioctl_setsens(struct net_device *dev, |
3099 | struct iw_request_info *info, | ||
3100 | struct iw_param *srq, | ||
3101 | char *extra) | ||
3088 | { | 3102 | { |
3089 | struct orinoco_private *priv = netdev_priv(dev); | 3103 | struct orinoco_private *priv = netdev_priv(dev); |
3090 | int val = srq->value; | 3104 | int val = srq->value; |
@@ -3101,10 +3115,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) | |||
3101 | priv->ap_density = val; | 3115 | priv->ap_density = val; |
3102 | orinoco_unlock(priv, &flags); | 3116 | orinoco_unlock(priv, &flags); |
3103 | 3117 | ||
3104 | return 0; | 3118 | return -EINPROGRESS; /* Call commit handler */ |
3105 | } | 3119 | } |
3106 | 3120 | ||
3107 | static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) | 3121 | static int orinoco_ioctl_setrts(struct net_device *dev, |
3122 | struct iw_request_info *info, | ||
3123 | struct iw_param *rrq, | ||
3124 | char *extra) | ||
3108 | { | 3125 | { |
3109 | struct orinoco_private *priv = netdev_priv(dev); | 3126 | struct orinoco_private *priv = netdev_priv(dev); |
3110 | int val = rrq->value; | 3127 | int val = rrq->value; |
@@ -3122,13 +3139,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) | |||
3122 | priv->rts_thresh = val; | 3139 | priv->rts_thresh = val; |
3123 | orinoco_unlock(priv, &flags); | 3140 | orinoco_unlock(priv, &flags); |
3124 | 3141 | ||
3142 | return -EINPROGRESS; /* Call commit handler */ | ||
3143 | } | ||
3144 | |||
3145 | static int orinoco_ioctl_getrts(struct net_device *dev, | ||
3146 | struct iw_request_info *info, | ||
3147 | struct iw_param *rrq, | ||
3148 | char *extra) | ||
3149 | { | ||
3150 | struct orinoco_private *priv = netdev_priv(dev); | ||
3151 | |||
3152 | rrq->value = priv->rts_thresh; | ||
3153 | rrq->disabled = (rrq->value == 2347); | ||
3154 | rrq->fixed = 1; | ||
3155 | |||
3125 | return 0; | 3156 | return 0; |
3126 | } | 3157 | } |
3127 | 3158 | ||
3128 | static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) | 3159 | static int orinoco_ioctl_setfrag(struct net_device *dev, |
3160 | struct iw_request_info *info, | ||
3161 | struct iw_param *frq, | ||
3162 | char *extra) | ||
3129 | { | 3163 | { |
3130 | struct orinoco_private *priv = netdev_priv(dev); | 3164 | struct orinoco_private *priv = netdev_priv(dev); |
3131 | int err = 0; | 3165 | int err = -EINPROGRESS; /* Call commit handler */ |
3132 | unsigned long flags; | 3166 | unsigned long flags; |
3133 | 3167 | ||
3134 | if (orinoco_lock(priv, &flags) != 0) | 3168 | if (orinoco_lock(priv, &flags) != 0) |
@@ -3160,11 +3194,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) | |||
3160 | return err; | 3194 | return err; |
3161 | } | 3195 | } |
3162 | 3196 | ||
3163 | static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) | 3197 | static int orinoco_ioctl_getfrag(struct net_device *dev, |
3198 | struct iw_request_info *info, | ||
3199 | struct iw_param *frq, | ||
3200 | char *extra) | ||
3164 | { | 3201 | { |
3165 | struct orinoco_private *priv = netdev_priv(dev); | 3202 | struct orinoco_private *priv = netdev_priv(dev); |
3166 | hermes_t *hw = &priv->hw; | 3203 | hermes_t *hw = &priv->hw; |
3167 | int err = 0; | 3204 | int err; |
3168 | u16 val; | 3205 | u16 val; |
3169 | unsigned long flags; | 3206 | unsigned long flags; |
3170 | 3207 | ||
@@ -3197,10 +3234,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) | |||
3197 | return err; | 3234 | return err; |
3198 | } | 3235 | } |
3199 | 3236 | ||
3200 | static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) | 3237 | static int orinoco_ioctl_setrate(struct net_device *dev, |
3238 | struct iw_request_info *info, | ||
3239 | struct iw_param *rrq, | ||
3240 | char *extra) | ||
3201 | { | 3241 | { |
3202 | struct orinoco_private *priv = netdev_priv(dev); | 3242 | struct orinoco_private *priv = netdev_priv(dev); |
3203 | int err = 0; | ||
3204 | int ratemode = -1; | 3243 | int ratemode = -1; |
3205 | int bitrate; /* 100s of kilobits */ | 3244 | int bitrate; /* 100s of kilobits */ |
3206 | int i; | 3245 | int i; |
@@ -3236,10 +3275,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) | |||
3236 | priv->bitratemode = ratemode; | 3275 | priv->bitratemode = ratemode; |
3237 | orinoco_unlock(priv, &flags); | 3276 | orinoco_unlock(priv, &flags); |
3238 | 3277 | ||
3239 | return err; | 3278 | return -EINPROGRESS; |
3240 | } | 3279 | } |
3241 | 3280 | ||
3242 | static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) | 3281 | static int orinoco_ioctl_getrate(struct net_device *dev, |
3282 | struct iw_request_info *info, | ||
3283 | struct iw_param *rrq, | ||
3284 | char *extra) | ||
3243 | { | 3285 | { |
3244 | struct orinoco_private *priv = netdev_priv(dev); | 3286 | struct orinoco_private *priv = netdev_priv(dev); |
3245 | hermes_t *hw = &priv->hw; | 3287 | hermes_t *hw = &priv->hw; |
@@ -3304,10 +3346,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) | |||
3304 | return err; | 3346 | return err; |
3305 | } | 3347 | } |
3306 | 3348 | ||
3307 | static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) | 3349 | static int orinoco_ioctl_setpower(struct net_device *dev, |
3350 | struct iw_request_info *info, | ||
3351 | struct iw_param *prq, | ||
3352 | char *extra) | ||
3308 | { | 3353 | { |
3309 | struct orinoco_private *priv = netdev_priv(dev); | 3354 | struct orinoco_private *priv = netdev_priv(dev); |
3310 | int err = 0; | 3355 | int err = -EINPROGRESS; /* Call commit handler */ |
3311 | unsigned long flags; | 3356 | unsigned long flags; |
3312 | 3357 | ||
3313 | if (orinoco_lock(priv, &flags) != 0) | 3358 | if (orinoco_lock(priv, &flags) != 0) |
@@ -3356,7 +3401,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) | |||
3356 | return err; | 3401 | return err; |
3357 | } | 3402 | } |
3358 | 3403 | ||
3359 | static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) | 3404 | static int orinoco_ioctl_getpower(struct net_device *dev, |
3405 | struct iw_request_info *info, | ||
3406 | struct iw_param *prq, | ||
3407 | char *extra) | ||
3360 | { | 3408 | { |
3361 | struct orinoco_private *priv = netdev_priv(dev); | 3409 | struct orinoco_private *priv = netdev_priv(dev); |
3362 | hermes_t *hw = &priv->hw; | 3410 | hermes_t *hw = &priv->hw; |
@@ -3404,7 +3452,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) | |||
3404 | return err; | 3452 | return err; |
3405 | } | 3453 | } |
3406 | 3454 | ||
3407 | static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) | 3455 | static int orinoco_ioctl_getretry(struct net_device *dev, |
3456 | struct iw_request_info *info, | ||
3457 | struct iw_param *rrq, | ||
3458 | char *extra) | ||
3408 | { | 3459 | { |
3409 | struct orinoco_private *priv = netdev_priv(dev); | 3460 | struct orinoco_private *priv = netdev_priv(dev); |
3410 | hermes_t *hw = &priv->hw; | 3461 | hermes_t *hw = &priv->hw; |
@@ -3455,10 +3506,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) | |||
3455 | return err; | 3506 | return err; |
3456 | } | 3507 | } |
3457 | 3508 | ||
3458 | static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) | 3509 | static int orinoco_ioctl_reset(struct net_device *dev, |
3510 | struct iw_request_info *info, | ||
3511 | void *wrqu, | ||
3512 | char *extra) | ||
3513 | { | ||
3514 | struct orinoco_private *priv = netdev_priv(dev); | ||
3515 | |||
3516 | if (! capable(CAP_NET_ADMIN)) | ||
3517 | return -EPERM; | ||
3518 | |||
3519 | if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { | ||
3520 | printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); | ||
3521 | |||
3522 | /* Firmware reset */ | ||
3523 | orinoco_reset(dev); | ||
3524 | } else { | ||
3525 | printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); | ||
3526 | |||
3527 | schedule_work(&priv->reset_work); | ||
3528 | } | ||
3529 | |||
3530 | return 0; | ||
3531 | } | ||
3532 | |||
3533 | static int orinoco_ioctl_setibssport(struct net_device *dev, | ||
3534 | struct iw_request_info *info, | ||
3535 | void *wrqu, | ||
3536 | char *extra) | ||
3537 | |||
3459 | { | 3538 | { |
3460 | struct orinoco_private *priv = netdev_priv(dev); | 3539 | struct orinoco_private *priv = netdev_priv(dev); |
3461 | int val = *( (int *) wrq->u.name ); | 3540 | int val = *( (int *) extra ); |
3462 | unsigned long flags; | 3541 | unsigned long flags; |
3463 | 3542 | ||
3464 | if (orinoco_lock(priv, &flags) != 0) | 3543 | if (orinoco_lock(priv, &flags) != 0) |
@@ -3470,28 +3549,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) | |||
3470 | set_port_type(priv); | 3549 | set_port_type(priv); |
3471 | 3550 | ||
3472 | orinoco_unlock(priv, &flags); | 3551 | orinoco_unlock(priv, &flags); |
3473 | return 0; | 3552 | return -EINPROGRESS; /* Call commit handler */ |
3474 | } | 3553 | } |
3475 | 3554 | ||
3476 | static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) | 3555 | static int orinoco_ioctl_getibssport(struct net_device *dev, |
3556 | struct iw_request_info *info, | ||
3557 | void *wrqu, | ||
3558 | char *extra) | ||
3477 | { | 3559 | { |
3478 | struct orinoco_private *priv = netdev_priv(dev); | 3560 | struct orinoco_private *priv = netdev_priv(dev); |
3479 | int *val = (int *)wrq->u.name; | 3561 | int *val = (int *) extra; |
3480 | unsigned long flags; | ||
3481 | |||
3482 | if (orinoco_lock(priv, &flags) != 0) | ||
3483 | return -EBUSY; | ||
3484 | 3562 | ||
3485 | *val = priv->ibss_port; | 3563 | *val = priv->ibss_port; |
3486 | orinoco_unlock(priv, &flags); | ||
3487 | |||
3488 | return 0; | 3564 | return 0; |
3489 | } | 3565 | } |
3490 | 3566 | ||
3491 | static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) | 3567 | static int orinoco_ioctl_setport3(struct net_device *dev, |
3568 | struct iw_request_info *info, | ||
3569 | void *wrqu, | ||
3570 | char *extra) | ||
3492 | { | 3571 | { |
3493 | struct orinoco_private *priv = netdev_priv(dev); | 3572 | struct orinoco_private *priv = netdev_priv(dev); |
3494 | int val = *( (int *) wrq->u.name ); | 3573 | int val = *( (int *) extra ); |
3495 | int err = 0; | 3574 | int err = 0; |
3496 | unsigned long flags; | 3575 | unsigned long flags; |
3497 | 3576 | ||
@@ -3520,51 +3599,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) | |||
3520 | err = -EINVAL; | 3599 | err = -EINVAL; |
3521 | } | 3600 | } |
3522 | 3601 | ||
3523 | if (! err) | 3602 | if (! err) { |
3524 | /* Actually update the mode we are using */ | 3603 | /* Actually update the mode we are using */ |
3525 | set_port_type(priv); | 3604 | set_port_type(priv); |
3605 | err = -EINPROGRESS; | ||
3606 | } | ||
3526 | 3607 | ||
3527 | orinoco_unlock(priv, &flags); | 3608 | orinoco_unlock(priv, &flags); |
3528 | 3609 | ||
3529 | return err; | 3610 | return err; |
3530 | } | 3611 | } |
3531 | 3612 | ||
3532 | static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) | 3613 | static int orinoco_ioctl_getport3(struct net_device *dev, |
3614 | struct iw_request_info *info, | ||
3615 | void *wrqu, | ||
3616 | char *extra) | ||
3617 | { | ||
3618 | struct orinoco_private *priv = netdev_priv(dev); | ||
3619 | int *val = (int *) extra; | ||
3620 | |||
3621 | *val = priv->prefer_port3; | ||
3622 | return 0; | ||
3623 | } | ||
3624 | |||
3625 | static int orinoco_ioctl_setpreamble(struct net_device *dev, | ||
3626 | struct iw_request_info *info, | ||
3627 | void *wrqu, | ||
3628 | char *extra) | ||
3533 | { | 3629 | { |
3534 | struct orinoco_private *priv = netdev_priv(dev); | 3630 | struct orinoco_private *priv = netdev_priv(dev); |
3535 | int *val = (int *)wrq->u.name; | ||
3536 | unsigned long flags; | 3631 | unsigned long flags; |
3632 | int val; | ||
3633 | |||
3634 | if (! priv->has_preamble) | ||
3635 | return -EOPNOTSUPP; | ||
3636 | |||
3637 | /* 802.11b has recently defined some short preamble. | ||
3638 | * Basically, the Phy header has been reduced in size. | ||
3639 | * This increase performance, especially at high rates | ||
3640 | * (the preamble is transmitted at 1Mb/s), unfortunately | ||
3641 | * this give compatibility troubles... - Jean II */ | ||
3642 | val = *( (int *) extra ); | ||
3537 | 3643 | ||
3538 | if (orinoco_lock(priv, &flags) != 0) | 3644 | if (orinoco_lock(priv, &flags) != 0) |
3539 | return -EBUSY; | 3645 | return -EBUSY; |
3540 | 3646 | ||
3541 | *val = priv->prefer_port3; | 3647 | if (val) |
3648 | priv->preamble = 1; | ||
3649 | else | ||
3650 | priv->preamble = 0; | ||
3651 | |||
3542 | orinoco_unlock(priv, &flags); | 3652 | orinoco_unlock(priv, &flags); |
3653 | |||
3654 | return -EINPROGRESS; /* Call commit handler */ | ||
3655 | } | ||
3656 | |||
3657 | static int orinoco_ioctl_getpreamble(struct net_device *dev, | ||
3658 | struct iw_request_info *info, | ||
3659 | void *wrqu, | ||
3660 | char *extra) | ||
3661 | { | ||
3662 | struct orinoco_private *priv = netdev_priv(dev); | ||
3663 | int *val = (int *) extra; | ||
3664 | |||
3665 | if (! priv->has_preamble) | ||
3666 | return -EOPNOTSUPP; | ||
3667 | |||
3668 | *val = priv->preamble; | ||
3543 | return 0; | 3669 | return 0; |
3544 | } | 3670 | } |
3545 | 3671 | ||
3672 | /* ioctl interface to hermes_read_ltv() | ||
3673 | * To use with iwpriv, pass the RID as the token argument, e.g. | ||
3674 | * iwpriv get_rid [0xfc00] | ||
3675 | * At least Wireless Tools 25 is required to use iwpriv. | ||
3676 | * For Wireless Tools 25 and 26 append "dummy" are the end. */ | ||
3677 | static int orinoco_ioctl_getrid(struct net_device *dev, | ||
3678 | struct iw_request_info *info, | ||
3679 | struct iw_point *data, | ||
3680 | char *extra) | ||
3681 | { | ||
3682 | struct orinoco_private *priv = netdev_priv(dev); | ||
3683 | hermes_t *hw = &priv->hw; | ||
3684 | int rid = data->flags; | ||
3685 | u16 length; | ||
3686 | int err; | ||
3687 | unsigned long flags; | ||
3688 | |||
3689 | /* It's a "get" function, but we don't want users to access the | ||
3690 | * WEP key and other raw firmware data */ | ||
3691 | if (! capable(CAP_NET_ADMIN)) | ||
3692 | return -EPERM; | ||
3693 | |||
3694 | if (rid < 0xfc00 || rid > 0xffff) | ||
3695 | return -EINVAL; | ||
3696 | |||
3697 | if (orinoco_lock(priv, &flags) != 0) | ||
3698 | return -EBUSY; | ||
3699 | |||
3700 | err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, | ||
3701 | extra); | ||
3702 | if (err) | ||
3703 | goto out; | ||
3704 | |||
3705 | data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), | ||
3706 | MAX_RID_LEN); | ||
3707 | |||
3708 | out: | ||
3709 | orinoco_unlock(priv, &flags); | ||
3710 | return err; | ||
3711 | } | ||
3712 | |||
3546 | /* Spy is used for link quality/strength measurements in Ad-Hoc mode | 3713 | /* Spy is used for link quality/strength measurements in Ad-Hoc mode |
3547 | * Jean II */ | 3714 | * Jean II */ |
3548 | static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) | 3715 | static int orinoco_ioctl_setspy(struct net_device *dev, |
3716 | struct iw_request_info *info, | ||
3717 | struct iw_point *srq, | ||
3718 | char *extra) | ||
3719 | |||
3549 | { | 3720 | { |
3550 | struct orinoco_private *priv = netdev_priv(dev); | 3721 | struct orinoco_private *priv = netdev_priv(dev); |
3551 | struct sockaddr address[IW_MAX_SPY]; | 3722 | struct sockaddr *address = (struct sockaddr *) extra; |
3552 | int number = srq->length; | 3723 | int number = srq->length; |
3553 | int i; | 3724 | int i; |
3554 | int err = 0; | ||
3555 | unsigned long flags; | 3725 | unsigned long flags; |
3556 | 3726 | ||
3557 | /* Check the number of addresses */ | ||
3558 | if (number > IW_MAX_SPY) | ||
3559 | return -E2BIG; | ||
3560 | |||
3561 | /* Get the data in the driver */ | ||
3562 | if (srq->pointer) { | ||
3563 | if (copy_from_user(address, srq->pointer, | ||
3564 | sizeof(struct sockaddr) * number)) | ||
3565 | return -EFAULT; | ||
3566 | } | ||
3567 | |||
3568 | /* Make sure nobody mess with the structure while we do */ | 3727 | /* Make sure nobody mess with the structure while we do */ |
3569 | if (orinoco_lock(priv, &flags) != 0) | 3728 | if (orinoco_lock(priv, &flags) != 0) |
3570 | return -EBUSY; | 3729 | return -EBUSY; |
@@ -3588,14 +3747,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) | |||
3588 | /* Now, let the others play */ | 3747 | /* Now, let the others play */ |
3589 | orinoco_unlock(priv, &flags); | 3748 | orinoco_unlock(priv, &flags); |
3590 | 3749 | ||
3591 | return err; | 3750 | /* Do NOT call commit handler */ |
3751 | return 0; | ||
3592 | } | 3752 | } |
3593 | 3753 | ||
3594 | static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) | 3754 | static int orinoco_ioctl_getspy(struct net_device *dev, |
3755 | struct iw_request_info *info, | ||
3756 | struct iw_point *srq, | ||
3757 | char *extra) | ||
3595 | { | 3758 | { |
3596 | struct orinoco_private *priv = netdev_priv(dev); | 3759 | struct orinoco_private *priv = netdev_priv(dev); |
3597 | struct sockaddr address[IW_MAX_SPY]; | 3760 | struct sockaddr *address = (struct sockaddr *) extra; |
3598 | struct iw_quality spy_stat[IW_MAX_SPY]; | ||
3599 | int number; | 3761 | int number; |
3600 | int i; | 3762 | int i; |
3601 | unsigned long flags; | 3763 | unsigned long flags; |
@@ -3604,7 +3766,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) | |||
3604 | return -EBUSY; | 3766 | return -EBUSY; |
3605 | 3767 | ||
3606 | number = priv->spy_number; | 3768 | number = priv->spy_number; |
3607 | if ((number > 0) && (srq->pointer)) { | 3769 | /* Create address struct */ |
3770 | for (i = 0; i < number; i++) { | ||
3771 | memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN); | ||
3772 | address[i].sa_family = AF_UNIX; | ||
3773 | } | ||
3774 | if (number > 0) { | ||
3608 | /* Create address struct */ | 3775 | /* Create address struct */ |
3609 | for (i = 0; i < number; i++) { | 3776 | for (i = 0; i < number; i++) { |
3610 | memcpy(address[i].sa_data, priv->spy_address[i], | 3777 | memcpy(address[i].sa_data, priv->spy_address[i], |
@@ -3615,344 +3782,153 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) | |||
3615 | /* In theory, we should disable irqs while copying the stats | 3782 | /* In theory, we should disable irqs while copying the stats |
3616 | * because the rx path might update it in the middle... | 3783 | * because the rx path might update it in the middle... |
3617 | * Bah, who care ? - Jean II */ | 3784 | * Bah, who care ? - Jean II */ |
3618 | memcpy(&spy_stat, priv->spy_stat, | 3785 | memcpy(extra + (sizeof(struct sockaddr) * number), |
3619 | sizeof(struct iw_quality) * IW_MAX_SPY); | 3786 | priv->spy_stat, sizeof(struct iw_quality) * number); |
3620 | for (i=0; i < number; i++) | ||
3621 | priv->spy_stat[i].updated = 0; | ||
3622 | } | 3787 | } |
3788 | /* Reset updated flags. */ | ||
3789 | for (i = 0; i < number; i++) | ||
3790 | priv->spy_stat[i].updated = 0; | ||
3623 | 3791 | ||
3624 | orinoco_unlock(priv, &flags); | 3792 | orinoco_unlock(priv, &flags); |
3625 | 3793 | ||
3626 | /* Push stuff to user space */ | ||
3627 | srq->length = number; | 3794 | srq->length = number; |
3628 | if(copy_to_user(srq->pointer, address, | ||
3629 | sizeof(struct sockaddr) * number)) | ||
3630 | return -EFAULT; | ||
3631 | if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), | ||
3632 | &spy_stat, sizeof(struct iw_quality) * number)) | ||
3633 | return -EFAULT; | ||
3634 | 3795 | ||
3635 | return 0; | 3796 | return 0; |
3636 | } | 3797 | } |
3637 | 3798 | ||
3638 | static int | 3799 | /* Commit handler, called after set operations */ |
3639 | orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 3800 | static int orinoco_ioctl_commit(struct net_device *dev, |
3801 | struct iw_request_info *info, | ||
3802 | void *wrqu, | ||
3803 | char *extra) | ||
3640 | { | 3804 | { |
3641 | struct orinoco_private *priv = netdev_priv(dev); | 3805 | struct orinoco_private *priv = netdev_priv(dev); |
3642 | struct iwreq *wrq = (struct iwreq *)rq; | 3806 | struct hermes *hw = &priv->hw; |
3643 | int err = 0; | ||
3644 | int tmp; | ||
3645 | int changed = 0; | ||
3646 | unsigned long flags; | 3807 | unsigned long flags; |
3808 | int err = 0; | ||
3647 | 3809 | ||
3648 | TRACE_ENTER(dev->name); | 3810 | if (!priv->open) |
3649 | 3811 | return 0; | |
3650 | /* In theory, we could allow most of the the SET stuff to be | ||
3651 | * done. In practice, the lapse of time at startup when the | ||
3652 | * card is not ready is very short, so why bother... Note | ||
3653 | * that netif_device_present is different from up/down | ||
3654 | * (ifconfig), when the device is not yet up, it is usually | ||
3655 | * already ready... Jean II */ | ||
3656 | if (! netif_device_present(dev)) | ||
3657 | return -ENODEV; | ||
3658 | |||
3659 | switch (cmd) { | ||
3660 | case SIOCGIWNAME: | ||
3661 | strcpy(wrq->u.name, "IEEE 802.11-DS"); | ||
3662 | break; | ||
3663 | |||
3664 | case SIOCGIWAP: | ||
3665 | wrq->u.ap_addr.sa_family = ARPHRD_ETHER; | ||
3666 | err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); | ||
3667 | break; | ||
3668 | |||
3669 | case SIOCGIWRANGE: | ||
3670 | err = orinoco_ioctl_getiwrange(dev, &wrq->u.data); | ||
3671 | break; | ||
3672 | |||
3673 | case SIOCSIWMODE: | ||
3674 | if (orinoco_lock(priv, &flags) != 0) | ||
3675 | return -EBUSY; | ||
3676 | switch (wrq->u.mode) { | ||
3677 | case IW_MODE_ADHOC: | ||
3678 | if (! (priv->has_ibss || priv->has_port3) ) | ||
3679 | err = -EINVAL; | ||
3680 | else { | ||
3681 | priv->iw_mode = IW_MODE_ADHOC; | ||
3682 | changed = 1; | ||
3683 | } | ||
3684 | break; | ||
3685 | |||
3686 | case IW_MODE_INFRA: | ||
3687 | priv->iw_mode = IW_MODE_INFRA; | ||
3688 | changed = 1; | ||
3689 | break; | ||
3690 | |||
3691 | default: | ||
3692 | err = -EINVAL; | ||
3693 | break; | ||
3694 | } | ||
3695 | set_port_type(priv); | ||
3696 | orinoco_unlock(priv, &flags); | ||
3697 | break; | ||
3698 | |||
3699 | case SIOCGIWMODE: | ||
3700 | if (orinoco_lock(priv, &flags) != 0) | ||
3701 | return -EBUSY; | ||
3702 | wrq->u.mode = priv->iw_mode; | ||
3703 | orinoco_unlock(priv, &flags); | ||
3704 | break; | ||
3705 | |||
3706 | case SIOCSIWENCODE: | ||
3707 | err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding); | ||
3708 | if (! err) | ||
3709 | changed = 1; | ||
3710 | break; | ||
3711 | |||
3712 | case SIOCGIWENCODE: | ||
3713 | if (! capable(CAP_NET_ADMIN)) { | ||
3714 | err = -EPERM; | ||
3715 | break; | ||
3716 | } | ||
3717 | |||
3718 | err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding); | ||
3719 | break; | ||
3720 | |||
3721 | case SIOCSIWESSID: | ||
3722 | err = orinoco_ioctl_setessid(dev, &wrq->u.essid); | ||
3723 | if (! err) | ||
3724 | changed = 1; | ||
3725 | break; | ||
3726 | |||
3727 | case SIOCGIWESSID: | ||
3728 | err = orinoco_ioctl_getessid(dev, &wrq->u.essid); | ||
3729 | break; | ||
3730 | |||
3731 | case SIOCSIWNICKN: | ||
3732 | err = orinoco_ioctl_setnick(dev, &wrq->u.data); | ||
3733 | if (! err) | ||
3734 | changed = 1; | ||
3735 | break; | ||
3736 | |||
3737 | case SIOCGIWNICKN: | ||
3738 | err = orinoco_ioctl_getnick(dev, &wrq->u.data); | ||
3739 | break; | ||
3740 | |||
3741 | case SIOCGIWFREQ: | ||
3742 | tmp = orinoco_hw_get_freq(priv); | ||
3743 | if (tmp < 0) { | ||
3744 | err = tmp; | ||
3745 | } else { | ||
3746 | wrq->u.freq.m = tmp; | ||
3747 | wrq->u.freq.e = 1; | ||
3748 | } | ||
3749 | break; | ||
3750 | |||
3751 | case SIOCSIWFREQ: | ||
3752 | err = orinoco_ioctl_setfreq(dev, &wrq->u.freq); | ||
3753 | if (! err) | ||
3754 | changed = 1; | ||
3755 | break; | ||
3756 | |||
3757 | case SIOCGIWSENS: | ||
3758 | err = orinoco_ioctl_getsens(dev, &wrq->u.sens); | ||
3759 | break; | ||
3760 | |||
3761 | case SIOCSIWSENS: | ||
3762 | err = orinoco_ioctl_setsens(dev, &wrq->u.sens); | ||
3763 | if (! err) | ||
3764 | changed = 1; | ||
3765 | break; | ||
3766 | |||
3767 | case SIOCGIWRTS: | ||
3768 | wrq->u.rts.value = priv->rts_thresh; | ||
3769 | wrq->u.rts.disabled = (wrq->u.rts.value == 2347); | ||
3770 | wrq->u.rts.fixed = 1; | ||
3771 | break; | ||
3772 | |||
3773 | case SIOCSIWRTS: | ||
3774 | err = orinoco_ioctl_setrts(dev, &wrq->u.rts); | ||
3775 | if (! err) | ||
3776 | changed = 1; | ||
3777 | break; | ||
3778 | |||
3779 | case SIOCSIWFRAG: | ||
3780 | err = orinoco_ioctl_setfrag(dev, &wrq->u.frag); | ||
3781 | if (! err) | ||
3782 | changed = 1; | ||
3783 | break; | ||
3784 | |||
3785 | case SIOCGIWFRAG: | ||
3786 | err = orinoco_ioctl_getfrag(dev, &wrq->u.frag); | ||
3787 | break; | ||
3788 | |||
3789 | case SIOCSIWRATE: | ||
3790 | err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate); | ||
3791 | if (! err) | ||
3792 | changed = 1; | ||
3793 | break; | ||
3794 | |||
3795 | case SIOCGIWRATE: | ||
3796 | err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate); | ||
3797 | break; | ||
3798 | |||
3799 | case SIOCSIWPOWER: | ||
3800 | err = orinoco_ioctl_setpower(dev, &wrq->u.power); | ||
3801 | if (! err) | ||
3802 | changed = 1; | ||
3803 | break; | ||
3804 | |||
3805 | case SIOCGIWPOWER: | ||
3806 | err = orinoco_ioctl_getpower(dev, &wrq->u.power); | ||
3807 | break; | ||
3808 | |||
3809 | case SIOCGIWTXPOW: | ||
3810 | /* The card only supports one tx power, so this is easy */ | ||
3811 | wrq->u.txpower.value = 15; /* dBm */ | ||
3812 | wrq->u.txpower.fixed = 1; | ||
3813 | wrq->u.txpower.disabled = 0; | ||
3814 | wrq->u.txpower.flags = IW_TXPOW_DBM; | ||
3815 | break; | ||
3816 | 3812 | ||
3817 | case SIOCSIWRETRY: | 3813 | if (priv->broken_disableport) { |
3818 | err = -EOPNOTSUPP; | 3814 | orinoco_reset(dev); |
3819 | break; | 3815 | return 0; |
3816 | } | ||
3820 | 3817 | ||
3821 | case SIOCGIWRETRY: | 3818 | if (orinoco_lock(priv, &flags) != 0) |
3822 | err = orinoco_ioctl_getretry(dev, &wrq->u.retry); | 3819 | return err; |
3823 | break; | ||
3824 | 3820 | ||
3825 | case SIOCSIWSPY: | 3821 | err = hermes_disable_port(hw, 0); |
3826 | err = orinoco_ioctl_setspy(dev, &wrq->u.data); | 3822 | if (err) { |
3827 | break; | 3823 | printk(KERN_WARNING "%s: Unable to disable port " |
3824 | "while reconfiguring card\n", dev->name); | ||
3825 | priv->broken_disableport = 1; | ||
3826 | goto out; | ||
3827 | } | ||
3828 | 3828 | ||
3829 | case SIOCGIWSPY: | 3829 | err = __orinoco_program_rids(dev); |
3830 | err = orinoco_ioctl_getspy(dev, &wrq->u.data); | 3830 | if (err) { |
3831 | break; | 3831 | printk(KERN_WARNING "%s: Unable to reconfigure card\n", |
3832 | dev->name); | ||
3833 | goto out; | ||
3834 | } | ||
3832 | 3835 | ||
3833 | case SIOCGIWPRIV: | 3836 | err = hermes_enable_port(hw, 0); |
3834 | if (wrq->u.data.pointer) { | 3837 | if (err) { |
3835 | struct iw_priv_args privtab[] = { | 3838 | printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", |
3836 | { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, | 3839 | dev->name); |
3837 | { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, | 3840 | goto out; |
3838 | { SIOCIWFIRSTPRIV + 0x2, | 3841 | } |
3839 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3840 | 0, "set_port3" }, | ||
3841 | { SIOCIWFIRSTPRIV + 0x3, 0, | ||
3842 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3843 | "get_port3" }, | ||
3844 | { SIOCIWFIRSTPRIV + 0x4, | ||
3845 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3846 | 0, "set_preamble" }, | ||
3847 | { SIOCIWFIRSTPRIV + 0x5, 0, | ||
3848 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3849 | "get_preamble" }, | ||
3850 | { SIOCIWFIRSTPRIV + 0x6, | ||
3851 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3852 | 0, "set_ibssport" }, | ||
3853 | { SIOCIWFIRSTPRIV + 0x7, 0, | ||
3854 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3855 | "get_ibssport" }, | ||
3856 | }; | ||
3857 | |||
3858 | wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); | ||
3859 | if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) | ||
3860 | err = -EFAULT; | ||
3861 | } | ||
3862 | break; | ||
3863 | |||
3864 | case SIOCIWFIRSTPRIV + 0x0: /* force_reset */ | ||
3865 | case SIOCIWFIRSTPRIV + 0x1: /* card_reset */ | ||
3866 | if (! capable(CAP_NET_ADMIN)) { | ||
3867 | err = -EPERM; | ||
3868 | break; | ||
3869 | } | ||
3870 | |||
3871 | printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); | ||
3872 | 3842 | ||
3843 | out: | ||
3844 | if (err) { | ||
3845 | printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); | ||
3873 | schedule_work(&priv->reset_work); | 3846 | schedule_work(&priv->reset_work); |
3874 | break; | 3847 | err = 0; |
3875 | 3848 | } | |
3876 | case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ | ||
3877 | if (! capable(CAP_NET_ADMIN)) { | ||
3878 | err = -EPERM; | ||
3879 | break; | ||
3880 | } | ||
3881 | |||
3882 | err = orinoco_ioctl_setport3(dev, wrq); | ||
3883 | if (! err) | ||
3884 | changed = 1; | ||
3885 | break; | ||
3886 | |||
3887 | case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */ | ||
3888 | err = orinoco_ioctl_getport3(dev, wrq); | ||
3889 | break; | ||
3890 | |||
3891 | case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */ | ||
3892 | if (! capable(CAP_NET_ADMIN)) { | ||
3893 | err = -EPERM; | ||
3894 | break; | ||
3895 | } | ||
3896 | |||
3897 | /* 802.11b has recently defined some short preamble. | ||
3898 | * Basically, the Phy header has been reduced in size. | ||
3899 | * This increase performance, especially at high rates | ||
3900 | * (the preamble is transmitted at 1Mb/s), unfortunately | ||
3901 | * this give compatibility troubles... - Jean II */ | ||
3902 | if(priv->has_preamble) { | ||
3903 | int val = *( (int *) wrq->u.name ); | ||
3904 | |||
3905 | if (orinoco_lock(priv, &flags) != 0) | ||
3906 | return -EBUSY; | ||
3907 | if (val) | ||
3908 | priv->preamble = 1; | ||
3909 | else | ||
3910 | priv->preamble = 0; | ||
3911 | orinoco_unlock(priv, &flags); | ||
3912 | changed = 1; | ||
3913 | } else | ||
3914 | err = -EOPNOTSUPP; | ||
3915 | break; | ||
3916 | 3849 | ||
3917 | case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */ | 3850 | orinoco_unlock(priv, &flags); |
3918 | if(priv->has_preamble) { | 3851 | return err; |
3919 | int *val = (int *)wrq->u.name; | 3852 | } |
3920 | 3853 | ||
3921 | if (orinoco_lock(priv, &flags) != 0) | 3854 | static const struct iw_priv_args orinoco_privtab[] = { |
3922 | return -EBUSY; | 3855 | { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, |
3923 | *val = priv->preamble; | 3856 | { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, |
3924 | orinoco_unlock(priv, &flags); | 3857 | { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
3925 | } else | 3858 | 0, "set_port3" }, |
3926 | err = -EOPNOTSUPP; | 3859 | { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
3927 | break; | 3860 | "get_port3" }, |
3928 | case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */ | 3861 | { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
3929 | if (! capable(CAP_NET_ADMIN)) { | 3862 | 0, "set_preamble" }, |
3930 | err = -EPERM; | 3863 | { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
3931 | break; | 3864 | "get_preamble" }, |
3932 | } | 3865 | { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
3866 | 0, "set_ibssport" }, | ||
3867 | { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
3868 | "get_ibssport" }, | ||
3869 | { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, | ||
3870 | "get_rid" }, | ||
3871 | }; | ||
3933 | 3872 | ||
3934 | err = orinoco_ioctl_setibssport(dev, wrq); | ||
3935 | if (! err) | ||
3936 | changed = 1; | ||
3937 | break; | ||
3938 | 3873 | ||
3939 | case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */ | 3874 | /* |
3940 | err = orinoco_ioctl_getibssport(dev, wrq); | 3875 | * Structures to export the Wireless Handlers |
3941 | break; | 3876 | */ |
3942 | 3877 | ||
3943 | default: | 3878 | static const iw_handler orinoco_handler[] = { |
3944 | err = -EOPNOTSUPP; | 3879 | [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit, |
3945 | } | 3880 | [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname, |
3946 | 3881 | [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq, | |
3947 | if (! err && changed && netif_running(dev)) { | 3882 | [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq, |
3948 | err = orinoco_reconfigure(dev); | 3883 | [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode, |
3949 | } | 3884 | [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode, |
3885 | [SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens, | ||
3886 | [SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens, | ||
3887 | [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange, | ||
3888 | [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy, | ||
3889 | [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy, | ||
3890 | [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap, | ||
3891 | [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid, | ||
3892 | [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid, | ||
3893 | [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick, | ||
3894 | [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick, | ||
3895 | [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate, | ||
3896 | [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate, | ||
3897 | [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts, | ||
3898 | [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts, | ||
3899 | [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag, | ||
3900 | [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag, | ||
3901 | [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry, | ||
3902 | [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode, | ||
3903 | [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode, | ||
3904 | [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower, | ||
3905 | [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower, | ||
3906 | }; | ||
3950 | 3907 | ||
3951 | TRACE_EXIT(dev->name); | ||
3952 | 3908 | ||
3953 | return err; | 3909 | /* |
3954 | } | 3910 | Added typecasting since we no longer use iwreq_data -- Moustafa |
3911 | */ | ||
3912 | static const iw_handler orinoco_private_handler[] = { | ||
3913 | [0] (iw_handler) orinoco_ioctl_reset, | ||
3914 | [1] (iw_handler) orinoco_ioctl_reset, | ||
3915 | [2] (iw_handler) orinoco_ioctl_setport3, | ||
3916 | [3] (iw_handler) orinoco_ioctl_getport3, | ||
3917 | [4] (iw_handler) orinoco_ioctl_setpreamble, | ||
3918 | [5] (iw_handler) orinoco_ioctl_getpreamble, | ||
3919 | [6] (iw_handler) orinoco_ioctl_setibssport, | ||
3920 | [7] (iw_handler) orinoco_ioctl_getibssport, | ||
3921 | [9] (iw_handler) orinoco_ioctl_getrid, | ||
3922 | }; | ||
3955 | 3923 | ||
3924 | static const struct iw_handler_def orinoco_handler_def = { | ||
3925 | .num_standard = ARRAY_SIZE(orinoco_handler), | ||
3926 | .num_private = ARRAY_SIZE(orinoco_private_handler), | ||
3927 | .num_private_args = ARRAY_SIZE(orinoco_privtab), | ||
3928 | .standard = orinoco_handler, | ||
3929 | .private = orinoco_private_handler, | ||
3930 | .private_args = orinoco_privtab, | ||
3931 | }; | ||
3956 | 3932 | ||
3957 | /********************************************************************/ | 3933 | /********************************************************************/ |
3958 | /* Debugging */ | 3934 | /* Debugging */ |