1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /******************************************************************************* |
3 | |
4 | Copyright(c) 2004-2005 Intel Corporation. All rights reserved. |
5 | |
6 | Portions of this file are based on the WEP enablement code provided by the |
7 | Host AP project hostap-drivers v0.1.3 |
8 | Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen |
9 | <j@w1.fi> |
10 | Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> |
11 | |
12 | |
13 | Contact Information: |
14 | Intel Linux Wireless <ilw@linux.intel.com> |
15 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
16 | |
17 | *******************************************************************************/ |
18 | |
19 | #include <linux/compiler.h> |
20 | #include <linux/errno.h> |
21 | #include <linux/if_arp.h> |
22 | #include <linux/in6.h> |
23 | #include <linux/in.h> |
24 | #include <linux/ip.h> |
25 | #include <linux/kernel.h> |
26 | #include <linux/module.h> |
27 | #include <linux/netdevice.h> |
28 | #include <linux/proc_fs.h> |
29 | #include <linux/skbuff.h> |
30 | #include <linux/slab.h> |
31 | #include <linux/tcp.h> |
32 | #include <linux/types.h> |
33 | #include <linux/wireless.h> |
34 | #include <linux/etherdevice.h> |
35 | #include <linux/uaccess.h> |
36 | #include <net/net_namespace.h> |
37 | #include <net/arp.h> |
38 | |
39 | #include "libipw.h" |
40 | |
41 | #define DRV_DESCRIPTION "802.11 data/management/control stack" |
42 | #define DRV_NAME "libipw" |
43 | #define DRV_PROCNAME "ieee80211" |
44 | #define DRV_VERSION LIBIPW_VERSION |
45 | #define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>" |
46 | |
47 | MODULE_VERSION(DRV_VERSION); |
48 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |
49 | MODULE_AUTHOR(DRV_COPYRIGHT); |
50 | MODULE_LICENSE("GPL" ); |
51 | |
52 | static struct cfg80211_ops libipw_config_ops = { }; |
53 | static void *libipw_wiphy_privid = &libipw_wiphy_privid; |
54 | |
55 | static int libipw_networks_allocate(struct libipw_device *ieee) |
56 | { |
57 | int i, j; |
58 | |
59 | for (i = 0; i < MAX_NETWORK_COUNT; i++) { |
60 | ieee->networks[i] = kzalloc(size: sizeof(struct libipw_network), |
61 | GFP_KERNEL); |
62 | if (!ieee->networks[i]) { |
63 | LIBIPW_ERROR("Out of memory allocating beacons\n" ); |
64 | for (j = 0; j < i; j++) |
65 | kfree(objp: ieee->networks[j]); |
66 | return -ENOMEM; |
67 | } |
68 | } |
69 | |
70 | return 0; |
71 | } |
72 | |
73 | static inline void libipw_networks_free(struct libipw_device *ieee) |
74 | { |
75 | int i; |
76 | |
77 | for (i = 0; i < MAX_NETWORK_COUNT; i++) |
78 | kfree(objp: ieee->networks[i]); |
79 | } |
80 | |
81 | void libipw_networks_age(struct libipw_device *ieee, |
82 | unsigned long age_secs) |
83 | { |
84 | struct libipw_network *network = NULL; |
85 | unsigned long flags; |
86 | unsigned long age_jiffies = msecs_to_jiffies(m: age_secs * MSEC_PER_SEC); |
87 | |
88 | spin_lock_irqsave(&ieee->lock, flags); |
89 | list_for_each_entry(network, &ieee->network_list, list) { |
90 | network->last_scanned -= age_jiffies; |
91 | } |
92 | spin_unlock_irqrestore(lock: &ieee->lock, flags); |
93 | } |
94 | EXPORT_SYMBOL(libipw_networks_age); |
95 | |
96 | static void libipw_networks_initialize(struct libipw_device *ieee) |
97 | { |
98 | int i; |
99 | |
100 | INIT_LIST_HEAD(list: &ieee->network_free_list); |
101 | INIT_LIST_HEAD(list: &ieee->network_list); |
102 | for (i = 0; i < MAX_NETWORK_COUNT; i++) |
103 | list_add_tail(new: &ieee->networks[i]->list, |
104 | head: &ieee->network_free_list); |
105 | } |
106 | |
107 | struct net_device *alloc_libipw(int sizeof_priv, int monitor) |
108 | { |
109 | struct libipw_device *ieee; |
110 | struct net_device *dev; |
111 | int err; |
112 | |
113 | LIBIPW_DEBUG_INFO("Initializing...\n" ); |
114 | |
115 | dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv); |
116 | if (!dev) |
117 | goto failed; |
118 | |
119 | ieee = netdev_priv(dev); |
120 | |
121 | ieee->dev = dev; |
122 | |
123 | if (!monitor) { |
124 | ieee->wdev.wiphy = wiphy_new(ops: &libipw_config_ops, sizeof_priv: 0); |
125 | if (!ieee->wdev.wiphy) { |
126 | LIBIPW_ERROR("Unable to allocate wiphy.\n" ); |
127 | goto failed_free_netdev; |
128 | } |
129 | |
130 | ieee->dev->ieee80211_ptr = &ieee->wdev; |
131 | ieee->wdev.iftype = NL80211_IFTYPE_STATION; |
132 | |
133 | /* Fill-out wiphy structure bits we know... Not enough info |
134 | here to call set_wiphy_dev or set MAC address or channel info |
135 | -- have to do that in ->ndo_init... */ |
136 | ieee->wdev.wiphy->privid = libipw_wiphy_privid; |
137 | |
138 | ieee->wdev.wiphy->max_scan_ssids = 1; |
139 | ieee->wdev.wiphy->max_scan_ie_len = 0; |
140 | ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
141 | | BIT(NL80211_IFTYPE_ADHOC); |
142 | } |
143 | |
144 | err = libipw_networks_allocate(ieee); |
145 | if (err) { |
146 | LIBIPW_ERROR("Unable to allocate beacon storage: %d\n" , err); |
147 | goto failed_free_wiphy; |
148 | } |
149 | libipw_networks_initialize(ieee); |
150 | |
151 | /* Default fragmentation threshold is maximum payload size */ |
152 | ieee->fts = DEFAULT_FTS; |
153 | ieee->rts = DEFAULT_FTS; |
154 | ieee->scan_age = DEFAULT_MAX_SCAN_AGE; |
155 | ieee->open_wep = 1; |
156 | |
157 | /* Default to enabling full open WEP with host based encrypt/decrypt */ |
158 | ieee->host_encrypt = 1; |
159 | ieee->host_decrypt = 1; |
160 | ieee->host_mc_decrypt = 1; |
161 | |
162 | /* Host fragmentation in Open mode. Default is enabled. |
163 | * Note: host fragmentation is always enabled if host encryption |
164 | * is enabled. For cards can do hardware encryption, they must do |
165 | * hardware fragmentation as well. So we don't need a variable |
166 | * like host_enc_frag. */ |
167 | ieee->host_open_frag = 1; |
168 | ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ |
169 | |
170 | spin_lock_init(&ieee->lock); |
171 | |
172 | lib80211_crypt_info_init(info: &ieee->crypt_info, name: dev->name, lock: &ieee->lock); |
173 | |
174 | ieee->wpa_enabled = 0; |
175 | ieee->drop_unencrypted = 0; |
176 | ieee->privacy_invoked = 0; |
177 | |
178 | return dev; |
179 | |
180 | failed_free_wiphy: |
181 | if (!monitor) |
182 | wiphy_free(wiphy: ieee->wdev.wiphy); |
183 | failed_free_netdev: |
184 | free_netdev(dev); |
185 | failed: |
186 | return NULL; |
187 | } |
188 | EXPORT_SYMBOL(alloc_libipw); |
189 | |
190 | void free_libipw(struct net_device *dev, int monitor) |
191 | { |
192 | struct libipw_device *ieee = netdev_priv(dev); |
193 | |
194 | lib80211_crypt_info_free(info: &ieee->crypt_info); |
195 | |
196 | libipw_networks_free(ieee); |
197 | |
198 | /* free cfg80211 resources */ |
199 | if (!monitor) |
200 | wiphy_free(wiphy: ieee->wdev.wiphy); |
201 | |
202 | free_netdev(dev); |
203 | } |
204 | EXPORT_SYMBOL(free_libipw); |
205 | |
206 | #ifdef CONFIG_LIBIPW_DEBUG |
207 | |
208 | static int debug = 0; |
209 | u32 libipw_debug_level = 0; |
210 | EXPORT_SYMBOL_GPL(libipw_debug_level); |
211 | static struct proc_dir_entry *libipw_proc = NULL; |
212 | |
213 | static int debug_level_proc_show(struct seq_file *m, void *v) |
214 | { |
215 | seq_printf(m, fmt: "0x%08X\n" , libipw_debug_level); |
216 | return 0; |
217 | } |
218 | |
219 | static int debug_level_proc_open(struct inode *inode, struct file *file) |
220 | { |
221 | return single_open(file, debug_level_proc_show, NULL); |
222 | } |
223 | |
224 | static ssize_t debug_level_proc_write(struct file *file, |
225 | const char __user *buffer, size_t count, loff_t *pos) |
226 | { |
227 | char buf[] = "0x00000000\n" ; |
228 | size_t len = min(sizeof(buf) - 1, count); |
229 | unsigned long val; |
230 | |
231 | if (copy_from_user(to: buf, from: buffer, n: len)) |
232 | return count; |
233 | buf[len] = 0; |
234 | if (sscanf(buf, "%li" , &val) != 1) |
235 | printk(KERN_INFO DRV_NAME |
236 | ": %s is not in hex or decimal form.\n" , buf); |
237 | else |
238 | libipw_debug_level = val; |
239 | |
240 | return strnlen(p: buf, maxlen: len); |
241 | } |
242 | |
243 | static const struct proc_ops debug_level_proc_ops = { |
244 | .proc_open = debug_level_proc_open, |
245 | .proc_read = seq_read, |
246 | .proc_lseek = seq_lseek, |
247 | .proc_release = single_release, |
248 | .proc_write = debug_level_proc_write, |
249 | }; |
250 | #endif /* CONFIG_LIBIPW_DEBUG */ |
251 | |
252 | static int __init libipw_init(void) |
253 | { |
254 | #ifdef CONFIG_LIBIPW_DEBUG |
255 | struct proc_dir_entry *e; |
256 | |
257 | libipw_debug_level = debug; |
258 | libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net); |
259 | if (libipw_proc == NULL) { |
260 | LIBIPW_ERROR("Unable to create " DRV_PROCNAME |
261 | " proc directory\n" ); |
262 | return -EIO; |
263 | } |
264 | e = proc_create(name: "debug_level" , mode: 0644, parent: libipw_proc, |
265 | proc_ops: &debug_level_proc_ops); |
266 | if (!e) { |
267 | remove_proc_entry(DRV_PROCNAME, init_net.proc_net); |
268 | libipw_proc = NULL; |
269 | return -EIO; |
270 | } |
271 | #endif /* CONFIG_LIBIPW_DEBUG */ |
272 | |
273 | printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n" ); |
274 | printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n" ); |
275 | |
276 | return 0; |
277 | } |
278 | |
279 | static void __exit libipw_exit(void) |
280 | { |
281 | #ifdef CONFIG_LIBIPW_DEBUG |
282 | if (libipw_proc) { |
283 | remove_proc_entry("debug_level" , libipw_proc); |
284 | remove_proc_entry(DRV_PROCNAME, init_net.proc_net); |
285 | libipw_proc = NULL; |
286 | } |
287 | #endif /* CONFIG_LIBIPW_DEBUG */ |
288 | } |
289 | |
290 | #ifdef CONFIG_LIBIPW_DEBUG |
291 | #include <linux/moduleparam.h> |
292 | module_param(debug, int, 0444); |
293 | MODULE_PARM_DESC(debug, "debug output mask" ); |
294 | #endif /* CONFIG_LIBIPW_DEBUG */ |
295 | |
296 | module_exit(libipw_exit); |
297 | module_init(libipw_init); |
298 | |