diff options
author | John W. Linville <linville@tuxdriver.com> | 2008-06-25 15:17:58 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-25 15:17:58 -0400 |
commit | 1839cea91e5629756dd4f87c5d70d8a18b89c0b4 (patch) | |
tree | 88c6788cab32303570c7558dda5cbf40ed26bfb3 /net | |
parent | e35c3269edba151e1c703d87068a28ce2cd65bb0 (diff) | |
parent | ccc580571cf0799d0460a085a7632b77753f083e (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/wireless-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 48 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 5 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 66 | ||||
-rw-r--r-- | net/mac80211/wext.c | 2 | ||||
-rw-r--r-- | net/socket.c | 10 | ||||
-rw-r--r-- | net/wireless/wext.c | 582 |
6 files changed, 443 insertions, 270 deletions
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 822606b615ca..973832dd7faf 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c | |||
@@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = { | |||
43 | 43 | ||
44 | #define MAX_CUSTOM_LEN 64 | 44 | #define MAX_CUSTOM_LEN 64 |
45 | static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | 45 | static char *ieee80211_translate_scan(struct ieee80211_device *ieee, |
46 | char *start, char *stop, | 46 | char *start, char *stop, |
47 | struct ieee80211_network *network) | 47 | struct ieee80211_network *network, |
48 | struct iw_request_info *info) | ||
48 | { | 49 | { |
49 | char custom[MAX_CUSTOM_LEN]; | 50 | char custom[MAX_CUSTOM_LEN]; |
50 | char *p; | 51 | char *p; |
@@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
57 | iwe.cmd = SIOCGIWAP; | 58 | iwe.cmd = SIOCGIWAP; |
58 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 59 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
59 | memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); | 60 | memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); |
60 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); | 61 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); |
61 | 62 | ||
62 | /* Remaining entries will be displayed in the order we provide them */ | 63 | /* Remaining entries will be displayed in the order we provide them */ |
63 | 64 | ||
@@ -66,17 +67,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
66 | iwe.u.data.flags = 1; | 67 | iwe.u.data.flags = 1; |
67 | if (network->flags & NETWORK_EMPTY_ESSID) { | 68 | if (network->flags & NETWORK_EMPTY_ESSID) { |
68 | iwe.u.data.length = sizeof("<hidden>"); | 69 | iwe.u.data.length = sizeof("<hidden>"); |
69 | start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); | 70 | start = iwe_stream_add_point(info, start, stop, |
71 | &iwe, "<hidden>"); | ||
70 | } else { | 72 | } else { |
71 | iwe.u.data.length = min(network->ssid_len, (u8) 32); | 73 | iwe.u.data.length = min(network->ssid_len, (u8) 32); |
72 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 74 | start = iwe_stream_add_point(info, start, stop, |
75 | &iwe, network->ssid); | ||
73 | } | 76 | } |
74 | 77 | ||
75 | /* Add the protocol name */ | 78 | /* Add the protocol name */ |
76 | iwe.cmd = SIOCGIWNAME; | 79 | iwe.cmd = SIOCGIWNAME; |
77 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", | 80 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", |
78 | ieee80211_modes[network->mode]); | 81 | ieee80211_modes[network->mode]); |
79 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); | 82 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); |
80 | 83 | ||
81 | /* Add mode */ | 84 | /* Add mode */ |
82 | iwe.cmd = SIOCGIWMODE; | 85 | iwe.cmd = SIOCGIWMODE; |
@@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
86 | else | 89 | else |
87 | iwe.u.mode = IW_MODE_ADHOC; | 90 | iwe.u.mode = IW_MODE_ADHOC; |
88 | 91 | ||
89 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); | 92 | start = iwe_stream_add_event(info, start, stop, |
93 | &iwe, IW_EV_UINT_LEN); | ||
90 | } | 94 | } |
91 | 95 | ||
92 | /* Add channel and frequency */ | 96 | /* Add channel and frequency */ |
@@ -95,7 +99,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
95 | iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); | 99 | iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); |
96 | iwe.u.freq.e = 6; | 100 | iwe.u.freq.e = 6; |
97 | iwe.u.freq.i = 0; | 101 | iwe.u.freq.i = 0; |
98 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); | 102 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); |
99 | 103 | ||
100 | /* Add encryption capability */ | 104 | /* Add encryption capability */ |
101 | iwe.cmd = SIOCGIWENCODE; | 105 | iwe.cmd = SIOCGIWENCODE; |
@@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
104 | else | 108 | else |
105 | iwe.u.data.flags = IW_ENCODE_DISABLED; | 109 | iwe.u.data.flags = IW_ENCODE_DISABLED; |
106 | iwe.u.data.length = 0; | 110 | iwe.u.data.length = 0; |
107 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 111 | start = iwe_stream_add_point(info, start, stop, |
112 | &iwe, network->ssid); | ||
108 | 113 | ||
109 | /* Add basic and extended rates */ | 114 | /* Add basic and extended rates */ |
110 | /* Rate : stuffing multiple values in a single event require a bit | 115 | /* Rate : stuffing multiple values in a single event require a bit |
111 | * more of magic - Jean II */ | 116 | * more of magic - Jean II */ |
112 | current_val = start + IW_EV_LCP_LEN; | 117 | current_val = start + iwe_stream_lcp_len(info); |
113 | iwe.cmd = SIOCGIWRATE; | 118 | iwe.cmd = SIOCGIWRATE; |
114 | /* Those two flags are ignored... */ | 119 | /* Those two flags are ignored... */ |
115 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | 120 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; |
@@ -124,17 +129,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
124 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | 129 | /* Bit rate given in 500 kb/s units (+ 0x80) */ |
125 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); | 130 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); |
126 | /* Add new value to event */ | 131 | /* Add new value to event */ |
127 | current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); | 132 | current_val = iwe_stream_add_value(info, start, current_val, |
133 | stop, &iwe, IW_EV_PARAM_LEN); | ||
128 | } | 134 | } |
129 | for (; j < network->rates_ex_len; j++) { | 135 | for (; j < network->rates_ex_len; j++) { |
130 | rate = network->rates_ex[j] & 0x7F; | 136 | rate = network->rates_ex[j] & 0x7F; |
131 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | 137 | /* Bit rate given in 500 kb/s units (+ 0x80) */ |
132 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); | 138 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); |
133 | /* Add new value to event */ | 139 | /* Add new value to event */ |
134 | current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); | 140 | current_val = iwe_stream_add_value(info, start, current_val, |
141 | stop, &iwe, IW_EV_PARAM_LEN); | ||
135 | } | 142 | } |
136 | /* Check if we added any rate */ | 143 | /* Check if we added any rate */ |
137 | if((current_val - start) > IW_EV_LCP_LEN) | 144 | if ((current_val - start) > iwe_stream_lcp_len(info)) |
138 | start = current_val; | 145 | start = current_val; |
139 | 146 | ||
140 | /* Add quality statistics */ | 147 | /* Add quality statistics */ |
@@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
181 | iwe.u.qual.level = network->stats.signal; | 188 | iwe.u.qual.level = network->stats.signal; |
182 | } | 189 | } |
183 | 190 | ||
184 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); | 191 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); |
185 | 192 | ||
186 | iwe.cmd = IWEVCUSTOM; | 193 | iwe.cmd = IWEVCUSTOM; |
187 | p = custom; | 194 | p = custom; |
188 | 195 | ||
189 | iwe.u.data.length = p - custom; | 196 | iwe.u.data.length = p - custom; |
190 | if (iwe.u.data.length) | 197 | if (iwe.u.data.length) |
191 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 198 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
192 | 199 | ||
193 | memset(&iwe, 0, sizeof(iwe)); | 200 | memset(&iwe, 0, sizeof(iwe)); |
194 | if (network->wpa_ie_len) { | 201 | if (network->wpa_ie_len) { |
@@ -196,7 +203,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
196 | memcpy(buf, network->wpa_ie, network->wpa_ie_len); | 203 | memcpy(buf, network->wpa_ie, network->wpa_ie_len); |
197 | iwe.cmd = IWEVGENIE; | 204 | iwe.cmd = IWEVGENIE; |
198 | iwe.u.data.length = network->wpa_ie_len; | 205 | iwe.u.data.length = network->wpa_ie_len; |
199 | start = iwe_stream_add_point(start, stop, &iwe, buf); | 206 | start = iwe_stream_add_point(info, start, stop, &iwe, buf); |
200 | } | 207 | } |
201 | 208 | ||
202 | memset(&iwe, 0, sizeof(iwe)); | 209 | memset(&iwe, 0, sizeof(iwe)); |
@@ -205,7 +212,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
205 | memcpy(buf, network->rsn_ie, network->rsn_ie_len); | 212 | memcpy(buf, network->rsn_ie, network->rsn_ie_len); |
206 | iwe.cmd = IWEVGENIE; | 213 | iwe.cmd = IWEVGENIE; |
207 | iwe.u.data.length = network->rsn_ie_len; | 214 | iwe.u.data.length = network->rsn_ie_len; |
208 | start = iwe_stream_add_point(start, stop, &iwe, buf); | 215 | start = iwe_stream_add_point(info, start, stop, &iwe, buf); |
209 | } | 216 | } |
210 | 217 | ||
211 | /* Add EXTRA: Age to display seconds since last beacon/probe response | 218 | /* Add EXTRA: Age to display seconds since last beacon/probe response |
@@ -217,7 +224,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
217 | jiffies_to_msecs(jiffies - network->last_scanned)); | 224 | jiffies_to_msecs(jiffies - network->last_scanned)); |
218 | iwe.u.data.length = p - custom; | 225 | iwe.u.data.length = p - custom; |
219 | if (iwe.u.data.length) | 226 | if (iwe.u.data.length) |
220 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 227 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
221 | 228 | ||
222 | /* Add spectrum management information */ | 229 | /* Add spectrum management information */ |
223 | iwe.cmd = -1; | 230 | iwe.cmd = -1; |
@@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
238 | 245 | ||
239 | if (iwe.cmd == IWEVCUSTOM) { | 246 | if (iwe.cmd == IWEVCUSTOM) { |
240 | iwe.u.data.length = p - custom; | 247 | iwe.u.data.length = p - custom; |
241 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 248 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
242 | } | 249 | } |
243 | 250 | ||
244 | return start; | 251 | return start; |
@@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, | |||
272 | 279 | ||
273 | if (ieee->scan_age == 0 || | 280 | if (ieee->scan_age == 0 || |
274 | time_after(network->last_scanned + ieee->scan_age, jiffies)) | 281 | time_after(network->last_scanned + ieee->scan_age, jiffies)) |
275 | ev = ieee80211_translate_scan(ieee, ev, stop, network); | 282 | ev = ieee80211_translate_scan(ieee, ev, stop, network, |
283 | info); | ||
276 | else | 284 | else |
277 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" | 285 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" |
278 | "%s)' due to age (%dms).\n", | 286 | "%s)' due to age (%dms).\n", |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 14fccf16b80f..80a9e7c07b47 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
26 | #include <net/wireless.h> | 26 | #include <net/wireless.h> |
27 | #include <net/iw_handler.h> | ||
27 | #include "key.h" | 28 | #include "key.h" |
28 | #include "sta_info.h" | 29 | #include "sta_info.h" |
29 | 30 | ||
@@ -867,7 +868,9 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid); | |||
867 | int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); | 868 | int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); |
868 | void ieee80211_sta_req_auth(struct net_device *dev, | 869 | void ieee80211_sta_req_auth(struct net_device *dev, |
869 | struct ieee80211_if_sta *ifsta); | 870 | struct ieee80211_if_sta *ifsta); |
870 | int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); | 871 | int ieee80211_sta_scan_results(struct net_device *dev, |
872 | struct iw_request_info *info, | ||
873 | char *buf, size_t len); | ||
871 | ieee80211_rx_result ieee80211_sta_rx_scan( | 874 | ieee80211_rx_result ieee80211_sta_rx_scan( |
872 | struct net_device *dev, struct sk_buff *skb, | 875 | struct net_device *dev, struct sk_buff *skb, |
873 | struct ieee80211_rx_status *rx_status); | 876 | struct ieee80211_rx_status *rx_status); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 55659a730dc1..e06d6450f215 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -4087,6 +4087,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len) | |||
4087 | 4087 | ||
4088 | static char * | 4088 | static char * |
4089 | ieee80211_sta_scan_result(struct net_device *dev, | 4089 | ieee80211_sta_scan_result(struct net_device *dev, |
4090 | struct iw_request_info *info, | ||
4090 | struct ieee80211_sta_bss *bss, | 4091 | struct ieee80211_sta_bss *bss, |
4091 | char *current_ev, char *end_buf) | 4092 | char *current_ev, char *end_buf) |
4092 | { | 4093 | { |
@@ -4101,7 +4102,7 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4101 | iwe.cmd = SIOCGIWAP; | 4102 | iwe.cmd = SIOCGIWAP; |
4102 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 4103 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
4103 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | 4104 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); |
4104 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4105 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4105 | IW_EV_ADDR_LEN); | 4106 | IW_EV_ADDR_LEN); |
4106 | 4107 | ||
4107 | memset(&iwe, 0, sizeof(iwe)); | 4108 | memset(&iwe, 0, sizeof(iwe)); |
@@ -4109,13 +4110,13 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4109 | if (bss_mesh_cfg(bss)) { | 4110 | if (bss_mesh_cfg(bss)) { |
4110 | iwe.u.data.length = bss_mesh_id_len(bss); | 4111 | iwe.u.data.length = bss_mesh_id_len(bss); |
4111 | iwe.u.data.flags = 1; | 4112 | iwe.u.data.flags = 1; |
4112 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4113 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4113 | bss_mesh_id(bss)); | 4114 | &iwe, bss_mesh_id(bss)); |
4114 | } else { | 4115 | } else { |
4115 | iwe.u.data.length = bss->ssid_len; | 4116 | iwe.u.data.length = bss->ssid_len; |
4116 | iwe.u.data.flags = 1; | 4117 | iwe.u.data.flags = 1; |
4117 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4118 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4118 | bss->ssid); | 4119 | &iwe, bss->ssid); |
4119 | } | 4120 | } |
4120 | 4121 | ||
4121 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) | 4122 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) |
@@ -4128,22 +4129,22 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4128 | iwe.u.mode = IW_MODE_MASTER; | 4129 | iwe.u.mode = IW_MODE_MASTER; |
4129 | else | 4130 | else |
4130 | iwe.u.mode = IW_MODE_ADHOC; | 4131 | iwe.u.mode = IW_MODE_ADHOC; |
4131 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4132 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, |
4132 | IW_EV_UINT_LEN); | 4133 | &iwe, IW_EV_UINT_LEN); |
4133 | } | 4134 | } |
4134 | 4135 | ||
4135 | memset(&iwe, 0, sizeof(iwe)); | 4136 | memset(&iwe, 0, sizeof(iwe)); |
4136 | iwe.cmd = SIOCGIWFREQ; | 4137 | iwe.cmd = SIOCGIWFREQ; |
4137 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); | 4138 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); |
4138 | iwe.u.freq.e = 0; | 4139 | iwe.u.freq.e = 0; |
4139 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4140 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4140 | IW_EV_FREQ_LEN); | 4141 | IW_EV_FREQ_LEN); |
4141 | 4142 | ||
4142 | memset(&iwe, 0, sizeof(iwe)); | 4143 | memset(&iwe, 0, sizeof(iwe)); |
4143 | iwe.cmd = SIOCGIWFREQ; | 4144 | iwe.cmd = SIOCGIWFREQ; |
4144 | iwe.u.freq.m = bss->freq; | 4145 | iwe.u.freq.m = bss->freq; |
4145 | iwe.u.freq.e = 6; | 4146 | iwe.u.freq.e = 6; |
4146 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4147 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4147 | IW_EV_FREQ_LEN); | 4148 | IW_EV_FREQ_LEN); |
4148 | memset(&iwe, 0, sizeof(iwe)); | 4149 | memset(&iwe, 0, sizeof(iwe)); |
4149 | iwe.cmd = IWEVQUAL; | 4150 | iwe.cmd = IWEVQUAL; |
@@ -4151,7 +4152,7 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4151 | iwe.u.qual.level = bss->signal; | 4152 | iwe.u.qual.level = bss->signal; |
4152 | iwe.u.qual.noise = bss->noise; | 4153 | iwe.u.qual.noise = bss->noise; |
4153 | iwe.u.qual.updated = local->wstats_flags; | 4154 | iwe.u.qual.updated = local->wstats_flags; |
4154 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4155 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4155 | IW_EV_QUAL_LEN); | 4156 | IW_EV_QUAL_LEN); |
4156 | 4157 | ||
4157 | memset(&iwe, 0, sizeof(iwe)); | 4158 | memset(&iwe, 0, sizeof(iwe)); |
@@ -4161,35 +4162,36 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4161 | else | 4162 | else |
4162 | iwe.u.data.flags = IW_ENCODE_DISABLED; | 4163 | iwe.u.data.flags = IW_ENCODE_DISABLED; |
4163 | iwe.u.data.length = 0; | 4164 | iwe.u.data.length = 0; |
4164 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); | 4165 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4166 | &iwe, ""); | ||
4165 | 4167 | ||
4166 | if (bss && bss->wpa_ie) { | 4168 | if (bss && bss->wpa_ie) { |
4167 | memset(&iwe, 0, sizeof(iwe)); | 4169 | memset(&iwe, 0, sizeof(iwe)); |
4168 | iwe.cmd = IWEVGENIE; | 4170 | iwe.cmd = IWEVGENIE; |
4169 | iwe.u.data.length = bss->wpa_ie_len; | 4171 | iwe.u.data.length = bss->wpa_ie_len; |
4170 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4172 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4171 | bss->wpa_ie); | 4173 | &iwe, bss->wpa_ie); |
4172 | } | 4174 | } |
4173 | 4175 | ||
4174 | if (bss && bss->rsn_ie) { | 4176 | if (bss && bss->rsn_ie) { |
4175 | memset(&iwe, 0, sizeof(iwe)); | 4177 | memset(&iwe, 0, sizeof(iwe)); |
4176 | iwe.cmd = IWEVGENIE; | 4178 | iwe.cmd = IWEVGENIE; |
4177 | iwe.u.data.length = bss->rsn_ie_len; | 4179 | iwe.u.data.length = bss->rsn_ie_len; |
4178 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4180 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4179 | bss->rsn_ie); | 4181 | &iwe, bss->rsn_ie); |
4180 | } | 4182 | } |
4181 | 4183 | ||
4182 | if (bss && bss->ht_ie) { | 4184 | if (bss && bss->ht_ie) { |
4183 | memset(&iwe, 0, sizeof(iwe)); | 4185 | memset(&iwe, 0, sizeof(iwe)); |
4184 | iwe.cmd = IWEVGENIE; | 4186 | iwe.cmd = IWEVGENIE; |
4185 | iwe.u.data.length = bss->ht_ie_len; | 4187 | iwe.u.data.length = bss->ht_ie_len; |
4186 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4188 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4187 | bss->ht_ie); | 4189 | &iwe, bss->ht_ie); |
4188 | } | 4190 | } |
4189 | 4191 | ||
4190 | if (bss && bss->supp_rates_len > 0) { | 4192 | if (bss && bss->supp_rates_len > 0) { |
4191 | /* display all supported rates in readable format */ | 4193 | /* display all supported rates in readable format */ |
4192 | char *p = current_ev + IW_EV_LCP_LEN; | 4194 | char *p = current_ev + iwe_stream_lcp_len(info); |
4193 | int i; | 4195 | int i; |
4194 | 4196 | ||
4195 | memset(&iwe, 0, sizeof(iwe)); | 4197 | memset(&iwe, 0, sizeof(iwe)); |
@@ -4200,7 +4202,7 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4200 | for (i = 0; i < bss->supp_rates_len; i++) { | 4202 | for (i = 0; i < bss->supp_rates_len; i++) { |
4201 | iwe.u.bitrate.value = ((bss->supp_rates[i] & | 4203 | iwe.u.bitrate.value = ((bss->supp_rates[i] & |
4202 | 0x7f) * 500000); | 4204 | 0x7f) * 500000); |
4203 | p = iwe_stream_add_value(current_ev, p, | 4205 | p = iwe_stream_add_value(info, current_ev, p, |
4204 | end_buf, &iwe, IW_EV_PARAM_LEN); | 4206 | end_buf, &iwe, IW_EV_PARAM_LEN); |
4205 | } | 4207 | } |
4206 | current_ev = p; | 4208 | current_ev = p; |
@@ -4214,7 +4216,8 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4214 | iwe.cmd = IWEVCUSTOM; | 4216 | iwe.cmd = IWEVCUSTOM; |
4215 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); | 4217 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); |
4216 | iwe.u.data.length = strlen(buf); | 4218 | iwe.u.data.length = strlen(buf); |
4217 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4219 | current_ev = iwe_stream_add_point(info, current_ev, |
4220 | end_buf, | ||
4218 | &iwe, buf); | 4221 | &iwe, buf); |
4219 | kfree(buf); | 4222 | kfree(buf); |
4220 | } | 4223 | } |
@@ -4229,31 +4232,36 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4229 | iwe.cmd = IWEVCUSTOM; | 4232 | iwe.cmd = IWEVCUSTOM; |
4230 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | 4233 | sprintf(buf, "Mesh network (version %d)", cfg[0]); |
4231 | iwe.u.data.length = strlen(buf); | 4234 | iwe.u.data.length = strlen(buf); |
4232 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4235 | current_ev = iwe_stream_add_point(info, current_ev, |
4236 | end_buf, | ||
4233 | &iwe, buf); | 4237 | &iwe, buf); |
4234 | sprintf(buf, "Path Selection Protocol ID: " | 4238 | sprintf(buf, "Path Selection Protocol ID: " |
4235 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | 4239 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], |
4236 | cfg[4]); | 4240 | cfg[4]); |
4237 | iwe.u.data.length = strlen(buf); | 4241 | iwe.u.data.length = strlen(buf); |
4238 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4242 | current_ev = iwe_stream_add_point(info, current_ev, |
4243 | end_buf, | ||
4239 | &iwe, buf); | 4244 | &iwe, buf); |
4240 | sprintf(buf, "Path Selection Metric ID: " | 4245 | sprintf(buf, "Path Selection Metric ID: " |
4241 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | 4246 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], |
4242 | cfg[8]); | 4247 | cfg[8]); |
4243 | iwe.u.data.length = strlen(buf); | 4248 | iwe.u.data.length = strlen(buf); |
4244 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4249 | current_ev = iwe_stream_add_point(info, current_ev, |
4250 | end_buf, | ||
4245 | &iwe, buf); | 4251 | &iwe, buf); |
4246 | sprintf(buf, "Congestion Control Mode ID: " | 4252 | sprintf(buf, "Congestion Control Mode ID: " |
4247 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | 4253 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], |
4248 | cfg[11], cfg[12]); | 4254 | cfg[11], cfg[12]); |
4249 | iwe.u.data.length = strlen(buf); | 4255 | iwe.u.data.length = strlen(buf); |
4250 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4256 | current_ev = iwe_stream_add_point(info, current_ev, |
4257 | end_buf, | ||
4251 | &iwe, buf); | 4258 | &iwe, buf); |
4252 | sprintf(buf, "Channel Precedence: " | 4259 | sprintf(buf, "Channel Precedence: " |
4253 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | 4260 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], |
4254 | cfg[15], cfg[16]); | 4261 | cfg[15], cfg[16]); |
4255 | iwe.u.data.length = strlen(buf); | 4262 | iwe.u.data.length = strlen(buf); |
4256 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4263 | current_ev = iwe_stream_add_point(info, current_ev, |
4264 | end_buf, | ||
4257 | &iwe, buf); | 4265 | &iwe, buf); |
4258 | kfree(buf); | 4266 | kfree(buf); |
4259 | } | 4267 | } |
@@ -4263,7 +4271,9 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4263 | } | 4271 | } |
4264 | 4272 | ||
4265 | 4273 | ||
4266 | int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) | 4274 | int ieee80211_sta_scan_results(struct net_device *dev, |
4275 | struct iw_request_info *info, | ||
4276 | char *buf, size_t len) | ||
4267 | { | 4277 | { |
4268 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 4278 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
4269 | char *current_ev = buf; | 4279 | char *current_ev = buf; |
@@ -4276,8 +4286,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) | |||
4276 | spin_unlock_bh(&local->sta_bss_lock); | 4286 | spin_unlock_bh(&local->sta_bss_lock); |
4277 | return -E2BIG; | 4287 | return -E2BIG; |
4278 | } | 4288 | } |
4279 | current_ev = ieee80211_sta_scan_result(dev, bss, current_ev, | 4289 | current_ev = ieee80211_sta_scan_result(dev, info, bss, |
4280 | end_buf); | 4290 | current_ev, end_buf); |
4281 | } | 4291 | } |
4282 | spin_unlock_bh(&local->sta_bss_lock); | 4292 | spin_unlock_bh(&local->sta_bss_lock); |
4283 | return current_ev - buf; | 4293 | return current_ev - buf; |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 5af3862e7191..f47d13bdf7f7 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -567,7 +567,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev, | |||
567 | if (local->sta_sw_scanning || local->sta_hw_scanning) | 567 | if (local->sta_sw_scanning || local->sta_hw_scanning) |
568 | return -EAGAIN; | 568 | return -EAGAIN; |
569 | 569 | ||
570 | res = ieee80211_sta_scan_results(dev, extra, data->length); | 570 | res = ieee80211_sta_scan_results(dev, info, extra, data->length); |
571 | if (res >= 0) { | 571 | if (res >= 0) { |
572 | data->length = res; | 572 | data->length = res; |
573 | return 0; | 573 | return 0; |
diff --git a/net/socket.c b/net/socket.c index 66c4a8cf6db9..81fe82513046 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -90,6 +90,7 @@ | |||
90 | #include <asm/unistd.h> | 90 | #include <asm/unistd.h> |
91 | 91 | ||
92 | #include <net/compat.h> | 92 | #include <net/compat.h> |
93 | #include <net/wext.h> | ||
93 | 94 | ||
94 | #include <net/sock.h> | 95 | #include <net/sock.h> |
95 | #include <linux/netfilter.h> | 96 | #include <linux/netfilter.h> |
@@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd, | |||
2210 | { | 2211 | { |
2211 | struct socket *sock = file->private_data; | 2212 | struct socket *sock = file->private_data; |
2212 | int ret = -ENOIOCTLCMD; | 2213 | int ret = -ENOIOCTLCMD; |
2214 | struct sock *sk; | ||
2215 | struct net *net; | ||
2216 | |||
2217 | sk = sock->sk; | ||
2218 | net = sock_net(sk); | ||
2213 | 2219 | ||
2214 | if (sock->ops->compat_ioctl) | 2220 | if (sock->ops->compat_ioctl) |
2215 | ret = sock->ops->compat_ioctl(sock, cmd, arg); | 2221 | ret = sock->ops->compat_ioctl(sock, cmd, arg); |
2216 | 2222 | ||
2223 | if (ret == -ENOIOCTLCMD && | ||
2224 | (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) | ||
2225 | ret = compat_wext_handle_ioctl(net, cmd, arg); | ||
2226 | |||
2217 | return ret; | 2227 | return ret; |
2218 | } | 2228 | } |
2219 | #endif | 2229 | #endif |
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 947188a5b937..273a84359998 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev) | |||
500 | /* | 500 | /* |
501 | * Calculate size of private arguments | 501 | * Calculate size of private arguments |
502 | */ | 502 | */ |
503 | static inline int get_priv_size(__u16 args) | 503 | static int get_priv_size(__u16 args) |
504 | { | 504 | { |
505 | int num = args & IW_PRIV_SIZE_MASK; | 505 | int num = args & IW_PRIV_SIZE_MASK; |
506 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; | 506 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; |
@@ -512,10 +512,9 @@ static inline int get_priv_size(__u16 args) | |||
512 | /* | 512 | /* |
513 | * Re-calculate the size of private arguments | 513 | * Re-calculate the size of private arguments |
514 | */ | 514 | */ |
515 | static inline int adjust_priv_size(__u16 args, | 515 | static int adjust_priv_size(__u16 args, struct iw_point *iwp) |
516 | union iwreq_data * wrqu) | ||
517 | { | 516 | { |
518 | int num = wrqu->data.length; | 517 | int num = iwp->length; |
519 | int max = args & IW_PRIV_SIZE_MASK; | 518 | int max = args & IW_PRIV_SIZE_MASK; |
520 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; | 519 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; |
521 | 520 | ||
@@ -695,19 +694,150 @@ void wext_proc_exit(struct net *net) | |||
695 | */ | 694 | */ |
696 | 695 | ||
697 | /* ---------------------------------------------------------------- */ | 696 | /* ---------------------------------------------------------------- */ |
697 | static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, | ||
698 | const struct iw_ioctl_description *descr, | ||
699 | iw_handler handler, struct net_device *dev, | ||
700 | struct iw_request_info *info) | ||
701 | { | ||
702 | int err, extra_size, user_length = 0, essid_compat = 0; | ||
703 | char *extra; | ||
704 | |||
705 | /* Calculate space needed by arguments. Always allocate | ||
706 | * for max space. | ||
707 | */ | ||
708 | extra_size = descr->max_tokens * descr->token_size; | ||
709 | |||
710 | /* Check need for ESSID compatibility for WE < 21 */ | ||
711 | switch (cmd) { | ||
712 | case SIOCSIWESSID: | ||
713 | case SIOCGIWESSID: | ||
714 | case SIOCSIWNICKN: | ||
715 | case SIOCGIWNICKN: | ||
716 | if (iwp->length == descr->max_tokens + 1) | ||
717 | essid_compat = 1; | ||
718 | else if (IW_IS_SET(cmd) && (iwp->length != 0)) { | ||
719 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
720 | |||
721 | err = copy_from_user(essid, iwp->pointer, | ||
722 | iwp->length * | ||
723 | descr->token_size); | ||
724 | if (err) | ||
725 | return -EFAULT; | ||
726 | |||
727 | if (essid[iwp->length - 1] == '\0') | ||
728 | essid_compat = 1; | ||
729 | } | ||
730 | break; | ||
731 | default: | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | iwp->length -= essid_compat; | ||
736 | |||
737 | /* Check what user space is giving us */ | ||
738 | if (IW_IS_SET(cmd)) { | ||
739 | /* Check NULL pointer */ | ||
740 | if (!iwp->pointer && iwp->length != 0) | ||
741 | return -EFAULT; | ||
742 | /* Check if number of token fits within bounds */ | ||
743 | if (iwp->length > descr->max_tokens) | ||
744 | return -E2BIG; | ||
745 | if (iwp->length < descr->min_tokens) | ||
746 | return -EINVAL; | ||
747 | } else { | ||
748 | /* Check NULL pointer */ | ||
749 | if (!iwp->pointer) | ||
750 | return -EFAULT; | ||
751 | /* Save user space buffer size for checking */ | ||
752 | user_length = iwp->length; | ||
753 | |||
754 | /* Don't check if user_length > max to allow forward | ||
755 | * compatibility. The test user_length < min is | ||
756 | * implied by the test at the end. | ||
757 | */ | ||
758 | |||
759 | /* Support for very large requests */ | ||
760 | if ((descr->flags & IW_DESCR_FLAG_NOMAX) && | ||
761 | (user_length > descr->max_tokens)) { | ||
762 | /* Allow userspace to GET more than max so | ||
763 | * we can support any size GET requests. | ||
764 | * There is still a limit : -ENOMEM. | ||
765 | */ | ||
766 | extra_size = user_length * descr->token_size; | ||
767 | |||
768 | /* Note : user_length is originally a __u16, | ||
769 | * and token_size is controlled by us, | ||
770 | * so extra_size won't get negative and | ||
771 | * won't overflow... | ||
772 | */ | ||
773 | } | ||
774 | } | ||
775 | |||
776 | /* kzalloc() ensures NULL-termination for essid_compat. */ | ||
777 | extra = kzalloc(extra_size, GFP_KERNEL); | ||
778 | if (!extra) | ||
779 | return -ENOMEM; | ||
780 | |||
781 | /* If it is a SET, get all the extra data in here */ | ||
782 | if (IW_IS_SET(cmd) && (iwp->length != 0)) { | ||
783 | if (copy_from_user(extra, iwp->pointer, | ||
784 | iwp->length * | ||
785 | descr->token_size)) { | ||
786 | err = -EFAULT; | ||
787 | goto out; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | err = handler(dev, info, (union iwreq_data *) iwp, extra); | ||
792 | |||
793 | iwp->length += essid_compat; | ||
794 | |||
795 | /* If we have something to return to the user */ | ||
796 | if (!err && IW_IS_GET(cmd)) { | ||
797 | /* Check if there is enough buffer up there */ | ||
798 | if (user_length < iwp->length) { | ||
799 | err = -E2BIG; | ||
800 | goto out; | ||
801 | } | ||
802 | |||
803 | if (copy_to_user(iwp->pointer, extra, | ||
804 | iwp->length * | ||
805 | descr->token_size)) { | ||
806 | err = -EFAULT; | ||
807 | goto out; | ||
808 | } | ||
809 | } | ||
810 | |||
811 | /* Generate an event to notify listeners of the change */ | ||
812 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { | ||
813 | union iwreq_data *data = (union iwreq_data *) iwp; | ||
814 | |||
815 | if (descr->flags & IW_DESCR_FLAG_RESTRICT) | ||
816 | /* If the event is restricted, don't | ||
817 | * export the payload. | ||
818 | */ | ||
819 | wireless_send_event(dev, cmd, data, NULL); | ||
820 | else | ||
821 | wireless_send_event(dev, cmd, data, extra); | ||
822 | } | ||
823 | |||
824 | out: | ||
825 | kfree(extra); | ||
826 | return err; | ||
827 | } | ||
828 | |||
698 | /* | 829 | /* |
699 | * Wrapper to call a standard Wireless Extension handler. | 830 | * Wrapper to call a standard Wireless Extension handler. |
700 | * We do various checks and also take care of moving data between | 831 | * We do various checks and also take care of moving data between |
701 | * user space and kernel space. | 832 | * user space and kernel space. |
702 | */ | 833 | */ |
703 | static int ioctl_standard_call(struct net_device * dev, | 834 | static int ioctl_standard_call(struct net_device * dev, |
704 | struct ifreq * ifr, | 835 | struct iwreq *iwr, |
705 | unsigned int cmd, | 836 | unsigned int cmd, |
837 | struct iw_request_info *info, | ||
706 | iw_handler handler) | 838 | iw_handler handler) |
707 | { | 839 | { |
708 | struct iwreq * iwr = (struct iwreq *) ifr; | ||
709 | const struct iw_ioctl_description * descr; | 840 | const struct iw_ioctl_description * descr; |
710 | struct iw_request_info info; | ||
711 | int ret = -EINVAL; | 841 | int ret = -EINVAL; |
712 | 842 | ||
713 | /* Get the description of the IOCTL */ | 843 | /* Get the description of the IOCTL */ |
@@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device * dev, | |||
715 | return -EOPNOTSUPP; | 845 | return -EOPNOTSUPP; |
716 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | 846 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); |
717 | 847 | ||
718 | /* Prepare the call */ | ||
719 | info.cmd = cmd; | ||
720 | info.flags = 0; | ||
721 | |||
722 | /* Check if we have a pointer to user space data or not */ | 848 | /* Check if we have a pointer to user space data or not */ |
723 | if (descr->header_type != IW_HEADER_TYPE_POINT) { | 849 | if (descr->header_type != IW_HEADER_TYPE_POINT) { |
724 | 850 | ||
725 | /* No extra arguments. Trivial to handle */ | 851 | /* No extra arguments. Trivial to handle */ |
726 | ret = handler(dev, &info, &(iwr->u), NULL); | 852 | ret = handler(dev, info, &(iwr->u), NULL); |
727 | 853 | ||
728 | /* Generate an event to notify listeners of the change */ | 854 | /* Generate an event to notify listeners of the change */ |
729 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && | 855 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && |
730 | ((ret == 0) || (ret == -EIWCOMMIT))) | 856 | ((ret == 0) || (ret == -EIWCOMMIT))) |
731 | wireless_send_event(dev, cmd, &(iwr->u), NULL); | 857 | wireless_send_event(dev, cmd, &(iwr->u), NULL); |
732 | } else { | 858 | } else { |
733 | char * extra; | 859 | ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, |
734 | int extra_size; | 860 | handler, dev, info); |
735 | int user_length = 0; | ||
736 | int err; | ||
737 | int essid_compat = 0; | ||
738 | |||
739 | /* Calculate space needed by arguments. Always allocate | ||
740 | * for max space. Easier, and won't last long... */ | ||
741 | extra_size = descr->max_tokens * descr->token_size; | ||
742 | |||
743 | /* Check need for ESSID compatibility for WE < 21 */ | ||
744 | switch (cmd) { | ||
745 | case SIOCSIWESSID: | ||
746 | case SIOCGIWESSID: | ||
747 | case SIOCSIWNICKN: | ||
748 | case SIOCGIWNICKN: | ||
749 | if (iwr->u.data.length == descr->max_tokens + 1) | ||
750 | essid_compat = 1; | ||
751 | else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { | ||
752 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
753 | |||
754 | err = copy_from_user(essid, iwr->u.data.pointer, | ||
755 | iwr->u.data.length * | ||
756 | descr->token_size); | ||
757 | if (err) | ||
758 | return -EFAULT; | ||
759 | |||
760 | if (essid[iwr->u.data.length - 1] == '\0') | ||
761 | essid_compat = 1; | ||
762 | } | ||
763 | break; | ||
764 | default: | ||
765 | break; | ||
766 | } | ||
767 | |||
768 | iwr->u.data.length -= essid_compat; | ||
769 | |||
770 | /* Check what user space is giving us */ | ||
771 | if (IW_IS_SET(cmd)) { | ||
772 | /* Check NULL pointer */ | ||
773 | if ((iwr->u.data.pointer == NULL) && | ||
774 | (iwr->u.data.length != 0)) | ||
775 | return -EFAULT; | ||
776 | /* Check if number of token fits within bounds */ | ||
777 | if (iwr->u.data.length > descr->max_tokens) | ||
778 | return -E2BIG; | ||
779 | if (iwr->u.data.length < descr->min_tokens) | ||
780 | return -EINVAL; | ||
781 | } else { | ||
782 | /* Check NULL pointer */ | ||
783 | if (iwr->u.data.pointer == NULL) | ||
784 | return -EFAULT; | ||
785 | /* Save user space buffer size for checking */ | ||
786 | user_length = iwr->u.data.length; | ||
787 | |||
788 | /* Don't check if user_length > max to allow forward | ||
789 | * compatibility. The test user_length < min is | ||
790 | * implied by the test at the end. */ | ||
791 | |||
792 | /* Support for very large requests */ | ||
793 | if ((descr->flags & IW_DESCR_FLAG_NOMAX) && | ||
794 | (user_length > descr->max_tokens)) { | ||
795 | /* Allow userspace to GET more than max so | ||
796 | * we can support any size GET requests. | ||
797 | * There is still a limit : -ENOMEM. */ | ||
798 | extra_size = user_length * descr->token_size; | ||
799 | /* Note : user_length is originally a __u16, | ||
800 | * and token_size is controlled by us, | ||
801 | * so extra_size won't get negative and | ||
802 | * won't overflow... */ | ||
803 | } | ||
804 | } | ||
805 | |||
806 | /* Create the kernel buffer */ | ||
807 | /* kzalloc ensures NULL-termination for essid_compat */ | ||
808 | extra = kzalloc(extra_size, GFP_KERNEL); | ||
809 | if (extra == NULL) | ||
810 | return -ENOMEM; | ||
811 | |||
812 | /* If it is a SET, get all the extra data in here */ | ||
813 | if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { | ||
814 | err = copy_from_user(extra, iwr->u.data.pointer, | ||
815 | iwr->u.data.length * | ||
816 | descr->token_size); | ||
817 | if (err) { | ||
818 | kfree(extra); | ||
819 | return -EFAULT; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | /* Call the handler */ | ||
824 | ret = handler(dev, &info, &(iwr->u), extra); | ||
825 | |||
826 | iwr->u.data.length += essid_compat; | ||
827 | |||
828 | /* If we have something to return to the user */ | ||
829 | if (!ret && IW_IS_GET(cmd)) { | ||
830 | /* Check if there is enough buffer up there */ | ||
831 | if (user_length < iwr->u.data.length) { | ||
832 | kfree(extra); | ||
833 | return -E2BIG; | ||
834 | } | ||
835 | |||
836 | err = copy_to_user(iwr->u.data.pointer, extra, | ||
837 | iwr->u.data.length * | ||
838 | descr->token_size); | ||
839 | if (err) | ||
840 | ret = -EFAULT; | ||
841 | } | ||
842 | |||
843 | /* Generate an event to notify listeners of the change */ | ||
844 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && | ||
845 | ((ret == 0) || (ret == -EIWCOMMIT))) { | ||
846 | if (descr->flags & IW_DESCR_FLAG_RESTRICT) | ||
847 | /* If the event is restricted, don't | ||
848 | * export the payload */ | ||
849 | wireless_send_event(dev, cmd, &(iwr->u), NULL); | ||
850 | else | ||
851 | wireless_send_event(dev, cmd, &(iwr->u), | ||
852 | extra); | ||
853 | } | ||
854 | |||
855 | /* Cleanup - I told you it wasn't that long ;-) */ | ||
856 | kfree(extra); | ||
857 | } | 861 | } |
858 | 862 | ||
859 | /* Call commit handler if needed and defined */ | 863 | /* Call commit handler if needed and defined */ |
@@ -881,25 +885,22 @@ static int ioctl_standard_call(struct net_device * dev, | |||
881 | * a iw_handler but process it in your ioctl handler (i.e. use the | 885 | * a iw_handler but process it in your ioctl handler (i.e. use the |
882 | * old driver API). | 886 | * old driver API). |
883 | */ | 887 | */ |
884 | static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, | 888 | static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, |
885 | unsigned int cmd, iw_handler handler) | 889 | const struct iw_priv_args **descrp) |
886 | { | 890 | { |
887 | struct iwreq * iwr = (struct iwreq *) ifr; | 891 | const struct iw_priv_args *descr; |
888 | const struct iw_priv_args * descr = NULL; | 892 | int i, extra_size; |
889 | struct iw_request_info info; | ||
890 | int extra_size = 0; | ||
891 | int i; | ||
892 | int ret = -EINVAL; | ||
893 | 893 | ||
894 | /* Get the description of the IOCTL */ | 894 | descr = NULL; |
895 | for (i = 0; i < dev->wireless_handlers->num_private_args; i++) | 895 | for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { |
896 | if (cmd == dev->wireless_handlers->private_args[i].cmd) { | 896 | if (cmd == dev->wireless_handlers->private_args[i].cmd) { |
897 | descr = &(dev->wireless_handlers->private_args[i]); | 897 | descr = &dev->wireless_handlers->private_args[i]; |
898 | break; | 898 | break; |
899 | } | 899 | } |
900 | } | ||
900 | 901 | ||
901 | /* Compute the size of the set/get arguments */ | 902 | extra_size = 0; |
902 | if (descr != NULL) { | 903 | if (descr) { |
903 | if (IW_IS_SET(cmd)) { | 904 | if (IW_IS_SET(cmd)) { |
904 | int offset = 0; /* For sub-ioctls */ | 905 | int offset = 0; /* For sub-ioctls */ |
905 | /* Check for sub-ioctl handler */ | 906 | /* Check for sub-ioctl handler */ |
@@ -924,72 +925,77 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, | |||
924 | extra_size = 0; | 925 | extra_size = 0; |
925 | } | 926 | } |
926 | } | 927 | } |
928 | *descrp = descr; | ||
929 | return extra_size; | ||
930 | } | ||
927 | 931 | ||
928 | /* Prepare the call */ | 932 | static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, |
929 | info.cmd = cmd; | 933 | const struct iw_priv_args *descr, |
930 | info.flags = 0; | 934 | iw_handler handler, struct net_device *dev, |
935 | struct iw_request_info *info, int extra_size) | ||
936 | { | ||
937 | char *extra; | ||
938 | int err; | ||
931 | 939 | ||
932 | /* Check if we have a pointer to user space data or not. */ | 940 | /* Check what user space is giving us */ |
933 | if (extra_size == 0) { | 941 | if (IW_IS_SET(cmd)) { |
934 | /* No extra arguments. Trivial to handle */ | 942 | if (!iwp->pointer && iwp->length != 0) |
935 | ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); | 943 | return -EFAULT; |
936 | } else { | ||
937 | char * extra; | ||
938 | int err; | ||
939 | 944 | ||
940 | /* Check what user space is giving us */ | 945 | if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) |
941 | if (IW_IS_SET(cmd)) { | 946 | return -E2BIG; |
942 | /* Check NULL pointer */ | 947 | } else if (!iwp->pointer) |
943 | if ((iwr->u.data.pointer == NULL) && | 948 | return -EFAULT; |
944 | (iwr->u.data.length != 0)) | ||
945 | return -EFAULT; | ||
946 | 949 | ||
947 | /* Does it fits within bounds ? */ | 950 | extra = kmalloc(extra_size, GFP_KERNEL); |
948 | if (iwr->u.data.length > (descr->set_args & | 951 | if (!extra) |
949 | IW_PRIV_SIZE_MASK)) | 952 | return -ENOMEM; |
950 | return -E2BIG; | ||
951 | } else if (iwr->u.data.pointer == NULL) | ||
952 | return -EFAULT; | ||
953 | 953 | ||
954 | /* Always allocate for max space. Easier, and won't last | 954 | /* If it is a SET, get all the extra data in here */ |
955 | * long... */ | 955 | if (IW_IS_SET(cmd) && (iwp->length != 0)) { |
956 | extra = kmalloc(extra_size, GFP_KERNEL); | 956 | if (copy_from_user(extra, iwp->pointer, extra_size)) { |
957 | if (extra == NULL) | 957 | err = -EFAULT; |
958 | return -ENOMEM; | 958 | goto out; |
959 | |||
960 | /* If it is a SET, get all the extra data in here */ | ||
961 | if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { | ||
962 | err = copy_from_user(extra, iwr->u.data.pointer, | ||
963 | extra_size); | ||
964 | if (err) { | ||
965 | kfree(extra); | ||
966 | return -EFAULT; | ||
967 | } | ||
968 | } | 959 | } |
960 | } | ||
969 | 961 | ||
970 | /* Call the handler */ | 962 | /* Call the handler */ |
971 | ret = handler(dev, &info, &(iwr->u), extra); | 963 | err = handler(dev, info, (union iwreq_data *) iwp, extra); |
972 | 964 | ||
973 | /* If we have something to return to the user */ | 965 | /* If we have something to return to the user */ |
974 | if (!ret && IW_IS_GET(cmd)) { | 966 | if (!err && IW_IS_GET(cmd)) { |
967 | /* Adjust for the actual length if it's variable, | ||
968 | * avoid leaking kernel bits outside. | ||
969 | */ | ||
970 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) | ||
971 | extra_size = adjust_priv_size(descr->get_args, iwp); | ||
975 | 972 | ||
976 | /* Adjust for the actual length if it's variable, | 973 | if (copy_to_user(iwp->pointer, extra, extra_size)) |
977 | * avoid leaking kernel bits outside. */ | 974 | err = -EFAULT; |
978 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { | 975 | } |
979 | extra_size = adjust_priv_size(descr->get_args, | ||
980 | &(iwr->u)); | ||
981 | } | ||
982 | 976 | ||
983 | err = copy_to_user(iwr->u.data.pointer, extra, | 977 | out: |
984 | extra_size); | 978 | kfree(extra); |
985 | if (err) | 979 | return err; |
986 | ret = -EFAULT; | 980 | } |
987 | } | ||
988 | 981 | ||
989 | /* Cleanup - I told you it wasn't that long ;-) */ | 982 | static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, |
990 | kfree(extra); | 983 | unsigned int cmd, struct iw_request_info *info, |
991 | } | 984 | iw_handler handler) |
985 | { | ||
986 | int extra_size = 0, ret = -EINVAL; | ||
987 | const struct iw_priv_args *descr; | ||
992 | 988 | ||
989 | extra_size = get_priv_descr_and_size(dev, cmd, &descr); | ||
990 | |||
991 | /* Check if we have a pointer to user space data or not. */ | ||
992 | if (extra_size == 0) { | ||
993 | /* No extra arguments. Trivial to handle */ | ||
994 | ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); | ||
995 | } else { | ||
996 | ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, | ||
997 | handler, dev, info, extra_size); | ||
998 | } | ||
993 | 999 | ||
994 | /* Call commit handler if needed and defined */ | 1000 | /* Call commit handler if needed and defined */ |
995 | if (ret == -EIWCOMMIT) | 1001 | if (ret == -EIWCOMMIT) |
@@ -999,12 +1005,21 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, | |||
999 | } | 1005 | } |
1000 | 1006 | ||
1001 | /* ---------------------------------------------------------------- */ | 1007 | /* ---------------------------------------------------------------- */ |
1008 | typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, | ||
1009 | unsigned int, struct iw_request_info *, | ||
1010 | iw_handler); | ||
1011 | |||
1002 | /* | 1012 | /* |
1003 | * Main IOCTl dispatcher. | 1013 | * Main IOCTl dispatcher. |
1004 | * Check the type of IOCTL and call the appropriate wrapper... | 1014 | * Check the type of IOCTL and call the appropriate wrapper... |
1005 | */ | 1015 | */ |
1006 | static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) | 1016 | static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, |
1017 | unsigned int cmd, | ||
1018 | struct iw_request_info *info, | ||
1019 | wext_ioctl_func standard, | ||
1020 | wext_ioctl_func private) | ||
1007 | { | 1021 | { |
1022 | struct iwreq *iwr = (struct iwreq *) ifr; | ||
1008 | struct net_device *dev; | 1023 | struct net_device *dev; |
1009 | iw_handler handler; | 1024 | iw_handler handler; |
1010 | 1025 | ||
@@ -1019,12 +1034,12 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i | |||
1019 | * Note that 'cmd' is already filtered in dev_ioctl() with | 1034 | * Note that 'cmd' is already filtered in dev_ioctl() with |
1020 | * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ | 1035 | * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ |
1021 | if (cmd == SIOCGIWSTATS) | 1036 | if (cmd == SIOCGIWSTATS) |
1022 | return ioctl_standard_call(dev, ifr, cmd, | 1037 | return standard(dev, iwr, cmd, info, |
1023 | &iw_handler_get_iwstats); | 1038 | &iw_handler_get_iwstats); |
1024 | 1039 | ||
1025 | if (cmd == SIOCGIWPRIV && dev->wireless_handlers) | 1040 | if (cmd == SIOCGIWPRIV && dev->wireless_handlers) |
1026 | return ioctl_standard_call(dev, ifr, cmd, | 1041 | return standard(dev, iwr, cmd, info, |
1027 | &iw_handler_get_private); | 1042 | &iw_handler_get_private); |
1028 | 1043 | ||
1029 | /* Basic check */ | 1044 | /* Basic check */ |
1030 | if (!netif_device_present(dev)) | 1045 | if (!netif_device_present(dev)) |
@@ -1035,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i | |||
1035 | if (handler) { | 1050 | if (handler) { |
1036 | /* Standard and private are not the same */ | 1051 | /* Standard and private are not the same */ |
1037 | if (cmd < SIOCIWFIRSTPRIV) | 1052 | if (cmd < SIOCIWFIRSTPRIV) |
1038 | return ioctl_standard_call(dev, ifr, cmd, handler); | 1053 | return standard(dev, iwr, cmd, info, handler); |
1039 | else | 1054 | else |
1040 | return ioctl_private_call(dev, ifr, cmd, handler); | 1055 | return private(dev, iwr, cmd, info, handler); |
1041 | } | 1056 | } |
1042 | /* Old driver API : call driver ioctl handler */ | 1057 | /* Old driver API : call driver ioctl handler */ |
1043 | if (dev->do_ioctl) | 1058 | if (dev->do_ioctl) |
@@ -1045,27 +1060,154 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i | |||
1045 | return -EOPNOTSUPP; | 1060 | return -EOPNOTSUPP; |
1046 | } | 1061 | } |
1047 | 1062 | ||
1048 | /* entry point from dev ioctl */ | 1063 | /* If command is `set a parameter', or `get the encoding parameters', |
1049 | int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, | 1064 | * check if the user has the right to do it. |
1050 | void __user *arg) | 1065 | */ |
1066 | static int wext_permission_check(unsigned int cmd) | ||
1051 | { | 1067 | { |
1052 | int ret; | ||
1053 | |||
1054 | /* If command is `set a parameter', or | ||
1055 | * `get the encoding parameters', check if | ||
1056 | * the user has the right to do it */ | ||
1057 | if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) | 1068 | if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) |
1058 | && !capable(CAP_NET_ADMIN)) | 1069 | && !capable(CAP_NET_ADMIN)) |
1059 | return -EPERM; | 1070 | return -EPERM; |
1060 | 1071 | ||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | /* entry point from dev ioctl */ | ||
1076 | static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, | ||
1077 | unsigned int cmd, struct iw_request_info *info, | ||
1078 | wext_ioctl_func standard, | ||
1079 | wext_ioctl_func private) | ||
1080 | { | ||
1081 | int ret = wext_permission_check(cmd); | ||
1082 | |||
1083 | if (ret) | ||
1084 | return ret; | ||
1085 | |||
1061 | dev_load(net, ifr->ifr_name); | 1086 | dev_load(net, ifr->ifr_name); |
1062 | rtnl_lock(); | 1087 | rtnl_lock(); |
1063 | ret = wireless_process_ioctl(net, ifr, cmd); | 1088 | ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); |
1064 | rtnl_unlock(); | 1089 | rtnl_unlock(); |
1065 | if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq))) | 1090 | |
1091 | return ret; | ||
1092 | } | ||
1093 | |||
1094 | int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, | ||
1095 | void __user *arg) | ||
1096 | { | ||
1097 | struct iw_request_info info = { .cmd = cmd, .flags = 0 }; | ||
1098 | int ret; | ||
1099 | |||
1100 | ret = wext_ioctl_dispatch(net, ifr, cmd, &info, | ||
1101 | ioctl_standard_call, | ||
1102 | ioctl_private_call); | ||
1103 | if (ret >= 0 && | ||
1104 | IW_IS_GET(cmd) && | ||
1105 | copy_to_user(arg, ifr, sizeof(struct iwreq))) | ||
1106 | return -EFAULT; | ||
1107 | |||
1108 | return ret; | ||
1109 | } | ||
1110 | |||
1111 | #ifdef CONFIG_COMPAT | ||
1112 | static int compat_standard_call(struct net_device *dev, | ||
1113 | struct iwreq *iwr, | ||
1114 | unsigned int cmd, | ||
1115 | struct iw_request_info *info, | ||
1116 | iw_handler handler) | ||
1117 | { | ||
1118 | const struct iw_ioctl_description *descr; | ||
1119 | struct compat_iw_point *iwp_compat; | ||
1120 | struct iw_point iwp; | ||
1121 | int err; | ||
1122 | |||
1123 | descr = standard_ioctl + (cmd - SIOCIWFIRST); | ||
1124 | |||
1125 | if (descr->header_type != IW_HEADER_TYPE_POINT) | ||
1126 | return ioctl_standard_call(dev, iwr, cmd, info, handler); | ||
1127 | |||
1128 | iwp_compat = (struct compat_iw_point *) &iwr->u.data; | ||
1129 | iwp.pointer = compat_ptr(iwp_compat->pointer); | ||
1130 | iwp.length = iwp_compat->length; | ||
1131 | iwp.flags = iwp_compat->flags; | ||
1132 | |||
1133 | err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); | ||
1134 | |||
1135 | iwp_compat->pointer = ptr_to_compat(iwp.pointer); | ||
1136 | iwp_compat->length = iwp.length; | ||
1137 | iwp_compat->flags = iwp.flags; | ||
1138 | |||
1139 | return err; | ||
1140 | } | ||
1141 | |||
1142 | static int compat_private_call(struct net_device *dev, struct iwreq *iwr, | ||
1143 | unsigned int cmd, struct iw_request_info *info, | ||
1144 | iw_handler handler) | ||
1145 | { | ||
1146 | const struct iw_priv_args *descr; | ||
1147 | int ret, extra_size; | ||
1148 | |||
1149 | extra_size = get_priv_descr_and_size(dev, cmd, &descr); | ||
1150 | |||
1151 | /* Check if we have a pointer to user space data or not. */ | ||
1152 | if (extra_size == 0) { | ||
1153 | /* No extra arguments. Trivial to handle */ | ||
1154 | ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); | ||
1155 | } else { | ||
1156 | struct compat_iw_point *iwp_compat; | ||
1157 | struct iw_point iwp; | ||
1158 | |||
1159 | iwp_compat = (struct compat_iw_point *) &iwr->u.data; | ||
1160 | iwp.pointer = compat_ptr(iwp_compat->pointer); | ||
1161 | iwp.length = iwp_compat->length; | ||
1162 | iwp.flags = iwp_compat->flags; | ||
1163 | |||
1164 | ret = ioctl_private_iw_point(&iwp, cmd, descr, | ||
1165 | handler, dev, info, extra_size); | ||
1166 | |||
1167 | iwp_compat->pointer = ptr_to_compat(iwp.pointer); | ||
1168 | iwp_compat->length = iwp.length; | ||
1169 | iwp_compat->flags = iwp.flags; | ||
1170 | } | ||
1171 | |||
1172 | /* Call commit handler if needed and defined */ | ||
1173 | if (ret == -EIWCOMMIT) | ||
1174 | ret = call_commit_handler(dev); | ||
1175 | |||
1176 | return ret; | ||
1177 | } | ||
1178 | |||
1179 | int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, | ||
1180 | unsigned long arg) | ||
1181 | { | ||
1182 | void __user *argp = (void __user *)arg; | ||
1183 | struct iw_request_info info; | ||
1184 | struct iwreq iwr; | ||
1185 | char *colon; | ||
1186 | int ret; | ||
1187 | |||
1188 | if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) | ||
1189 | return -EFAULT; | ||
1190 | |||
1191 | iwr.ifr_name[IFNAMSIZ-1] = 0; | ||
1192 | colon = strchr(iwr.ifr_name, ':'); | ||
1193 | if (colon) | ||
1194 | *colon = 0; | ||
1195 | |||
1196 | info.cmd = cmd; | ||
1197 | info.flags = IW_REQUEST_FLAG_COMPAT; | ||
1198 | |||
1199 | ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, | ||
1200 | compat_standard_call, | ||
1201 | compat_private_call); | ||
1202 | |||
1203 | if (ret >= 0 && | ||
1204 | IW_IS_GET(cmd) && | ||
1205 | copy_to_user(argp, &iwr, sizeof(struct iwreq))) | ||
1066 | return -EFAULT; | 1206 | return -EFAULT; |
1207 | |||
1067 | return ret; | 1208 | return ret; |
1068 | } | 1209 | } |
1210 | #endif | ||
1069 | 1211 | ||
1070 | /************************* EVENT PROCESSING *************************/ | 1212 | /************************* EVENT PROCESSING *************************/ |
1071 | /* | 1213 | /* |