diff options
author | David Kilroy <kilroyd@googlemail.com> | 2009-02-04 18:05:56 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:44:33 -0500 |
commit | cb1576a829826d56fab59e22aa3af8c5a7db9936 (patch) | |
tree | 9d5fcd385dc1e28e7ddb89412bbdfc433d23c769 /drivers/net/wireless/orinoco/main.c | |
parent | 712a4342a0d89e855a03ba06fb11f7eb29456d45 (diff) |
orinoco: Move WEXT handlers into a separate file
No functional change.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/orinoco/main.c')
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 2355 |
1 files changed, 6 insertions, 2349 deletions
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index a340c7d75dd1..54dfc4540b82 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -95,6 +95,8 @@ | |||
95 | #include "scan.h" | 95 | #include "scan.h" |
96 | #include "mic.h" | 96 | #include "mic.h" |
97 | #include "fw.h" | 97 | #include "fw.h" |
98 | #include "wext.h" | ||
99 | #include "main.h" | ||
98 | 100 | ||
99 | #include "orinoco.h" | 101 | #include "orinoco.h" |
100 | 102 | ||
@@ -125,22 +127,11 @@ module_param(ignore_disconnect, int, 0644); | |||
125 | MODULE_PARM_DESC(ignore_disconnect, | 127 | MODULE_PARM_DESC(ignore_disconnect, |
126 | "Don't report lost link to the network layer"); | 128 | "Don't report lost link to the network layer"); |
127 | 129 | ||
128 | static int force_monitor; /* = 0 */ | 130 | int force_monitor; /* = 0 */ |
129 | module_param(force_monitor, int, 0644); | 131 | module_param(force_monitor, int, 0644); |
130 | MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); | 132 | MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); |
131 | 133 | ||
132 | /********************************************************************/ | 134 | /********************************************************************/ |
133 | /* Compile time configuration and compatibility stuff */ | ||
134 | /********************************************************************/ | ||
135 | |||
136 | /* We do this this way to avoid ifdefs in the actual code */ | ||
137 | #ifdef WIRELESS_SPY | ||
138 | #define SPY_NUMBER(priv) (priv->spy_data.spy_number) | ||
139 | #else | ||
140 | #define SPY_NUMBER(priv) 0 | ||
141 | #endif /* WIRELESS_SPY */ | ||
142 | |||
143 | /********************************************************************/ | ||
144 | /* Internal constants */ | 135 | /* Internal constants */ |
145 | /********************************************************************/ | 136 | /********************************************************************/ |
146 | 137 | ||
@@ -170,9 +161,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | |||
170 | | HERMES_EV_WTERR | HERMES_EV_INFO \ | 161 | | HERMES_EV_WTERR | HERMES_EV_INFO \ |
171 | | HERMES_EV_INFDROP) | 162 | | HERMES_EV_INFDROP) |
172 | 163 | ||
173 | #define MAX_RID_LEN 1024 | ||
174 | |||
175 | static const struct iw_handler_def orinoco_handler_def; | ||
176 | static const struct ethtool_ops orinoco_ethtool_ops; | 164 | static const struct ethtool_ops orinoco_ethtool_ops; |
177 | 165 | ||
178 | /********************************************************************/ | 166 | /********************************************************************/ |
@@ -221,14 +209,13 @@ struct orinoco_rx_data { | |||
221 | /* Function prototypes */ | 209 | /* Function prototypes */ |
222 | /********************************************************************/ | 210 | /********************************************************************/ |
223 | 211 | ||
224 | static int __orinoco_program_rids(struct net_device *dev); | ||
225 | static void __orinoco_set_multicast_list(struct net_device *dev); | 212 | static void __orinoco_set_multicast_list(struct net_device *dev); |
226 | 213 | ||
227 | /********************************************************************/ | 214 | /********************************************************************/ |
228 | /* Internal helper functions */ | 215 | /* Internal helper functions */ |
229 | /********************************************************************/ | 216 | /********************************************************************/ |
230 | 217 | ||
231 | static inline void set_port_type(struct orinoco_private *priv) | 218 | void set_port_type(struct orinoco_private *priv) |
232 | { | 219 | { |
233 | switch (priv->iw_mode) { | 220 | switch (priv->iw_mode) { |
234 | case IW_MODE_INFRA: | 221 | case IW_MODE_INFRA: |
@@ -254,33 +241,6 @@ static inline void set_port_type(struct orinoco_private *priv) | |||
254 | } | 241 | } |
255 | } | 242 | } |
256 | 243 | ||
257 | static inline u8 *orinoco_get_ie(u8 *data, size_t len, | ||
258 | enum ieee80211_eid eid) | ||
259 | { | ||
260 | u8 *p = data; | ||
261 | while ((p + 2) < (data + len)) { | ||
262 | if (p[0] == eid) | ||
263 | return p; | ||
264 | p += p[1] + 2; | ||
265 | } | ||
266 | return NULL; | ||
267 | } | ||
268 | |||
269 | #define WPA_OUI_TYPE "\x00\x50\xF2\x01" | ||
270 | #define WPA_SELECTOR_LEN 4 | ||
271 | static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) | ||
272 | { | ||
273 | u8 *p = data; | ||
274 | while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { | ||
275 | if ((p[0] == WLAN_EID_GENERIC) && | ||
276 | (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) | ||
277 | return p; | ||
278 | p += p[1] + 2; | ||
279 | } | ||
280 | return NULL; | ||
281 | } | ||
282 | |||
283 | |||
284 | /********************************************************************/ | 244 | /********************************************************************/ |
285 | /* Device methods */ | 245 | /* Device methods */ |
286 | /********************************************************************/ | 246 | /********************************************************************/ |
@@ -330,68 +290,6 @@ static struct net_device_stats *orinoco_get_stats(struct net_device *dev) | |||
330 | return &priv->stats; | 290 | return &priv->stats; |
331 | } | 291 | } |
332 | 292 | ||
333 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) | ||
334 | { | ||
335 | struct orinoco_private *priv = netdev_priv(dev); | ||
336 | hermes_t *hw = &priv->hw; | ||
337 | struct iw_statistics *wstats = &priv->wstats; | ||
338 | int err; | ||
339 | unsigned long flags; | ||
340 | |||
341 | if (!netif_device_present(dev)) { | ||
342 | printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", | ||
343 | dev->name); | ||
344 | return NULL; /* FIXME: Can we do better than this? */ | ||
345 | } | ||
346 | |||
347 | /* If busy, return the old stats. Returning NULL may cause | ||
348 | * the interface to disappear from /proc/net/wireless */ | ||
349 | if (orinoco_lock(priv, &flags) != 0) | ||
350 | return wstats; | ||
351 | |||
352 | /* We can't really wait for the tallies inquiry command to | ||
353 | * complete, so we just use the previous results and trigger | ||
354 | * a new tallies inquiry command for next time - Jean II */ | ||
355 | /* FIXME: Really we should wait for the inquiry to come back - | ||
356 | * as it is the stats we give don't make a whole lot of sense. | ||
357 | * Unfortunately, it's not clear how to do that within the | ||
358 | * wireless extensions framework: I think we're in user | ||
359 | * context, but a lock seems to be held by the time we get in | ||
360 | * here so we're not safe to sleep here. */ | ||
361 | hermes_inquire(hw, HERMES_INQ_TALLIES); | ||
362 | |||
363 | if (priv->iw_mode == IW_MODE_ADHOC) { | ||
364 | memset(&wstats->qual, 0, sizeof(wstats->qual)); | ||
365 | /* If a spy address is defined, we report stats of the | ||
366 | * first spy address - Jean II */ | ||
367 | if (SPY_NUMBER(priv)) { | ||
368 | wstats->qual.qual = priv->spy_data.spy_stat[0].qual; | ||
369 | wstats->qual.level = priv->spy_data.spy_stat[0].level; | ||
370 | wstats->qual.noise = priv->spy_data.spy_stat[0].noise; | ||
371 | wstats->qual.updated = | ||
372 | priv->spy_data.spy_stat[0].updated; | ||
373 | } | ||
374 | } else { | ||
375 | struct { | ||
376 | __le16 qual, signal, noise, unused; | ||
377 | } __attribute__ ((packed)) cq; | ||
378 | |||
379 | err = HERMES_READ_RECORD(hw, USER_BAP, | ||
380 | HERMES_RID_COMMSQUALITY, &cq); | ||
381 | |||
382 | if (!err) { | ||
383 | wstats->qual.qual = (int)le16_to_cpu(cq.qual); | ||
384 | wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; | ||
385 | wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; | ||
386 | wstats->qual.updated = | ||
387 | IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | orinoco_unlock(priv, &flags); | ||
392 | return wstats; | ||
393 | } | ||
394 | |||
395 | static void orinoco_set_multicast_list(struct net_device *dev) | 293 | static void orinoco_set_multicast_list(struct net_device *dev) |
396 | { | 294 | { |
397 | struct orinoco_private *priv = netdev_priv(dev); | 295 | struct orinoco_private *priv = netdev_priv(dev); |
@@ -1716,7 +1614,7 @@ int orinoco_reinit_firmware(struct net_device *dev) | |||
1716 | } | 1614 | } |
1717 | EXPORT_SYMBOL(orinoco_reinit_firmware); | 1615 | EXPORT_SYMBOL(orinoco_reinit_firmware); |
1718 | 1616 | ||
1719 | static int __orinoco_program_rids(struct net_device *dev) | 1617 | int __orinoco_program_rids(struct net_device *dev) |
1720 | { | 1618 | { |
1721 | struct orinoco_private *priv = netdev_priv(dev); | 1619 | struct orinoco_private *priv = netdev_priv(dev); |
1722 | hermes_t *hw = &priv->hw; | 1620 | hermes_t *hw = &priv->hw; |
@@ -1970,7 +1868,7 @@ __orinoco_set_multicast_list(struct net_device *dev) | |||
1970 | 1868 | ||
1971 | /* This must be called from user context, without locks held - use | 1869 | /* This must be called from user context, without locks held - use |
1972 | * schedule_work() */ | 1870 | * schedule_work() */ |
1973 | static void orinoco_reset(struct work_struct *work) | 1871 | void orinoco_reset(struct work_struct *work) |
1974 | { | 1872 | { |
1975 | struct orinoco_private *priv = | 1873 | struct orinoco_private *priv = |
1976 | container_of(work, struct orinoco_private, reset_work); | 1874 | container_of(work, struct orinoco_private, reset_work); |
@@ -2711,2247 +2609,6 @@ void free_orinocodev(struct net_device *dev) | |||
2711 | } | 2609 | } |
2712 | EXPORT_SYMBOL(free_orinocodev); | 2610 | EXPORT_SYMBOL(free_orinocodev); |
2713 | 2611 | ||
2714 | /********************************************************************/ | ||
2715 | /* Wireless extensions */ | ||
2716 | /********************************************************************/ | ||
2717 | |||
2718 | static int orinoco_ioctl_getname(struct net_device *dev, | ||
2719 | struct iw_request_info *info, | ||
2720 | char *name, | ||
2721 | char *extra) | ||
2722 | { | ||
2723 | struct orinoco_private *priv = netdev_priv(dev); | ||
2724 | int numrates; | ||
2725 | int err; | ||
2726 | |||
2727 | err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0); | ||
2728 | |||
2729 | if (!err && (numrates > 2)) | ||
2730 | strcpy(name, "IEEE 802.11b"); | ||
2731 | else | ||
2732 | strcpy(name, "IEEE 802.11-DS"); | ||
2733 | |||
2734 | return 0; | ||
2735 | } | ||
2736 | |||
2737 | static int orinoco_ioctl_setwap(struct net_device *dev, | ||
2738 | struct iw_request_info *info, | ||
2739 | struct sockaddr *ap_addr, | ||
2740 | char *extra) | ||
2741 | { | ||
2742 | struct orinoco_private *priv = netdev_priv(dev); | ||
2743 | int err = -EINPROGRESS; /* Call commit handler */ | ||
2744 | unsigned long flags; | ||
2745 | static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
2746 | static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
2747 | |||
2748 | if (orinoco_lock(priv, &flags) != 0) | ||
2749 | return -EBUSY; | ||
2750 | |||
2751 | /* Enable automatic roaming - no sanity checks are needed */ | ||
2752 | if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 || | ||
2753 | memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) { | ||
2754 | priv->bssid_fixed = 0; | ||
2755 | memset(priv->desired_bssid, 0, ETH_ALEN); | ||
2756 | |||
2757 | /* "off" means keep existing connection */ | ||
2758 | if (ap_addr->sa_data[0] == 0) { | ||
2759 | __orinoco_hw_set_wap(priv); | ||
2760 | err = 0; | ||
2761 | } | ||
2762 | goto out; | ||
2763 | } | ||
2764 | |||
2765 | if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { | ||
2766 | printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " | ||
2767 | "support manual roaming\n", | ||
2768 | dev->name); | ||
2769 | err = -EOPNOTSUPP; | ||
2770 | goto out; | ||
2771 | } | ||
2772 | |||
2773 | if (priv->iw_mode != IW_MODE_INFRA) { | ||
2774 | printk(KERN_WARNING "%s: Manual roaming supported only in " | ||
2775 | "managed mode\n", dev->name); | ||
2776 | err = -EOPNOTSUPP; | ||
2777 | goto out; | ||
2778 | } | ||
2779 | |||
2780 | /* Intersil firmware hangs without Desired ESSID */ | ||
2781 | if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && | ||
2782 | strlen(priv->desired_essid) == 0) { | ||
2783 | printk(KERN_WARNING "%s: Desired ESSID must be set for " | ||
2784 | "manual roaming\n", dev->name); | ||
2785 | err = -EOPNOTSUPP; | ||
2786 | goto out; | ||
2787 | } | ||
2788 | |||
2789 | /* Finally, enable manual roaming */ | ||
2790 | priv->bssid_fixed = 1; | ||
2791 | memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); | ||
2792 | |||
2793 | out: | ||
2794 | orinoco_unlock(priv, &flags); | ||
2795 | return err; | ||
2796 | } | ||
2797 | |||
2798 | static int orinoco_ioctl_getwap(struct net_device *dev, | ||
2799 | struct iw_request_info *info, | ||
2800 | struct sockaddr *ap_addr, | ||
2801 | char *extra) | ||
2802 | { | ||
2803 | struct orinoco_private *priv = netdev_priv(dev); | ||
2804 | |||
2805 | hermes_t *hw = &priv->hw; | ||
2806 | int err = 0; | ||
2807 | unsigned long flags; | ||
2808 | |||
2809 | if (orinoco_lock(priv, &flags) != 0) | ||
2810 | return -EBUSY; | ||
2811 | |||
2812 | ap_addr->sa_family = ARPHRD_ETHER; | ||
2813 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | ||
2814 | ETH_ALEN, NULL, ap_addr->sa_data); | ||
2815 | |||
2816 | orinoco_unlock(priv, &flags); | ||
2817 | |||
2818 | return err; | ||
2819 | } | ||
2820 | |||
2821 | static int orinoco_ioctl_setmode(struct net_device *dev, | ||
2822 | struct iw_request_info *info, | ||
2823 | u32 *mode, | ||
2824 | char *extra) | ||
2825 | { | ||
2826 | struct orinoco_private *priv = netdev_priv(dev); | ||
2827 | int err = -EINPROGRESS; /* Call commit handler */ | ||
2828 | unsigned long flags; | ||
2829 | |||
2830 | if (priv->iw_mode == *mode) | ||
2831 | return 0; | ||
2832 | |||
2833 | if (orinoco_lock(priv, &flags) != 0) | ||
2834 | return -EBUSY; | ||
2835 | |||
2836 | switch (*mode) { | ||
2837 | case IW_MODE_ADHOC: | ||
2838 | if (!priv->has_ibss && !priv->has_port3) | ||
2839 | err = -EOPNOTSUPP; | ||
2840 | break; | ||
2841 | |||
2842 | case IW_MODE_INFRA: | ||
2843 | break; | ||
2844 | |||
2845 | case IW_MODE_MONITOR: | ||
2846 | if (priv->broken_monitor && !force_monitor) { | ||
2847 | printk(KERN_WARNING "%s: Monitor mode support is " | ||
2848 | "buggy in this firmware, not enabling\n", | ||
2849 | dev->name); | ||
2850 | err = -EOPNOTSUPP; | ||
2851 | } | ||
2852 | break; | ||
2853 | |||
2854 | default: | ||
2855 | err = -EOPNOTSUPP; | ||
2856 | break; | ||
2857 | } | ||
2858 | |||
2859 | if (err == -EINPROGRESS) { | ||
2860 | priv->iw_mode = *mode; | ||
2861 | set_port_type(priv); | ||
2862 | } | ||
2863 | |||
2864 | orinoco_unlock(priv, &flags); | ||
2865 | |||
2866 | return err; | ||
2867 | } | ||
2868 | |||
2869 | static int orinoco_ioctl_getmode(struct net_device *dev, | ||
2870 | struct iw_request_info *info, | ||
2871 | u32 *mode, | ||
2872 | char *extra) | ||
2873 | { | ||
2874 | struct orinoco_private *priv = netdev_priv(dev); | ||
2875 | |||
2876 | *mode = priv->iw_mode; | ||
2877 | return 0; | ||
2878 | } | ||
2879 | |||
2880 | static int orinoco_ioctl_getiwrange(struct net_device *dev, | ||
2881 | struct iw_request_info *info, | ||
2882 | struct iw_point *rrq, | ||
2883 | char *extra) | ||
2884 | { | ||
2885 | struct orinoco_private *priv = netdev_priv(dev); | ||
2886 | int err = 0; | ||
2887 | struct iw_range *range = (struct iw_range *) extra; | ||
2888 | int numrates; | ||
2889 | int i, k; | ||
2890 | |||
2891 | rrq->length = sizeof(struct iw_range); | ||
2892 | memset(range, 0, sizeof(struct iw_range)); | ||
2893 | |||
2894 | range->we_version_compiled = WIRELESS_EXT; | ||
2895 | range->we_version_source = 22; | ||
2896 | |||
2897 | /* Set available channels/frequencies */ | ||
2898 | range->num_channels = NUM_CHANNELS; | ||
2899 | k = 0; | ||
2900 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
2901 | if (priv->channel_mask & (1 << i)) { | ||
2902 | range->freq[k].i = i + 1; | ||
2903 | range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) * | ||
2904 | 100000); | ||
2905 | range->freq[k].e = 1; | ||
2906 | k++; | ||
2907 | } | ||
2908 | |||
2909 | if (k >= IW_MAX_FREQUENCIES) | ||
2910 | break; | ||
2911 | } | ||
2912 | range->num_frequency = k; | ||
2913 | range->sensitivity = 3; | ||
2914 | |||
2915 | if (priv->has_wep) { | ||
2916 | range->max_encoding_tokens = ORINOCO_MAX_KEYS; | ||
2917 | range->encoding_size[0] = SMALL_KEY_SIZE; | ||
2918 | range->num_encoding_sizes = 1; | ||
2919 | |||
2920 | if (priv->has_big_wep) { | ||
2921 | range->encoding_size[1] = LARGE_KEY_SIZE; | ||
2922 | range->num_encoding_sizes = 2; | ||
2923 | } | ||
2924 | } | ||
2925 | |||
2926 | if (priv->has_wpa) | ||
2927 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; | ||
2928 | |||
2929 | if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) { | ||
2930 | /* Quality stats meaningless in ad-hoc mode */ | ||
2931 | } else { | ||
2932 | range->max_qual.qual = 0x8b - 0x2f; | ||
2933 | range->max_qual.level = 0x2f - 0x95 - 1; | ||
2934 | range->max_qual.noise = 0x2f - 0x95 - 1; | ||
2935 | /* Need to get better values */ | ||
2936 | range->avg_qual.qual = 0x24; | ||
2937 | range->avg_qual.level = 0xC2; | ||
2938 | range->avg_qual.noise = 0x9E; | ||
2939 | } | ||
2940 | |||
2941 | err = orinoco_hw_get_bitratelist(priv, &numrates, | ||
2942 | range->bitrate, IW_MAX_BITRATES); | ||
2943 | if (err) | ||
2944 | return err; | ||
2945 | range->num_bitrates = numrates; | ||
2946 | |||
2947 | /* Set an indication of the max TCP throughput in bit/s that we can | ||
2948 | * expect using this interface. May be use for QoS stuff... | ||
2949 | * Jean II */ | ||
2950 | if (numrates > 2) | ||
2951 | range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ | ||
2952 | else | ||
2953 | range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ | ||
2954 | |||
2955 | range->min_rts = 0; | ||
2956 | range->max_rts = 2347; | ||
2957 | range->min_frag = 256; | ||
2958 | range->max_frag = 2346; | ||
2959 | |||
2960 | range->min_pmp = 0; | ||
2961 | range->max_pmp = 65535000; | ||
2962 | range->min_pmt = 0; | ||
2963 | range->max_pmt = 65535 * 1000; /* ??? */ | ||
2964 | range->pmp_flags = IW_POWER_PERIOD; | ||
2965 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
2966 | range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT | | ||
2967 | IW_POWER_UNICAST_R); | ||
2968 | |||
2969 | range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; | ||
2970 | range->retry_flags = IW_RETRY_LIMIT; | ||
2971 | range->r_time_flags = IW_RETRY_LIFETIME; | ||
2972 | range->min_retry = 0; | ||
2973 | range->max_retry = 65535; /* ??? */ | ||
2974 | range->min_r_time = 0; | ||
2975 | range->max_r_time = 65535 * 1000; /* ??? */ | ||
2976 | |||
2977 | if (priv->firmware_type == FIRMWARE_TYPE_AGERE) | ||
2978 | range->scan_capa = IW_SCAN_CAPA_ESSID; | ||
2979 | else | ||
2980 | range->scan_capa = IW_SCAN_CAPA_NONE; | ||
2981 | |||
2982 | /* Event capability (kernel) */ | ||
2983 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | ||
2984 | /* Event capability (driver) */ | ||
2985 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); | ||
2986 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | ||
2987 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | ||
2988 | IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); | ||
2989 | |||
2990 | return 0; | ||
2991 | } | ||
2992 | |||
2993 | static int orinoco_ioctl_setiwencode(struct net_device *dev, | ||
2994 | struct iw_request_info *info, | ||
2995 | struct iw_point *erq, | ||
2996 | char *keybuf) | ||
2997 | { | ||
2998 | struct orinoco_private *priv = netdev_priv(dev); | ||
2999 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | ||
3000 | int setindex = priv->tx_key; | ||
3001 | int encode_alg = priv->encode_alg; | ||
3002 | int restricted = priv->wep_restrict; | ||
3003 | u16 xlen = 0; | ||
3004 | int err = -EINPROGRESS; /* Call commit handler */ | ||
3005 | unsigned long flags; | ||
3006 | |||
3007 | if (!priv->has_wep) | ||
3008 | return -EOPNOTSUPP; | ||
3009 | |||
3010 | if (erq->pointer) { | ||
3011 | /* We actually have a key to set - check its length */ | ||
3012 | if (erq->length > LARGE_KEY_SIZE) | ||
3013 | return -E2BIG; | ||
3014 | |||
3015 | if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep) | ||
3016 | return -E2BIG; | ||
3017 | } | ||
3018 | |||
3019 | if (orinoco_lock(priv, &flags) != 0) | ||
3020 | return -EBUSY; | ||
3021 | |||
3022 | /* Clear any TKIP key we have */ | ||
3023 | if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) | ||
3024 | (void) orinoco_clear_tkip_key(priv, setindex); | ||
3025 | |||
3026 | if (erq->length > 0) { | ||
3027 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | ||
3028 | index = priv->tx_key; | ||
3029 | |||
3030 | /* Adjust key length to a supported value */ | ||
3031 | if (erq->length > SMALL_KEY_SIZE) | ||
3032 | xlen = LARGE_KEY_SIZE; | ||
3033 | else if (erq->length > 0) | ||
3034 | xlen = SMALL_KEY_SIZE; | ||
3035 | else | ||
3036 | xlen = 0; | ||
3037 | |||
3038 | /* Switch on WEP if off */ | ||
3039 | if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { | ||
3040 | setindex = index; | ||
3041 | encode_alg = IW_ENCODE_ALG_WEP; | ||
3042 | } | ||
3043 | } else { | ||
3044 | /* Important note : if the user do "iwconfig eth0 enc off", | ||
3045 | * we will arrive there with an index of -1. This is valid | ||
3046 | * but need to be taken care off... Jean II */ | ||
3047 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { | ||
3048 | if ((index != -1) || (erq->flags == 0)) { | ||
3049 | err = -EINVAL; | ||
3050 | goto out; | ||
3051 | } | ||
3052 | } else { | ||
3053 | /* Set the index : Check that the key is valid */ | ||
3054 | if (priv->keys[index].len == 0) { | ||
3055 | err = -EINVAL; | ||
3056 | goto out; | ||
3057 | } | ||
3058 | setindex = index; | ||
3059 | } | ||
3060 | } | ||
3061 | |||
3062 | if (erq->flags & IW_ENCODE_DISABLED) | ||
3063 | encode_alg = IW_ENCODE_ALG_NONE; | ||
3064 | if (erq->flags & IW_ENCODE_OPEN) | ||
3065 | restricted = 0; | ||
3066 | if (erq->flags & IW_ENCODE_RESTRICTED) | ||
3067 | restricted = 1; | ||
3068 | |||
3069 | if (erq->pointer && erq->length > 0) { | ||
3070 | priv->keys[index].len = cpu_to_le16(xlen); | ||
3071 | memset(priv->keys[index].data, 0, | ||
3072 | sizeof(priv->keys[index].data)); | ||
3073 | memcpy(priv->keys[index].data, keybuf, erq->length); | ||
3074 | } | ||
3075 | priv->tx_key = setindex; | ||
3076 | |||
3077 | /* Try fast key change if connected and only keys are changed */ | ||
3078 | if ((priv->encode_alg == encode_alg) && | ||
3079 | (priv->wep_restrict == restricted) && | ||
3080 | netif_carrier_ok(dev)) { | ||
3081 | err = __orinoco_hw_setup_wepkeys(priv); | ||
3082 | /* No need to commit if successful */ | ||
3083 | goto out; | ||
3084 | } | ||
3085 | |||
3086 | priv->encode_alg = encode_alg; | ||
3087 | priv->wep_restrict = restricted; | ||
3088 | |||
3089 | out: | ||
3090 | orinoco_unlock(priv, &flags); | ||
3091 | |||
3092 | return err; | ||
3093 | } | ||
3094 | |||
3095 | static int orinoco_ioctl_getiwencode(struct net_device *dev, | ||
3096 | struct iw_request_info *info, | ||
3097 | struct iw_point *erq, | ||
3098 | char *keybuf) | ||
3099 | { | ||
3100 | struct orinoco_private *priv = netdev_priv(dev); | ||
3101 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | ||
3102 | u16 xlen = 0; | ||
3103 | unsigned long flags; | ||
3104 | |||
3105 | if (!priv->has_wep) | ||
3106 | return -EOPNOTSUPP; | ||
3107 | |||
3108 | if (orinoco_lock(priv, &flags) != 0) | ||
3109 | return -EBUSY; | ||
3110 | |||
3111 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | ||
3112 | index = priv->tx_key; | ||
3113 | |||
3114 | erq->flags = 0; | ||
3115 | if (!priv->encode_alg) | ||
3116 | erq->flags |= IW_ENCODE_DISABLED; | ||
3117 | erq->flags |= index + 1; | ||
3118 | |||
3119 | if (priv->wep_restrict) | ||
3120 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
3121 | else | ||
3122 | erq->flags |= IW_ENCODE_OPEN; | ||
3123 | |||
3124 | xlen = le16_to_cpu(priv->keys[index].len); | ||
3125 | |||
3126 | erq->length = xlen; | ||
3127 | |||
3128 | memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); | ||
3129 | |||
3130 | orinoco_unlock(priv, &flags); | ||
3131 | return 0; | ||
3132 | } | ||
3133 | |||
3134 | static int orinoco_ioctl_setessid(struct net_device *dev, | ||
3135 | struct iw_request_info *info, | ||
3136 | struct iw_point *erq, | ||
3137 | char *essidbuf) | ||
3138 | { | ||
3139 | struct orinoco_private *priv = netdev_priv(dev); | ||
3140 | unsigned long flags; | ||
3141 | |||
3142 | /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it | ||
3143 | * anyway... - Jean II */ | ||
3144 | |||
3145 | /* Hum... Should not use Wireless Extension constant (may change), | ||
3146 | * should use our own... - Jean II */ | ||
3147 | if (erq->length > IW_ESSID_MAX_SIZE) | ||
3148 | return -E2BIG; | ||
3149 | |||
3150 | if (orinoco_lock(priv, &flags) != 0) | ||
3151 | return -EBUSY; | ||
3152 | |||
3153 | /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ | ||
3154 | memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); | ||
3155 | |||
3156 | /* If not ANY, get the new ESSID */ | ||
3157 | if (erq->flags) | ||
3158 | memcpy(priv->desired_essid, essidbuf, erq->length); | ||
3159 | |||
3160 | orinoco_unlock(priv, &flags); | ||
3161 | |||
3162 | return -EINPROGRESS; /* Call commit handler */ | ||
3163 | } | ||
3164 | |||
3165 | static int orinoco_ioctl_getessid(struct net_device *dev, | ||
3166 | struct iw_request_info *info, | ||
3167 | struct iw_point *erq, | ||
3168 | char *essidbuf) | ||
3169 | { | ||
3170 | struct orinoco_private *priv = netdev_priv(dev); | ||
3171 | int active; | ||
3172 | int err = 0; | ||
3173 | unsigned long flags; | ||
3174 | |||
3175 | if (netif_running(dev)) { | ||
3176 | err = orinoco_hw_get_essid(priv, &active, essidbuf); | ||
3177 | if (err < 0) | ||
3178 | return err; | ||
3179 | erq->length = err; | ||
3180 | } else { | ||
3181 | if (orinoco_lock(priv, &flags) != 0) | ||
3182 | return -EBUSY; | ||
3183 | memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); | ||
3184 | erq->length = strlen(priv->desired_essid); | ||
3185 | orinoco_unlock(priv, &flags); | ||
3186 | } | ||
3187 | |||
3188 | erq->flags = 1; | ||
3189 | |||
3190 | return 0; | ||
3191 | } | ||
3192 | |||
3193 | static int orinoco_ioctl_setnick(struct net_device *dev, | ||
3194 | struct iw_request_info *info, | ||
3195 | struct iw_point *nrq, | ||
3196 | char *nickbuf) | ||
3197 | { | ||
3198 | struct orinoco_private *priv = netdev_priv(dev); | ||
3199 | unsigned long flags; | ||
3200 | |||
3201 | if (nrq->length > IW_ESSID_MAX_SIZE) | ||
3202 | return -E2BIG; | ||
3203 | |||
3204 | if (orinoco_lock(priv, &flags) != 0) | ||
3205 | return -EBUSY; | ||
3206 | |||
3207 | memset(priv->nick, 0, sizeof(priv->nick)); | ||
3208 | memcpy(priv->nick, nickbuf, nrq->length); | ||
3209 | |||
3210 | orinoco_unlock(priv, &flags); | ||
3211 | |||
3212 | return -EINPROGRESS; /* Call commit handler */ | ||
3213 | } | ||
3214 | |||
3215 | static int orinoco_ioctl_getnick(struct net_device *dev, | ||
3216 | struct iw_request_info *info, | ||
3217 | struct iw_point *nrq, | ||
3218 | char *nickbuf) | ||
3219 | { | ||
3220 | struct orinoco_private *priv = netdev_priv(dev); | ||
3221 | unsigned long flags; | ||
3222 | |||
3223 | if (orinoco_lock(priv, &flags) != 0) | ||
3224 | return -EBUSY; | ||
3225 | |||
3226 | memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE); | ||
3227 | orinoco_unlock(priv, &flags); | ||
3228 | |||
3229 | nrq->length = strlen(priv->nick); | ||
3230 | |||
3231 | return 0; | ||
3232 | } | ||
3233 | |||
3234 | static int orinoco_ioctl_setfreq(struct net_device *dev, | ||
3235 | struct iw_request_info *info, | ||
3236 | struct iw_freq *frq, | ||
3237 | char *extra) | ||
3238 | { | ||
3239 | struct orinoco_private *priv = netdev_priv(dev); | ||
3240 | int chan = -1; | ||
3241 | unsigned long flags; | ||
3242 | int err = -EINPROGRESS; /* Call commit handler */ | ||
3243 | |||
3244 | /* In infrastructure mode the AP sets the channel */ | ||
3245 | if (priv->iw_mode == IW_MODE_INFRA) | ||
3246 | return -EBUSY; | ||
3247 | |||
3248 | if ((frq->e == 0) && (frq->m <= 1000)) { | ||
3249 | /* Setting by channel number */ | ||
3250 | chan = frq->m; | ||
3251 | } else { | ||
3252 | /* Setting by frequency */ | ||
3253 | int denom = 1; | ||
3254 | int i; | ||
3255 | |||
3256 | /* Calculate denominator to rescale to MHz */ | ||
3257 | for (i = 0; i < (6 - frq->e); i++) | ||
3258 | denom *= 10; | ||
3259 | |||
3260 | chan = ieee80211_freq_to_dsss_chan(frq->m / denom); | ||
3261 | } | ||
3262 | |||
3263 | if ((chan < 1) || (chan > NUM_CHANNELS) || | ||
3264 | !(priv->channel_mask & (1 << (chan-1)))) | ||
3265 | return -EINVAL; | ||
3266 | |||
3267 | if (orinoco_lock(priv, &flags) != 0) | ||
3268 | return -EBUSY; | ||
3269 | |||
3270 | priv->channel = chan; | ||
3271 | if (priv->iw_mode == IW_MODE_MONITOR) { | ||
3272 | /* Fast channel change - no commit if successful */ | ||
3273 | hermes_t *hw = &priv->hw; | ||
3274 | err = hermes_docmd_wait(hw, HERMES_CMD_TEST | | ||
3275 | HERMES_TEST_SET_CHANNEL, | ||
3276 | chan, NULL); | ||
3277 | } | ||
3278 | orinoco_unlock(priv, &flags); | ||
3279 | |||
3280 | return err; | ||
3281 | } | ||
3282 | |||
3283 | static int orinoco_ioctl_getfreq(struct net_device *dev, | ||
3284 | struct iw_request_info *info, | ||
3285 | struct iw_freq *frq, | ||
3286 | char *extra) | ||
3287 | { | ||
3288 | struct orinoco_private *priv = netdev_priv(dev); | ||
3289 | int tmp; | ||
3290 | |||
3291 | /* Locking done in there */ | ||
3292 | tmp = orinoco_hw_get_freq(priv); | ||
3293 | if (tmp < 0) | ||
3294 | return tmp; | ||
3295 | |||
3296 | frq->m = tmp * 100000; | ||
3297 | frq->e = 1; | ||
3298 | |||
3299 | return 0; | ||
3300 | } | ||
3301 | |||
3302 | static int orinoco_ioctl_getsens(struct net_device *dev, | ||
3303 | struct iw_request_info *info, | ||
3304 | struct iw_param *srq, | ||
3305 | char *extra) | ||
3306 | { | ||
3307 | struct orinoco_private *priv = netdev_priv(dev); | ||
3308 | hermes_t *hw = &priv->hw; | ||
3309 | u16 val; | ||
3310 | int err; | ||
3311 | unsigned long flags; | ||
3312 | |||
3313 | if (!priv->has_sensitivity) | ||
3314 | return -EOPNOTSUPP; | ||
3315 | |||
3316 | if (orinoco_lock(priv, &flags) != 0) | ||
3317 | return -EBUSY; | ||
3318 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3319 | HERMES_RID_CNFSYSTEMSCALE, &val); | ||
3320 | orinoco_unlock(priv, &flags); | ||
3321 | |||
3322 | if (err) | ||
3323 | return err; | ||
3324 | |||
3325 | srq->value = val; | ||
3326 | srq->fixed = 0; /* auto */ | ||
3327 | |||
3328 | return 0; | ||
3329 | } | ||
3330 | |||
3331 | static int orinoco_ioctl_setsens(struct net_device *dev, | ||
3332 | struct iw_request_info *info, | ||
3333 | struct iw_param *srq, | ||
3334 | char *extra) | ||
3335 | { | ||
3336 | struct orinoco_private *priv = netdev_priv(dev); | ||
3337 | int val = srq->value; | ||
3338 | unsigned long flags; | ||
3339 | |||
3340 | if (!priv->has_sensitivity) | ||
3341 | return -EOPNOTSUPP; | ||
3342 | |||
3343 | if ((val < 1) || (val > 3)) | ||
3344 | return -EINVAL; | ||
3345 | |||
3346 | if (orinoco_lock(priv, &flags) != 0) | ||
3347 | return -EBUSY; | ||
3348 | priv->ap_density = val; | ||
3349 | orinoco_unlock(priv, &flags); | ||
3350 | |||
3351 | return -EINPROGRESS; /* Call commit handler */ | ||
3352 | } | ||
3353 | |||
3354 | static int orinoco_ioctl_setrts(struct net_device *dev, | ||
3355 | struct iw_request_info *info, | ||
3356 | struct iw_param *rrq, | ||
3357 | char *extra) | ||
3358 | { | ||
3359 | struct orinoco_private *priv = netdev_priv(dev); | ||
3360 | int val = rrq->value; | ||
3361 | unsigned long flags; | ||
3362 | |||
3363 | if (rrq->disabled) | ||
3364 | val = 2347; | ||
3365 | |||
3366 | if ((val < 0) || (val > 2347)) | ||
3367 | return -EINVAL; | ||
3368 | |||
3369 | if (orinoco_lock(priv, &flags) != 0) | ||
3370 | return -EBUSY; | ||
3371 | |||
3372 | priv->rts_thresh = val; | ||
3373 | orinoco_unlock(priv, &flags); | ||
3374 | |||
3375 | return -EINPROGRESS; /* Call commit handler */ | ||
3376 | } | ||
3377 | |||
3378 | static int orinoco_ioctl_getrts(struct net_device *dev, | ||
3379 | struct iw_request_info *info, | ||
3380 | struct iw_param *rrq, | ||
3381 | char *extra) | ||
3382 | { | ||
3383 | struct orinoco_private *priv = netdev_priv(dev); | ||
3384 | |||
3385 | rrq->value = priv->rts_thresh; | ||
3386 | rrq->disabled = (rrq->value == 2347); | ||
3387 | rrq->fixed = 1; | ||
3388 | |||
3389 | return 0; | ||
3390 | } | ||
3391 | |||
3392 | static int orinoco_ioctl_setfrag(struct net_device *dev, | ||
3393 | struct iw_request_info *info, | ||
3394 | struct iw_param *frq, | ||
3395 | char *extra) | ||
3396 | { | ||
3397 | struct orinoco_private *priv = netdev_priv(dev); | ||
3398 | int err = -EINPROGRESS; /* Call commit handler */ | ||
3399 | unsigned long flags; | ||
3400 | |||
3401 | if (orinoco_lock(priv, &flags) != 0) | ||
3402 | return -EBUSY; | ||
3403 | |||
3404 | if (priv->has_mwo) { | ||
3405 | if (frq->disabled) | ||
3406 | priv->mwo_robust = 0; | ||
3407 | else { | ||
3408 | if (frq->fixed) | ||
3409 | printk(KERN_WARNING "%s: Fixed fragmentation " | ||
3410 | "is not supported on this firmware. " | ||
3411 | "Using MWO robust instead.\n", | ||
3412 | dev->name); | ||
3413 | priv->mwo_robust = 1; | ||
3414 | } | ||
3415 | } else { | ||
3416 | if (frq->disabled) | ||
3417 | priv->frag_thresh = 2346; | ||
3418 | else { | ||
3419 | if ((frq->value < 256) || (frq->value > 2346)) | ||
3420 | err = -EINVAL; | ||
3421 | else | ||
3422 | /* must be even */ | ||
3423 | priv->frag_thresh = frq->value & ~0x1; | ||
3424 | } | ||
3425 | } | ||
3426 | |||
3427 | orinoco_unlock(priv, &flags); | ||
3428 | |||
3429 | return err; | ||
3430 | } | ||
3431 | |||
3432 | static int orinoco_ioctl_getfrag(struct net_device *dev, | ||
3433 | struct iw_request_info *info, | ||
3434 | struct iw_param *frq, | ||
3435 | char *extra) | ||
3436 | { | ||
3437 | struct orinoco_private *priv = netdev_priv(dev); | ||
3438 | hermes_t *hw = &priv->hw; | ||
3439 | int err; | ||
3440 | u16 val; | ||
3441 | unsigned long flags; | ||
3442 | |||
3443 | if (orinoco_lock(priv, &flags) != 0) | ||
3444 | return -EBUSY; | ||
3445 | |||
3446 | if (priv->has_mwo) { | ||
3447 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3448 | HERMES_RID_CNFMWOROBUST_AGERE, | ||
3449 | &val); | ||
3450 | if (err) | ||
3451 | val = 0; | ||
3452 | |||
3453 | frq->value = val ? 2347 : 0; | ||
3454 | frq->disabled = !val; | ||
3455 | frq->fixed = 0; | ||
3456 | } else { | ||
3457 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3458 | HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, | ||
3459 | &val); | ||
3460 | if (err) | ||
3461 | val = 0; | ||
3462 | |||
3463 | frq->value = val; | ||
3464 | frq->disabled = (val >= 2346); | ||
3465 | frq->fixed = 1; | ||
3466 | } | ||
3467 | |||
3468 | orinoco_unlock(priv, &flags); | ||
3469 | |||
3470 | return err; | ||
3471 | } | ||
3472 | |||
3473 | static int orinoco_ioctl_setrate(struct net_device *dev, | ||
3474 | struct iw_request_info *info, | ||
3475 | struct iw_param *rrq, | ||
3476 | char *extra) | ||
3477 | { | ||
3478 | struct orinoco_private *priv = netdev_priv(dev); | ||
3479 | int ratemode; | ||
3480 | int bitrate; /* 100s of kilobits */ | ||
3481 | unsigned long flags; | ||
3482 | |||
3483 | /* As the user space doesn't know our highest rate, it uses -1 | ||
3484 | * to ask us to set the highest rate. Test it using "iwconfig | ||
3485 | * ethX rate auto" - Jean II */ | ||
3486 | if (rrq->value == -1) | ||
3487 | bitrate = 110; | ||
3488 | else { | ||
3489 | if (rrq->value % 100000) | ||
3490 | return -EINVAL; | ||
3491 | bitrate = rrq->value / 100000; | ||
3492 | } | ||
3493 | |||
3494 | ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed); | ||
3495 | |||
3496 | if (ratemode == -1) | ||
3497 | return -EINVAL; | ||
3498 | |||
3499 | if (orinoco_lock(priv, &flags) != 0) | ||
3500 | return -EBUSY; | ||
3501 | priv->bitratemode = ratemode; | ||
3502 | orinoco_unlock(priv, &flags); | ||
3503 | |||
3504 | return -EINPROGRESS; | ||
3505 | } | ||
3506 | |||
3507 | static int orinoco_ioctl_getrate(struct net_device *dev, | ||
3508 | struct iw_request_info *info, | ||
3509 | struct iw_param *rrq, | ||
3510 | char *extra) | ||
3511 | { | ||
3512 | struct orinoco_private *priv = netdev_priv(dev); | ||
3513 | int err = 0; | ||
3514 | int bitrate, automatic; | ||
3515 | unsigned long flags; | ||
3516 | |||
3517 | if (orinoco_lock(priv, &flags) != 0) | ||
3518 | return -EBUSY; | ||
3519 | |||
3520 | orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic); | ||
3521 | |||
3522 | /* If the interface is running we try to find more about the | ||
3523 | current mode */ | ||
3524 | if (netif_running(dev)) | ||
3525 | err = orinoco_hw_get_act_bitrate(priv, &bitrate); | ||
3526 | |||
3527 | orinoco_unlock(priv, &flags); | ||
3528 | |||
3529 | rrq->value = bitrate; | ||
3530 | rrq->fixed = !automatic; | ||
3531 | rrq->disabled = 0; | ||
3532 | |||
3533 | return err; | ||
3534 | } | ||
3535 | |||
3536 | static int orinoco_ioctl_setpower(struct net_device *dev, | ||
3537 | struct iw_request_info *info, | ||
3538 | struct iw_param *prq, | ||
3539 | char *extra) | ||
3540 | { | ||
3541 | struct orinoco_private *priv = netdev_priv(dev); | ||
3542 | int err = -EINPROGRESS; /* Call commit handler */ | ||
3543 | unsigned long flags; | ||
3544 | |||
3545 | if (orinoco_lock(priv, &flags) != 0) | ||
3546 | return -EBUSY; | ||
3547 | |||
3548 | if (prq->disabled) { | ||
3549 | priv->pm_on = 0; | ||
3550 | } else { | ||
3551 | switch (prq->flags & IW_POWER_MODE) { | ||
3552 | case IW_POWER_UNICAST_R: | ||
3553 | priv->pm_mcast = 0; | ||
3554 | priv->pm_on = 1; | ||
3555 | break; | ||
3556 | case IW_POWER_ALL_R: | ||
3557 | priv->pm_mcast = 1; | ||
3558 | priv->pm_on = 1; | ||
3559 | break; | ||
3560 | case IW_POWER_ON: | ||
3561 | /* No flags : but we may have a value - Jean II */ | ||
3562 | break; | ||
3563 | default: | ||
3564 | err = -EINVAL; | ||
3565 | goto out; | ||
3566 | } | ||
3567 | |||
3568 | if (prq->flags & IW_POWER_TIMEOUT) { | ||
3569 | priv->pm_on = 1; | ||
3570 | priv->pm_timeout = prq->value / 1000; | ||
3571 | } | ||
3572 | if (prq->flags & IW_POWER_PERIOD) { | ||
3573 | priv->pm_on = 1; | ||
3574 | priv->pm_period = prq->value / 1000; | ||
3575 | } | ||
3576 | /* It's valid to not have a value if we are just toggling | ||
3577 | * the flags... Jean II */ | ||
3578 | if (!priv->pm_on) { | ||
3579 | err = -EINVAL; | ||
3580 | goto out; | ||
3581 | } | ||
3582 | } | ||
3583 | |||
3584 | out: | ||
3585 | orinoco_unlock(priv, &flags); | ||
3586 | |||
3587 | return err; | ||
3588 | } | ||
3589 | |||
3590 | static int orinoco_ioctl_getpower(struct net_device *dev, | ||
3591 | struct iw_request_info *info, | ||
3592 | struct iw_param *prq, | ||
3593 | char *extra) | ||
3594 | { | ||
3595 | struct orinoco_private *priv = netdev_priv(dev); | ||
3596 | hermes_t *hw = &priv->hw; | ||
3597 | int err = 0; | ||
3598 | u16 enable, period, timeout, mcast; | ||
3599 | unsigned long flags; | ||
3600 | |||
3601 | if (orinoco_lock(priv, &flags) != 0) | ||
3602 | return -EBUSY; | ||
3603 | |||
3604 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3605 | HERMES_RID_CNFPMENABLED, &enable); | ||
3606 | if (err) | ||
3607 | goto out; | ||
3608 | |||
3609 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3610 | HERMES_RID_CNFMAXSLEEPDURATION, &period); | ||
3611 | if (err) | ||
3612 | goto out; | ||
3613 | |||
3614 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3615 | HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); | ||
3616 | if (err) | ||
3617 | goto out; | ||
3618 | |||
3619 | err = hermes_read_wordrec(hw, USER_BAP, | ||
3620 | HERMES_RID_CNFMULTICASTRECEIVE, &mcast); | ||
3621 | if (err) | ||
3622 | goto out; | ||
3623 | |||
3624 | prq->disabled = !enable; | ||
3625 | /* Note : by default, display the period */ | ||
3626 | if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
3627 | prq->flags = IW_POWER_TIMEOUT; | ||
3628 | prq->value = timeout * 1000; | ||
3629 | } else { | ||
3630 | prq->flags = IW_POWER_PERIOD; | ||
3631 | prq->value = period * 1000; | ||
3632 | } | ||
3633 | if (mcast) | ||
3634 | prq->flags |= IW_POWER_ALL_R; | ||
3635 | else | ||
3636 | prq->flags |= IW_POWER_UNICAST_R; | ||
3637 | |||
3638 | out: | ||
3639 | orinoco_unlock(priv, &flags); | ||
3640 | |||
3641 | return err; | ||
3642 | } | ||
3643 | |||
3644 | static int orinoco_ioctl_set_encodeext(struct net_device *dev, | ||
3645 | struct iw_request_info *info, | ||
3646 | union iwreq_data *wrqu, | ||
3647 | char *extra) | ||
3648 | { | ||
3649 | struct orinoco_private *priv = netdev_priv(dev); | ||
3650 | struct iw_point *encoding = &wrqu->encoding; | ||
3651 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
3652 | int idx, alg = ext->alg, set_key = 1; | ||
3653 | unsigned long flags; | ||
3654 | int err = -EINVAL; | ||
3655 | u16 key_len; | ||
3656 | |||
3657 | if (orinoco_lock(priv, &flags) != 0) | ||
3658 | return -EBUSY; | ||
3659 | |||
3660 | /* Determine and validate the key index */ | ||
3661 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
3662 | if (idx) { | ||
3663 | if ((idx < 1) || (idx > 4)) | ||
3664 | goto out; | ||
3665 | idx--; | ||
3666 | } else | ||
3667 | idx = priv->tx_key; | ||
3668 | |||
3669 | if (encoding->flags & IW_ENCODE_DISABLED) | ||
3670 | alg = IW_ENCODE_ALG_NONE; | ||
3671 | |||
3672 | if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { | ||
3673 | /* Clear any TKIP TX key we had */ | ||
3674 | (void) orinoco_clear_tkip_key(priv, priv->tx_key); | ||
3675 | } | ||
3676 | |||
3677 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
3678 | priv->tx_key = idx; | ||
3679 | set_key = ((alg == IW_ENCODE_ALG_TKIP) || | ||
3680 | (ext->key_len > 0)) ? 1 : 0; | ||
3681 | } | ||
3682 | |||
3683 | if (set_key) { | ||
3684 | /* Set the requested key first */ | ||
3685 | switch (alg) { | ||
3686 | case IW_ENCODE_ALG_NONE: | ||
3687 | priv->encode_alg = alg; | ||
3688 | priv->keys[idx].len = 0; | ||
3689 | break; | ||
3690 | |||
3691 | case IW_ENCODE_ALG_WEP: | ||
3692 | if (ext->key_len > SMALL_KEY_SIZE) | ||
3693 | key_len = LARGE_KEY_SIZE; | ||
3694 | else if (ext->key_len > 0) | ||
3695 | key_len = SMALL_KEY_SIZE; | ||
3696 | else | ||
3697 | goto out; | ||
3698 | |||
3699 | priv->encode_alg = alg; | ||
3700 | priv->keys[idx].len = cpu_to_le16(key_len); | ||
3701 | |||
3702 | key_len = min(ext->key_len, key_len); | ||
3703 | |||
3704 | memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); | ||
3705 | memcpy(priv->keys[idx].data, ext->key, key_len); | ||
3706 | break; | ||
3707 | |||
3708 | case IW_ENCODE_ALG_TKIP: | ||
3709 | { | ||
3710 | hermes_t *hw = &priv->hw; | ||
3711 | u8 *tkip_iv = NULL; | ||
3712 | |||
3713 | if (!priv->has_wpa || | ||
3714 | (ext->key_len > sizeof(priv->tkip_key[0]))) | ||
3715 | goto out; | ||
3716 | |||
3717 | priv->encode_alg = alg; | ||
3718 | memset(&priv->tkip_key[idx], 0, | ||
3719 | sizeof(priv->tkip_key[idx])); | ||
3720 | memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); | ||
3721 | |||
3722 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) | ||
3723 | tkip_iv = &ext->rx_seq[0]; | ||
3724 | |||
3725 | err = __orinoco_hw_set_tkip_key(hw, idx, | ||
3726 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | ||
3727 | (u8 *) &priv->tkip_key[idx], | ||
3728 | tkip_iv, NULL); | ||
3729 | if (err) | ||
3730 | printk(KERN_ERR "%s: Error %d setting TKIP key" | ||
3731 | "\n", dev->name, err); | ||
3732 | |||
3733 | goto out; | ||
3734 | } | ||
3735 | default: | ||
3736 | goto out; | ||
3737 | } | ||
3738 | } | ||
3739 | err = -EINPROGRESS; | ||
3740 | out: | ||
3741 | orinoco_unlock(priv, &flags); | ||
3742 | |||
3743 | return err; | ||
3744 | } | ||
3745 | |||
3746 | static int orinoco_ioctl_get_encodeext(struct net_device *dev, | ||
3747 | struct iw_request_info *info, | ||
3748 | union iwreq_data *wrqu, | ||
3749 | char *extra) | ||
3750 | { | ||
3751 | struct orinoco_private *priv = netdev_priv(dev); | ||
3752 | struct iw_point *encoding = &wrqu->encoding; | ||
3753 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
3754 | int idx, max_key_len; | ||
3755 | unsigned long flags; | ||
3756 | int err; | ||
3757 | |||
3758 | if (orinoco_lock(priv, &flags) != 0) | ||
3759 | return -EBUSY; | ||
3760 | |||
3761 | err = -EINVAL; | ||
3762 | max_key_len = encoding->length - sizeof(*ext); | ||
3763 | if (max_key_len < 0) | ||
3764 | goto out; | ||
3765 | |||
3766 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
3767 | if (idx) { | ||
3768 | if ((idx < 1) || (idx > 4)) | ||
3769 | goto out; | ||
3770 | idx--; | ||
3771 | } else | ||
3772 | idx = priv->tx_key; | ||
3773 | |||
3774 | encoding->flags = idx + 1; | ||
3775 | memset(ext, 0, sizeof(*ext)); | ||
3776 | |||
3777 | ext->alg = priv->encode_alg; | ||
3778 | switch (priv->encode_alg) { | ||
3779 | case IW_ENCODE_ALG_NONE: | ||
3780 | ext->key_len = 0; | ||
3781 | encoding->flags |= IW_ENCODE_DISABLED; | ||
3782 | break; | ||
3783 | case IW_ENCODE_ALG_WEP: | ||
3784 | ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), | ||
3785 | max_key_len); | ||
3786 | memcpy(ext->key, priv->keys[idx].data, ext->key_len); | ||
3787 | encoding->flags |= IW_ENCODE_ENABLED; | ||
3788 | break; | ||
3789 | case IW_ENCODE_ALG_TKIP: | ||
3790 | ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), | ||
3791 | max_key_len); | ||
3792 | memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); | ||
3793 | encoding->flags |= IW_ENCODE_ENABLED; | ||
3794 | break; | ||
3795 | } | ||
3796 | |||
3797 | err = 0; | ||
3798 | out: | ||
3799 | orinoco_unlock(priv, &flags); | ||
3800 | |||
3801 | return err; | ||
3802 | } | ||
3803 | |||
3804 | static int orinoco_ioctl_set_auth(struct net_device *dev, | ||
3805 | struct iw_request_info *info, | ||
3806 | union iwreq_data *wrqu, char *extra) | ||
3807 | { | ||
3808 | struct orinoco_private *priv = netdev_priv(dev); | ||
3809 | hermes_t *hw = &priv->hw; | ||
3810 | struct iw_param *param = &wrqu->param; | ||
3811 | unsigned long flags; | ||
3812 | int ret = -EINPROGRESS; | ||
3813 | |||
3814 | if (orinoco_lock(priv, &flags) != 0) | ||
3815 | return -EBUSY; | ||
3816 | |||
3817 | switch (param->flags & IW_AUTH_INDEX) { | ||
3818 | case IW_AUTH_WPA_VERSION: | ||
3819 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3820 | case IW_AUTH_CIPHER_GROUP: | ||
3821 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3822 | case IW_AUTH_PRIVACY_INVOKED: | ||
3823 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3824 | /* | ||
3825 | * orinoco does not use these parameters | ||
3826 | */ | ||
3827 | break; | ||
3828 | |||
3829 | case IW_AUTH_KEY_MGMT: | ||
3830 | /* wl_lkm implies value 2 == PSK for Hermes I | ||
3831 | * which ties in with WEXT | ||
3832 | * no other hints tho :( | ||
3833 | */ | ||
3834 | priv->key_mgmt = param->value; | ||
3835 | break; | ||
3836 | |||
3837 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3838 | /* When countermeasures are enabled, shut down the | ||
3839 | * card; when disabled, re-enable the card. This must | ||
3840 | * take effect immediately. | ||
3841 | * | ||
3842 | * TODO: Make sure that the EAPOL message is getting | ||
3843 | * out before card disabled | ||
3844 | */ | ||
3845 | if (param->value) { | ||
3846 | priv->tkip_cm_active = 1; | ||
3847 | ret = hermes_enable_port(hw, 0); | ||
3848 | } else { | ||
3849 | priv->tkip_cm_active = 0; | ||
3850 | ret = hermes_disable_port(hw, 0); | ||
3851 | } | ||
3852 | break; | ||
3853 | |||
3854 | case IW_AUTH_80211_AUTH_ALG: | ||
3855 | if (param->value & IW_AUTH_ALG_SHARED_KEY) | ||
3856 | priv->wep_restrict = 1; | ||
3857 | else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) | ||
3858 | priv->wep_restrict = 0; | ||
3859 | else | ||
3860 | ret = -EINVAL; | ||
3861 | break; | ||
3862 | |||
3863 | case IW_AUTH_WPA_ENABLED: | ||
3864 | if (priv->has_wpa) { | ||
3865 | priv->wpa_enabled = param->value ? 1 : 0; | ||
3866 | } else { | ||
3867 | if (param->value) | ||
3868 | ret = -EOPNOTSUPP; | ||
3869 | /* else silently accept disable of WPA */ | ||
3870 | priv->wpa_enabled = 0; | ||
3871 | } | ||
3872 | break; | ||
3873 | |||
3874 | default: | ||
3875 | ret = -EOPNOTSUPP; | ||
3876 | } | ||
3877 | |||
3878 | orinoco_unlock(priv, &flags); | ||
3879 | return ret; | ||
3880 | } | ||
3881 | |||
3882 | static int orinoco_ioctl_get_auth(struct net_device *dev, | ||
3883 | struct iw_request_info *info, | ||
3884 | union iwreq_data *wrqu, char *extra) | ||
3885 | { | ||
3886 | struct orinoco_private *priv = netdev_priv(dev); | ||
3887 | struct iw_param *param = &wrqu->param; | ||
3888 | unsigned long flags; | ||
3889 | int ret = 0; | ||
3890 | |||
3891 | if (orinoco_lock(priv, &flags) != 0) | ||
3892 | return -EBUSY; | ||
3893 | |||
3894 | switch (param->flags & IW_AUTH_INDEX) { | ||
3895 | case IW_AUTH_KEY_MGMT: | ||
3896 | param->value = priv->key_mgmt; | ||
3897 | break; | ||
3898 | |||
3899 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3900 | param->value = priv->tkip_cm_active; | ||
3901 | break; | ||
3902 | |||
3903 | case IW_AUTH_80211_AUTH_ALG: | ||
3904 | if (priv->wep_restrict) | ||
3905 | param->value = IW_AUTH_ALG_SHARED_KEY; | ||
3906 | else | ||
3907 | param->value = IW_AUTH_ALG_OPEN_SYSTEM; | ||
3908 | break; | ||
3909 | |||
3910 | case IW_AUTH_WPA_ENABLED: | ||
3911 | param->value = priv->wpa_enabled; | ||
3912 | break; | ||
3913 | |||
3914 | default: | ||
3915 | ret = -EOPNOTSUPP; | ||
3916 | } | ||
3917 | |||
3918 | orinoco_unlock(priv, &flags); | ||
3919 | return ret; | ||
3920 | } | ||
3921 | |||
3922 | static int orinoco_ioctl_set_genie(struct net_device *dev, | ||
3923 | struct iw_request_info *info, | ||
3924 | union iwreq_data *wrqu, char *extra) | ||
3925 | { | ||
3926 | struct orinoco_private *priv = netdev_priv(dev); | ||
3927 | u8 *buf; | ||
3928 | unsigned long flags; | ||
3929 | |||
3930 | /* cut off at IEEE80211_MAX_DATA_LEN */ | ||
3931 | if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || | ||
3932 | (wrqu->data.length && (extra == NULL))) | ||
3933 | return -EINVAL; | ||
3934 | |||
3935 | if (wrqu->data.length) { | ||
3936 | buf = kmalloc(wrqu->data.length, GFP_KERNEL); | ||
3937 | if (buf == NULL) | ||
3938 | return -ENOMEM; | ||
3939 | |||
3940 | memcpy(buf, extra, wrqu->data.length); | ||
3941 | } else | ||
3942 | buf = NULL; | ||
3943 | |||
3944 | if (orinoco_lock(priv, &flags) != 0) { | ||
3945 | kfree(buf); | ||
3946 | return -EBUSY; | ||
3947 | } | ||
3948 | |||
3949 | kfree(priv->wpa_ie); | ||
3950 | priv->wpa_ie = buf; | ||
3951 | priv->wpa_ie_len = wrqu->data.length; | ||
3952 | |||
3953 | if (priv->wpa_ie) { | ||
3954 | /* Looks like wl_lkm wants to check the auth alg, and | ||
3955 | * somehow pass it to the firmware. | ||
3956 | * Instead it just calls the key mgmt rid | ||
3957 | * - we do this in set auth. | ||
3958 | */ | ||
3959 | } | ||
3960 | |||
3961 | orinoco_unlock(priv, &flags); | ||
3962 | return 0; | ||
3963 | } | ||
3964 | |||
3965 | static int orinoco_ioctl_get_genie(struct net_device *dev, | ||
3966 | struct iw_request_info *info, | ||
3967 | union iwreq_data *wrqu, char *extra) | ||
3968 | { | ||
3969 | struct orinoco_private *priv = netdev_priv(dev); | ||
3970 | unsigned long flags; | ||
3971 | int err = 0; | ||
3972 | |||
3973 | if (orinoco_lock(priv, &flags) != 0) | ||
3974 | return -EBUSY; | ||
3975 | |||
3976 | if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { | ||
3977 | wrqu->data.length = 0; | ||
3978 | goto out; | ||
3979 | } | ||
3980 | |||
3981 | if (wrqu->data.length < priv->wpa_ie_len) { | ||
3982 | err = -E2BIG; | ||
3983 | goto out; | ||
3984 | } | ||
3985 | |||
3986 | wrqu->data.length = priv->wpa_ie_len; | ||
3987 | memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); | ||
3988 | |||
3989 | out: | ||
3990 | orinoco_unlock(priv, &flags); | ||
3991 | return err; | ||
3992 | } | ||
3993 | |||
3994 | static int orinoco_ioctl_set_mlme(struct net_device *dev, | ||
3995 | struct iw_request_info *info, | ||
3996 | union iwreq_data *wrqu, char *extra) | ||
3997 | { | ||
3998 | struct orinoco_private *priv = netdev_priv(dev); | ||
3999 | hermes_t *hw = &priv->hw; | ||
4000 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | ||
4001 | unsigned long flags; | ||
4002 | int ret = 0; | ||
4003 | |||
4004 | if (orinoco_lock(priv, &flags) != 0) | ||
4005 | return -EBUSY; | ||
4006 | |||
4007 | switch (mlme->cmd) { | ||
4008 | case IW_MLME_DEAUTH: | ||
4009 | /* silently ignore */ | ||
4010 | break; | ||
4011 | |||
4012 | case IW_MLME_DISASSOC: | ||
4013 | { | ||
4014 | struct { | ||
4015 | u8 addr[ETH_ALEN]; | ||
4016 | __le16 reason_code; | ||
4017 | } __attribute__ ((packed)) buf; | ||
4018 | |||
4019 | memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); | ||
4020 | buf.reason_code = cpu_to_le16(mlme->reason_code); | ||
4021 | ret = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
4022 | HERMES_RID_CNFDISASSOCIATE, | ||
4023 | &buf); | ||
4024 | break; | ||
4025 | } | ||
4026 | default: | ||
4027 | ret = -EOPNOTSUPP; | ||
4028 | } | ||
4029 | |||
4030 | orinoco_unlock(priv, &flags); | ||
4031 | return ret; | ||
4032 | } | ||
4033 | |||
4034 | static int orinoco_ioctl_getretry(struct net_device *dev, | ||
4035 | struct iw_request_info *info, | ||
4036 | struct iw_param *rrq, | ||
4037 | char *extra) | ||
4038 | { | ||
4039 | struct orinoco_private *priv = netdev_priv(dev); | ||
4040 | hermes_t *hw = &priv->hw; | ||
4041 | int err = 0; | ||
4042 | u16 short_limit, long_limit, lifetime; | ||
4043 | unsigned long flags; | ||
4044 | |||
4045 | if (orinoco_lock(priv, &flags) != 0) | ||
4046 | return -EBUSY; | ||
4047 | |||
4048 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, | ||
4049 | &short_limit); | ||
4050 | if (err) | ||
4051 | goto out; | ||
4052 | |||
4053 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, | ||
4054 | &long_limit); | ||
4055 | if (err) | ||
4056 | goto out; | ||
4057 | |||
4058 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, | ||
4059 | &lifetime); | ||
4060 | if (err) | ||
4061 | goto out; | ||
4062 | |||
4063 | rrq->disabled = 0; /* Can't be disabled */ | ||
4064 | |||
4065 | /* Note : by default, display the retry number */ | ||
4066 | if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
4067 | rrq->flags = IW_RETRY_LIFETIME; | ||
4068 | rrq->value = lifetime * 1000; /* ??? */ | ||
4069 | } else { | ||
4070 | /* By default, display the min number */ | ||
4071 | if ((rrq->flags & IW_RETRY_LONG)) { | ||
4072 | rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; | ||
4073 | rrq->value = long_limit; | ||
4074 | } else { | ||
4075 | rrq->flags = IW_RETRY_LIMIT; | ||
4076 | rrq->value = short_limit; | ||
4077 | if (short_limit != long_limit) | ||
4078 | rrq->flags |= IW_RETRY_SHORT; | ||
4079 | } | ||
4080 | } | ||
4081 | |||
4082 | out: | ||
4083 | orinoco_unlock(priv, &flags); | ||
4084 | |||
4085 | return err; | ||
4086 | } | ||
4087 | |||
4088 | static int orinoco_ioctl_reset(struct net_device *dev, | ||
4089 | struct iw_request_info *info, | ||
4090 | void *wrqu, | ||
4091 | char *extra) | ||
4092 | { | ||
4093 | struct orinoco_private *priv = netdev_priv(dev); | ||
4094 | |||
4095 | if (!capable(CAP_NET_ADMIN)) | ||
4096 | return -EPERM; | ||
4097 | |||
4098 | if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { | ||
4099 | printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); | ||
4100 | |||
4101 | /* Firmware reset */ | ||
4102 | orinoco_reset(&priv->reset_work); | ||
4103 | } else { | ||
4104 | printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); | ||
4105 | |||
4106 | schedule_work(&priv->reset_work); | ||
4107 | } | ||
4108 | |||
4109 | return 0; | ||
4110 | } | ||
4111 | |||
4112 | static int orinoco_ioctl_setibssport(struct net_device *dev, | ||
4113 | struct iw_request_info *info, | ||
4114 | void *wrqu, | ||
4115 | char *extra) | ||
4116 | |||
4117 | { | ||
4118 | struct orinoco_private *priv = netdev_priv(dev); | ||
4119 | int val = *((int *) extra); | ||
4120 | unsigned long flags; | ||
4121 | |||
4122 | if (orinoco_lock(priv, &flags) != 0) | ||
4123 | return -EBUSY; | ||
4124 | |||
4125 | priv->ibss_port = val ; | ||
4126 | |||
4127 | /* Actually update the mode we are using */ | ||
4128 | set_port_type(priv); | ||
4129 | |||
4130 | orinoco_unlock(priv, &flags); | ||
4131 | return -EINPROGRESS; /* Call commit handler */ | ||
4132 | } | ||
4133 | |||
4134 | static int orinoco_ioctl_getibssport(struct net_device *dev, | ||
4135 | struct iw_request_info *info, | ||
4136 | void *wrqu, | ||
4137 | char *extra) | ||
4138 | { | ||
4139 | struct orinoco_private *priv = netdev_priv(dev); | ||
4140 | int *val = (int *) extra; | ||
4141 | |||
4142 | *val = priv->ibss_port; | ||
4143 | return 0; | ||
4144 | } | ||
4145 | |||
4146 | static int orinoco_ioctl_setport3(struct net_device *dev, | ||
4147 | struct iw_request_info *info, | ||
4148 | void *wrqu, | ||
4149 | char *extra) | ||
4150 | { | ||
4151 | struct orinoco_private *priv = netdev_priv(dev); | ||
4152 | int val = *((int *) extra); | ||
4153 | int err = 0; | ||
4154 | unsigned long flags; | ||
4155 | |||
4156 | if (orinoco_lock(priv, &flags) != 0) | ||
4157 | return -EBUSY; | ||
4158 | |||
4159 | switch (val) { | ||
4160 | case 0: /* Try to do IEEE ad-hoc mode */ | ||
4161 | if (!priv->has_ibss) { | ||
4162 | err = -EINVAL; | ||
4163 | break; | ||
4164 | } | ||
4165 | priv->prefer_port3 = 0; | ||
4166 | |||
4167 | break; | ||
4168 | |||
4169 | case 1: /* Try to do Lucent proprietary ad-hoc mode */ | ||
4170 | if (!priv->has_port3) { | ||
4171 | err = -EINVAL; | ||
4172 | break; | ||
4173 | } | ||
4174 | priv->prefer_port3 = 1; | ||
4175 | break; | ||
4176 | |||
4177 | default: | ||
4178 | err = -EINVAL; | ||
4179 | } | ||
4180 | |||
4181 | if (!err) { | ||
4182 | /* Actually update the mode we are using */ | ||
4183 | set_port_type(priv); | ||
4184 | err = -EINPROGRESS; | ||
4185 | } | ||
4186 | |||
4187 | orinoco_unlock(priv, &flags); | ||
4188 | |||
4189 | return err; | ||
4190 | } | ||
4191 | |||
4192 | static int orinoco_ioctl_getport3(struct net_device *dev, | ||
4193 | struct iw_request_info *info, | ||
4194 | void *wrqu, | ||
4195 | char *extra) | ||
4196 | { | ||
4197 | struct orinoco_private *priv = netdev_priv(dev); | ||
4198 | int *val = (int *) extra; | ||
4199 | |||
4200 | *val = priv->prefer_port3; | ||
4201 | return 0; | ||
4202 | } | ||
4203 | |||
4204 | static int orinoco_ioctl_setpreamble(struct net_device *dev, | ||
4205 | struct iw_request_info *info, | ||
4206 | void *wrqu, | ||
4207 | char *extra) | ||
4208 | { | ||
4209 | struct orinoco_private *priv = netdev_priv(dev); | ||
4210 | unsigned long flags; | ||
4211 | int val; | ||
4212 | |||
4213 | if (!priv->has_preamble) | ||
4214 | return -EOPNOTSUPP; | ||
4215 | |||
4216 | /* 802.11b has recently defined some short preamble. | ||
4217 | * Basically, the Phy header has been reduced in size. | ||
4218 | * This increase performance, especially at high rates | ||
4219 | * (the preamble is transmitted at 1Mb/s), unfortunately | ||
4220 | * this give compatibility troubles... - Jean II */ | ||
4221 | val = *((int *) extra); | ||
4222 | |||
4223 | if (orinoco_lock(priv, &flags) != 0) | ||
4224 | return -EBUSY; | ||
4225 | |||
4226 | if (val) | ||
4227 | priv->preamble = 1; | ||
4228 | else | ||
4229 | priv->preamble = 0; | ||
4230 | |||
4231 | orinoco_unlock(priv, &flags); | ||
4232 | |||
4233 | return -EINPROGRESS; /* Call commit handler */ | ||
4234 | } | ||
4235 | |||
4236 | static int orinoco_ioctl_getpreamble(struct net_device *dev, | ||
4237 | struct iw_request_info *info, | ||
4238 | void *wrqu, | ||
4239 | char *extra) | ||
4240 | { | ||
4241 | struct orinoco_private *priv = netdev_priv(dev); | ||
4242 | int *val = (int *) extra; | ||
4243 | |||
4244 | if (!priv->has_preamble) | ||
4245 | return -EOPNOTSUPP; | ||
4246 | |||
4247 | *val = priv->preamble; | ||
4248 | return 0; | ||
4249 | } | ||
4250 | |||
4251 | /* ioctl interface to hermes_read_ltv() | ||
4252 | * To use with iwpriv, pass the RID as the token argument, e.g. | ||
4253 | * iwpriv get_rid [0xfc00] | ||
4254 | * At least Wireless Tools 25 is required to use iwpriv. | ||
4255 | * For Wireless Tools 25 and 26 append "dummy" are the end. */ | ||
4256 | static int orinoco_ioctl_getrid(struct net_device *dev, | ||
4257 | struct iw_request_info *info, | ||
4258 | struct iw_point *data, | ||
4259 | char *extra) | ||
4260 | { | ||
4261 | struct orinoco_private *priv = netdev_priv(dev); | ||
4262 | hermes_t *hw = &priv->hw; | ||
4263 | int rid = data->flags; | ||
4264 | u16 length; | ||
4265 | int err; | ||
4266 | unsigned long flags; | ||
4267 | |||
4268 | /* It's a "get" function, but we don't want users to access the | ||
4269 | * WEP key and other raw firmware data */ | ||
4270 | if (!capable(CAP_NET_ADMIN)) | ||
4271 | return -EPERM; | ||
4272 | |||
4273 | if (rid < 0xfc00 || rid > 0xffff) | ||
4274 | return -EINVAL; | ||
4275 | |||
4276 | if (orinoco_lock(priv, &flags) != 0) | ||
4277 | return -EBUSY; | ||
4278 | |||
4279 | err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, | ||
4280 | extra); | ||
4281 | if (err) | ||
4282 | goto out; | ||
4283 | |||
4284 | data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), | ||
4285 | MAX_RID_LEN); | ||
4286 | |||
4287 | out: | ||
4288 | orinoco_unlock(priv, &flags); | ||
4289 | return err; | ||
4290 | } | ||
4291 | |||
4292 | /* Trigger a scan (look for other cells in the vicinity) */ | ||
4293 | static int orinoco_ioctl_setscan(struct net_device *dev, | ||
4294 | struct iw_request_info *info, | ||
4295 | struct iw_point *srq, | ||
4296 | char *extra) | ||
4297 | { | ||
4298 | struct orinoco_private *priv = netdev_priv(dev); | ||
4299 | hermes_t *hw = &priv->hw; | ||
4300 | struct iw_scan_req *si = (struct iw_scan_req *) extra; | ||
4301 | int err = 0; | ||
4302 | unsigned long flags; | ||
4303 | |||
4304 | /* Note : you may have realised that, as this is a SET operation, | ||
4305 | * this is privileged and therefore a normal user can't | ||
4306 | * perform scanning. | ||
4307 | * This is not an error, while the device perform scanning, | ||
4308 | * traffic doesn't flow, so it's a perfect DoS... | ||
4309 | * Jean II */ | ||
4310 | |||
4311 | if (orinoco_lock(priv, &flags) != 0) | ||
4312 | return -EBUSY; | ||
4313 | |||
4314 | /* Scanning with port 0 disabled would fail */ | ||
4315 | if (!netif_running(dev)) { | ||
4316 | err = -ENETDOWN; | ||
4317 | goto out; | ||
4318 | } | ||
4319 | |||
4320 | /* In monitor mode, the scan results are always empty. | ||
4321 | * Probe responses are passed to the driver as received | ||
4322 | * frames and could be processed in software. */ | ||
4323 | if (priv->iw_mode == IW_MODE_MONITOR) { | ||
4324 | err = -EOPNOTSUPP; | ||
4325 | goto out; | ||
4326 | } | ||
4327 | |||
4328 | /* Note : because we don't lock out the irq handler, the way | ||
4329 | * we access scan variables in priv is critical. | ||
4330 | * o scan_inprogress : not touched by irq handler | ||
4331 | * o scan_mode : not touched by irq handler | ||
4332 | * Before modifying anything on those variables, please think hard ! | ||
4333 | * Jean II */ | ||
4334 | |||
4335 | /* Save flags */ | ||
4336 | priv->scan_mode = srq->flags; | ||
4337 | |||
4338 | /* Always trigger scanning, even if it's in progress. | ||
4339 | * This way, if the info frame get lost, we will recover somewhat | ||
4340 | * gracefully - Jean II */ | ||
4341 | |||
4342 | if (priv->has_hostscan) { | ||
4343 | switch (priv->firmware_type) { | ||
4344 | case FIRMWARE_TYPE_SYMBOL: | ||
4345 | err = hermes_write_wordrec(hw, USER_BAP, | ||
4346 | HERMES_RID_CNFHOSTSCAN_SYMBOL, | ||
4347 | HERMES_HOSTSCAN_SYMBOL_ONCE | | ||
4348 | HERMES_HOSTSCAN_SYMBOL_BCAST); | ||
4349 | break; | ||
4350 | case FIRMWARE_TYPE_INTERSIL: { | ||
4351 | __le16 req[3]; | ||
4352 | |||
4353 | req[0] = cpu_to_le16(0x3fff); /* All channels */ | ||
4354 | req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ | ||
4355 | req[2] = 0; /* Any ESSID */ | ||
4356 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
4357 | HERMES_RID_CNFHOSTSCAN, &req); | ||
4358 | } | ||
4359 | break; | ||
4360 | case FIRMWARE_TYPE_AGERE: | ||
4361 | if (priv->scan_mode & IW_SCAN_THIS_ESSID) { | ||
4362 | struct hermes_idstring idbuf; | ||
4363 | size_t len = min(sizeof(idbuf.val), | ||
4364 | (size_t) si->essid_len); | ||
4365 | idbuf.len = cpu_to_le16(len); | ||
4366 | memcpy(idbuf.val, si->essid, len); | ||
4367 | |||
4368 | err = hermes_write_ltv(hw, USER_BAP, | ||
4369 | HERMES_RID_CNFSCANSSID_AGERE, | ||
4370 | HERMES_BYTES_TO_RECLEN(len + 2), | ||
4371 | &idbuf); | ||
4372 | } else | ||
4373 | err = hermes_write_wordrec(hw, USER_BAP, | ||
4374 | HERMES_RID_CNFSCANSSID_AGERE, | ||
4375 | 0); /* Any ESSID */ | ||
4376 | if (err) | ||
4377 | break; | ||
4378 | |||
4379 | if (priv->has_ext_scan) { | ||
4380 | /* Clear scan results at the start of | ||
4381 | * an extended scan */ | ||
4382 | orinoco_clear_scan_results(priv, | ||
4383 | msecs_to_jiffies(15000)); | ||
4384 | |||
4385 | /* TODO: Is this available on older firmware? | ||
4386 | * Can we use it to scan specific channels | ||
4387 | * for IW_SCAN_THIS_FREQ? */ | ||
4388 | err = hermes_write_wordrec(hw, USER_BAP, | ||
4389 | HERMES_RID_CNFSCANCHANNELS2GHZ, | ||
4390 | 0x7FFF); | ||
4391 | if (err) | ||
4392 | goto out; | ||
4393 | |||
4394 | err = hermes_inquire(hw, | ||
4395 | HERMES_INQ_CHANNELINFO); | ||
4396 | } else | ||
4397 | err = hermes_inquire(hw, HERMES_INQ_SCAN); | ||
4398 | break; | ||
4399 | } | ||
4400 | } else | ||
4401 | err = hermes_inquire(hw, HERMES_INQ_SCAN); | ||
4402 | |||
4403 | /* One more client */ | ||
4404 | if (!err) | ||
4405 | priv->scan_inprogress = 1; | ||
4406 | |||
4407 | out: | ||
4408 | orinoco_unlock(priv, &flags); | ||
4409 | return err; | ||
4410 | } | ||
4411 | |||
4412 | #define MAX_CUSTOM_LEN 64 | ||
4413 | |||
4414 | /* Translate scan data returned from the card to a card independant | ||
4415 | * format that the Wireless Tools will understand - Jean II */ | ||
4416 | static inline char *orinoco_translate_scan(struct net_device *dev, | ||
4417 | struct iw_request_info *info, | ||
4418 | char *current_ev, | ||
4419 | char *end_buf, | ||
4420 | union hermes_scan_info *bss, | ||
4421 | unsigned long last_scanned) | ||
4422 | { | ||
4423 | struct orinoco_private *priv = netdev_priv(dev); | ||
4424 | u16 capabilities; | ||
4425 | u16 channel; | ||
4426 | struct iw_event iwe; /* Temporary buffer */ | ||
4427 | char custom[MAX_CUSTOM_LEN]; | ||
4428 | |||
4429 | memset(&iwe, 0, sizeof(iwe)); | ||
4430 | |||
4431 | /* First entry *MUST* be the AP MAC address */ | ||
4432 | iwe.cmd = SIOCGIWAP; | ||
4433 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
4434 | memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); | ||
4435 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4436 | &iwe, IW_EV_ADDR_LEN); | ||
4437 | |||
4438 | /* Other entries will be displayed in the order we give them */ | ||
4439 | |||
4440 | /* Add the ESSID */ | ||
4441 | iwe.u.data.length = le16_to_cpu(bss->a.essid_len); | ||
4442 | if (iwe.u.data.length > 32) | ||
4443 | iwe.u.data.length = 32; | ||
4444 | iwe.cmd = SIOCGIWESSID; | ||
4445 | iwe.u.data.flags = 1; | ||
4446 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4447 | &iwe, bss->a.essid); | ||
4448 | |||
4449 | /* Add mode */ | ||
4450 | iwe.cmd = SIOCGIWMODE; | ||
4451 | capabilities = le16_to_cpu(bss->a.capabilities); | ||
4452 | if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | ||
4453 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
4454 | iwe.u.mode = IW_MODE_MASTER; | ||
4455 | else | ||
4456 | iwe.u.mode = IW_MODE_ADHOC; | ||
4457 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4458 | &iwe, IW_EV_UINT_LEN); | ||
4459 | } | ||
4460 | |||
4461 | channel = bss->s.channel; | ||
4462 | if ((channel >= 1) && (channel <= NUM_CHANNELS)) { | ||
4463 | /* Add channel and frequency */ | ||
4464 | iwe.cmd = SIOCGIWFREQ; | ||
4465 | iwe.u.freq.m = channel; | ||
4466 | iwe.u.freq.e = 0; | ||
4467 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4468 | &iwe, IW_EV_FREQ_LEN); | ||
4469 | |||
4470 | iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; | ||
4471 | iwe.u.freq.e = 1; | ||
4472 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4473 | &iwe, IW_EV_FREQ_LEN); | ||
4474 | } | ||
4475 | |||
4476 | /* Add quality statistics. level and noise in dB. No link quality */ | ||
4477 | iwe.cmd = IWEVQUAL; | ||
4478 | iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; | ||
4479 | iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; | ||
4480 | iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; | ||
4481 | /* Wireless tools prior to 27.pre22 will show link quality | ||
4482 | * anyway, so we provide a reasonable value. */ | ||
4483 | if (iwe.u.qual.level > iwe.u.qual.noise) | ||
4484 | iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; | ||
4485 | else | ||
4486 | iwe.u.qual.qual = 0; | ||
4487 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4488 | &iwe, IW_EV_QUAL_LEN); | ||
4489 | |||
4490 | /* Add encryption capability */ | ||
4491 | iwe.cmd = SIOCGIWENCODE; | ||
4492 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
4493 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
4494 | else | ||
4495 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
4496 | iwe.u.data.length = 0; | ||
4497 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4498 | &iwe, NULL); | ||
4499 | |||
4500 | /* Bit rate is not available in Lucent/Agere firmwares */ | ||
4501 | if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { | ||
4502 | char *current_val = current_ev + iwe_stream_lcp_len(info); | ||
4503 | int i; | ||
4504 | int step; | ||
4505 | |||
4506 | if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) | ||
4507 | step = 2; | ||
4508 | else | ||
4509 | step = 1; | ||
4510 | |||
4511 | iwe.cmd = SIOCGIWRATE; | ||
4512 | /* Those two flags are ignored... */ | ||
4513 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
4514 | /* Max 10 values */ | ||
4515 | for (i = 0; i < 10; i += step) { | ||
4516 | /* NULL terminated */ | ||
4517 | if (bss->p.rates[i] == 0x0) | ||
4518 | break; | ||
4519 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
4520 | iwe.u.bitrate.value = | ||
4521 | ((bss->p.rates[i] & 0x7f) * 500000); | ||
4522 | current_val = iwe_stream_add_value(info, current_ev, | ||
4523 | current_val, | ||
4524 | end_buf, &iwe, | ||
4525 | IW_EV_PARAM_LEN); | ||
4526 | } | ||
4527 | /* Check if we added any event */ | ||
4528 | if ((current_val - current_ev) > iwe_stream_lcp_len(info)) | ||
4529 | current_ev = current_val; | ||
4530 | } | ||
4531 | |||
4532 | /* Beacon interval */ | ||
4533 | iwe.cmd = IWEVCUSTOM; | ||
4534 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
4535 | "bcn_int=%d", | ||
4536 | le16_to_cpu(bss->a.beacon_interv)); | ||
4537 | if (iwe.u.data.length) | ||
4538 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4539 | &iwe, custom); | ||
4540 | |||
4541 | /* Capabilites */ | ||
4542 | iwe.cmd = IWEVCUSTOM; | ||
4543 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
4544 | "capab=0x%04x", | ||
4545 | capabilities); | ||
4546 | if (iwe.u.data.length) | ||
4547 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4548 | &iwe, custom); | ||
4549 | |||
4550 | /* Add EXTRA: Age to display seconds since last beacon/probe response | ||
4551 | * for given network. */ | ||
4552 | iwe.cmd = IWEVCUSTOM; | ||
4553 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
4554 | " Last beacon: %dms ago", | ||
4555 | jiffies_to_msecs(jiffies - last_scanned)); | ||
4556 | if (iwe.u.data.length) | ||
4557 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4558 | &iwe, custom); | ||
4559 | |||
4560 | return current_ev; | ||
4561 | } | ||
4562 | |||
4563 | static inline char *orinoco_translate_ext_scan(struct net_device *dev, | ||
4564 | struct iw_request_info *info, | ||
4565 | char *current_ev, | ||
4566 | char *end_buf, | ||
4567 | struct agere_ext_scan_info *bss, | ||
4568 | unsigned long last_scanned) | ||
4569 | { | ||
4570 | u16 capabilities; | ||
4571 | u16 channel; | ||
4572 | struct iw_event iwe; /* Temporary buffer */ | ||
4573 | char custom[MAX_CUSTOM_LEN]; | ||
4574 | u8 *ie; | ||
4575 | |||
4576 | memset(&iwe, 0, sizeof(iwe)); | ||
4577 | |||
4578 | /* First entry *MUST* be the AP MAC address */ | ||
4579 | iwe.cmd = SIOCGIWAP; | ||
4580 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
4581 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | ||
4582 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4583 | &iwe, IW_EV_ADDR_LEN); | ||
4584 | |||
4585 | /* Other entries will be displayed in the order we give them */ | ||
4586 | |||
4587 | /* Add the ESSID */ | ||
4588 | ie = bss->data; | ||
4589 | iwe.u.data.length = ie[1]; | ||
4590 | if (iwe.u.data.length) { | ||
4591 | if (iwe.u.data.length > 32) | ||
4592 | iwe.u.data.length = 32; | ||
4593 | iwe.cmd = SIOCGIWESSID; | ||
4594 | iwe.u.data.flags = 1; | ||
4595 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4596 | &iwe, &ie[2]); | ||
4597 | } | ||
4598 | |||
4599 | /* Add mode */ | ||
4600 | capabilities = le16_to_cpu(bss->capabilities); | ||
4601 | if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | ||
4602 | iwe.cmd = SIOCGIWMODE; | ||
4603 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
4604 | iwe.u.mode = IW_MODE_MASTER; | ||
4605 | else | ||
4606 | iwe.u.mode = IW_MODE_ADHOC; | ||
4607 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4608 | &iwe, IW_EV_UINT_LEN); | ||
4609 | } | ||
4610 | |||
4611 | ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); | ||
4612 | channel = ie ? ie[2] : 0; | ||
4613 | if ((channel >= 1) && (channel <= NUM_CHANNELS)) { | ||
4614 | /* Add channel and frequency */ | ||
4615 | iwe.cmd = SIOCGIWFREQ; | ||
4616 | iwe.u.freq.m = channel; | ||
4617 | iwe.u.freq.e = 0; | ||
4618 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4619 | &iwe, IW_EV_FREQ_LEN); | ||
4620 | |||
4621 | iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; | ||
4622 | iwe.u.freq.e = 1; | ||
4623 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4624 | &iwe, IW_EV_FREQ_LEN); | ||
4625 | } | ||
4626 | |||
4627 | /* Add quality statistics. level and noise in dB. No link quality */ | ||
4628 | iwe.cmd = IWEVQUAL; | ||
4629 | iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; | ||
4630 | iwe.u.qual.level = bss->level - 0x95; | ||
4631 | iwe.u.qual.noise = bss->noise - 0x95; | ||
4632 | /* Wireless tools prior to 27.pre22 will show link quality | ||
4633 | * anyway, so we provide a reasonable value. */ | ||
4634 | if (iwe.u.qual.level > iwe.u.qual.noise) | ||
4635 | iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; | ||
4636 | else | ||
4637 | iwe.u.qual.qual = 0; | ||
4638 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4639 | &iwe, IW_EV_QUAL_LEN); | ||
4640 | |||
4641 | /* Add encryption capability */ | ||
4642 | iwe.cmd = SIOCGIWENCODE; | ||
4643 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
4644 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
4645 | else | ||
4646 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
4647 | iwe.u.data.length = 0; | ||
4648 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4649 | &iwe, NULL); | ||
4650 | |||
4651 | /* WPA IE */ | ||
4652 | ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); | ||
4653 | if (ie) { | ||
4654 | iwe.cmd = IWEVGENIE; | ||
4655 | iwe.u.data.length = ie[1] + 2; | ||
4656 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4657 | &iwe, ie); | ||
4658 | } | ||
4659 | |||
4660 | /* RSN IE */ | ||
4661 | ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); | ||
4662 | if (ie) { | ||
4663 | iwe.cmd = IWEVGENIE; | ||
4664 | iwe.u.data.length = ie[1] + 2; | ||
4665 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4666 | &iwe, ie); | ||
4667 | } | ||
4668 | |||
4669 | ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); | ||
4670 | if (ie) { | ||
4671 | char *p = current_ev + iwe_stream_lcp_len(info); | ||
4672 | int i; | ||
4673 | |||
4674 | iwe.cmd = SIOCGIWRATE; | ||
4675 | /* Those two flags are ignored... */ | ||
4676 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
4677 | |||
4678 | for (i = 2; i < (ie[1] + 2); i++) { | ||
4679 | iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); | ||
4680 | p = iwe_stream_add_value(info, current_ev, p, end_buf, | ||
4681 | &iwe, IW_EV_PARAM_LEN); | ||
4682 | } | ||
4683 | /* Check if we added any event */ | ||
4684 | if (p > (current_ev + iwe_stream_lcp_len(info))) | ||
4685 | current_ev = p; | ||
4686 | } | ||
4687 | |||
4688 | /* Timestamp */ | ||
4689 | iwe.cmd = IWEVCUSTOM; | ||
4690 | iwe.u.data.length = | ||
4691 | snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", | ||
4692 | (unsigned long long) le64_to_cpu(bss->timestamp)); | ||
4693 | if (iwe.u.data.length) | ||
4694 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4695 | &iwe, custom); | ||
4696 | |||
4697 | /* Beacon interval */ | ||
4698 | iwe.cmd = IWEVCUSTOM; | ||
4699 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
4700 | "bcn_int=%d", | ||
4701 | le16_to_cpu(bss->beacon_interval)); | ||
4702 | if (iwe.u.data.length) | ||
4703 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4704 | &iwe, custom); | ||
4705 | |||
4706 | /* Capabilites */ | ||
4707 | iwe.cmd = IWEVCUSTOM; | ||
4708 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
4709 | "capab=0x%04x", | ||
4710 | capabilities); | ||
4711 | if (iwe.u.data.length) | ||
4712 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4713 | &iwe, custom); | ||
4714 | |||
4715 | /* Add EXTRA: Age to display seconds since last beacon/probe response | ||
4716 | * for given network. */ | ||
4717 | iwe.cmd = IWEVCUSTOM; | ||
4718 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
4719 | " Last beacon: %dms ago", | ||
4720 | jiffies_to_msecs(jiffies - last_scanned)); | ||
4721 | if (iwe.u.data.length) | ||
4722 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4723 | &iwe, custom); | ||
4724 | |||
4725 | return current_ev; | ||
4726 | } | ||
4727 | |||
4728 | /* Return results of a scan */ | ||
4729 | static int orinoco_ioctl_getscan(struct net_device *dev, | ||
4730 | struct iw_request_info *info, | ||
4731 | struct iw_point *srq, | ||
4732 | char *extra) | ||
4733 | { | ||
4734 | struct orinoco_private *priv = netdev_priv(dev); | ||
4735 | int err = 0; | ||
4736 | unsigned long flags; | ||
4737 | char *current_ev = extra; | ||
4738 | |||
4739 | if (orinoco_lock(priv, &flags) != 0) | ||
4740 | return -EBUSY; | ||
4741 | |||
4742 | if (priv->scan_inprogress) { | ||
4743 | /* Important note : we don't want to block the caller | ||
4744 | * until results are ready for various reasons. | ||
4745 | * First, managing wait queues is complex and racy. | ||
4746 | * Second, we grab some rtnetlink lock before comming | ||
4747 | * here (in dev_ioctl()). | ||
4748 | * Third, we generate an Wireless Event, so the | ||
4749 | * caller can wait itself on that - Jean II */ | ||
4750 | err = -EAGAIN; | ||
4751 | goto out; | ||
4752 | } | ||
4753 | |||
4754 | if (priv->has_ext_scan) { | ||
4755 | struct xbss_element *bss; | ||
4756 | |||
4757 | list_for_each_entry(bss, &priv->bss_list, list) { | ||
4758 | /* Translate this entry to WE format */ | ||
4759 | current_ev = | ||
4760 | orinoco_translate_ext_scan(dev, info, | ||
4761 | current_ev, | ||
4762 | extra + srq->length, | ||
4763 | &bss->bss, | ||
4764 | bss->last_scanned); | ||
4765 | |||
4766 | /* Check if there is space for one more entry */ | ||
4767 | if ((extra + srq->length - current_ev) | ||
4768 | <= IW_EV_ADDR_LEN) { | ||
4769 | /* Ask user space to try again with a | ||
4770 | * bigger buffer */ | ||
4771 | err = -E2BIG; | ||
4772 | goto out; | ||
4773 | } | ||
4774 | } | ||
4775 | |||
4776 | } else { | ||
4777 | struct bss_element *bss; | ||
4778 | |||
4779 | list_for_each_entry(bss, &priv->bss_list, list) { | ||
4780 | /* Translate this entry to WE format */ | ||
4781 | current_ev = orinoco_translate_scan(dev, info, | ||
4782 | current_ev, | ||
4783 | extra + srq->length, | ||
4784 | &bss->bss, | ||
4785 | bss->last_scanned); | ||
4786 | |||
4787 | /* Check if there is space for one more entry */ | ||
4788 | if ((extra + srq->length - current_ev) | ||
4789 | <= IW_EV_ADDR_LEN) { | ||
4790 | /* Ask user space to try again with a | ||
4791 | * bigger buffer */ | ||
4792 | err = -E2BIG; | ||
4793 | goto out; | ||
4794 | } | ||
4795 | } | ||
4796 | } | ||
4797 | |||
4798 | srq->length = (current_ev - extra); | ||
4799 | srq->flags = (__u16) priv->scan_mode; | ||
4800 | |||
4801 | out: | ||
4802 | orinoco_unlock(priv, &flags); | ||
4803 | return err; | ||
4804 | } | ||
4805 | |||
4806 | /* Commit handler, called after set operations */ | ||
4807 | static int orinoco_ioctl_commit(struct net_device *dev, | ||
4808 | struct iw_request_info *info, | ||
4809 | void *wrqu, | ||
4810 | char *extra) | ||
4811 | { | ||
4812 | struct orinoco_private *priv = netdev_priv(dev); | ||
4813 | struct hermes *hw = &priv->hw; | ||
4814 | unsigned long flags; | ||
4815 | int err = 0; | ||
4816 | |||
4817 | if (!priv->open) | ||
4818 | return 0; | ||
4819 | |||
4820 | if (priv->broken_disableport) { | ||
4821 | orinoco_reset(&priv->reset_work); | ||
4822 | return 0; | ||
4823 | } | ||
4824 | |||
4825 | if (orinoco_lock(priv, &flags) != 0) | ||
4826 | return err; | ||
4827 | |||
4828 | err = hermes_disable_port(hw, 0); | ||
4829 | if (err) { | ||
4830 | printk(KERN_WARNING "%s: Unable to disable port " | ||
4831 | "while reconfiguring card\n", dev->name); | ||
4832 | priv->broken_disableport = 1; | ||
4833 | goto out; | ||
4834 | } | ||
4835 | |||
4836 | err = __orinoco_program_rids(dev); | ||
4837 | if (err) { | ||
4838 | printk(KERN_WARNING "%s: Unable to reconfigure card\n", | ||
4839 | dev->name); | ||
4840 | goto out; | ||
4841 | } | ||
4842 | |||
4843 | err = hermes_enable_port(hw, 0); | ||
4844 | if (err) { | ||
4845 | printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", | ||
4846 | dev->name); | ||
4847 | goto out; | ||
4848 | } | ||
4849 | |||
4850 | out: | ||
4851 | if (err) { | ||
4852 | printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); | ||
4853 | schedule_work(&priv->reset_work); | ||
4854 | err = 0; | ||
4855 | } | ||
4856 | |||
4857 | orinoco_unlock(priv, &flags); | ||
4858 | return err; | ||
4859 | } | ||
4860 | |||
4861 | static const struct iw_priv_args orinoco_privtab[] = { | ||
4862 | { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, | ||
4863 | { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, | ||
4864 | { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
4865 | 0, "set_port3" }, | ||
4866 | { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
4867 | "get_port3" }, | ||
4868 | { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
4869 | 0, "set_preamble" }, | ||
4870 | { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
4871 | "get_preamble" }, | ||
4872 | { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
4873 | 0, "set_ibssport" }, | ||
4874 | { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
4875 | "get_ibssport" }, | ||
4876 | { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, | ||
4877 | "get_rid" }, | ||
4878 | }; | ||
4879 | |||
4880 | |||
4881 | /* | ||
4882 | * Structures to export the Wireless Handlers | ||
4883 | */ | ||
4884 | |||
4885 | #define STD_IW_HANDLER(id, func) \ | ||
4886 | [IW_IOCTL_IDX(id)] = (iw_handler) func | ||
4887 | static const iw_handler orinoco_handler[] = { | ||
4888 | STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), | ||
4889 | STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), | ||
4890 | STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), | ||
4891 | STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), | ||
4892 | STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), | ||
4893 | STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), | ||
4894 | STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), | ||
4895 | STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), | ||
4896 | STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), | ||
4897 | STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), | ||
4898 | STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), | ||
4899 | STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), | ||
4900 | STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), | ||
4901 | STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), | ||
4902 | STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), | ||
4903 | STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), | ||
4904 | STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), | ||
4905 | STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), | ||
4906 | STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), | ||
4907 | STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), | ||
4908 | STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), | ||
4909 | STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), | ||
4910 | STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), | ||
4911 | STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), | ||
4912 | STD_IW_HANDLER(SIOCGIWRTS, orinoco_ioctl_getrts), | ||
4913 | STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag), | ||
4914 | STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag), | ||
4915 | STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry), | ||
4916 | STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), | ||
4917 | STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), | ||
4918 | STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), | ||
4919 | STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), | ||
4920 | STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), | ||
4921 | STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), | ||
4922 | STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), | ||
4923 | STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), | ||
4924 | STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), | ||
4925 | STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), | ||
4926 | STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), | ||
4927 | }; | ||
4928 | |||
4929 | |||
4930 | /* | ||
4931 | Added typecasting since we no longer use iwreq_data -- Moustafa | ||
4932 | */ | ||
4933 | static const iw_handler orinoco_private_handler[] = { | ||
4934 | [0] = (iw_handler) orinoco_ioctl_reset, | ||
4935 | [1] = (iw_handler) orinoco_ioctl_reset, | ||
4936 | [2] = (iw_handler) orinoco_ioctl_setport3, | ||
4937 | [3] = (iw_handler) orinoco_ioctl_getport3, | ||
4938 | [4] = (iw_handler) orinoco_ioctl_setpreamble, | ||
4939 | [5] = (iw_handler) orinoco_ioctl_getpreamble, | ||
4940 | [6] = (iw_handler) orinoco_ioctl_setibssport, | ||
4941 | [7] = (iw_handler) orinoco_ioctl_getibssport, | ||
4942 | [9] = (iw_handler) orinoco_ioctl_getrid, | ||
4943 | }; | ||
4944 | |||
4945 | static const struct iw_handler_def orinoco_handler_def = { | ||
4946 | .num_standard = ARRAY_SIZE(orinoco_handler), | ||
4947 | .num_private = ARRAY_SIZE(orinoco_private_handler), | ||
4948 | .num_private_args = ARRAY_SIZE(orinoco_privtab), | ||
4949 | .standard = orinoco_handler, | ||
4950 | .private = orinoco_private_handler, | ||
4951 | .private_args = orinoco_privtab, | ||
4952 | .get_wireless_stats = orinoco_get_wireless_stats, | ||
4953 | }; | ||
4954 | |||
4955 | static void orinoco_get_drvinfo(struct net_device *dev, | 2612 | static void orinoco_get_drvinfo(struct net_device *dev, |
4956 | struct ethtool_drvinfo *info) | 2613 | struct ethtool_drvinfo *info) |
4957 | { | 2614 | { |