diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-25 11:30:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-25 11:30:48 -0400 |
commit | c55960499f810357a29659b32d6ea594abee9237 (patch) | |
tree | b65748db925f7ec894e0b2cf8783609c6fbc88be | |
parent | fbaab1dc19751c80a7df62425f1d9ad2688e42f5 (diff) | |
parent | 10c6c9c94c3eaadd7f9d6bafccc8709eda0da0f5 (diff) |
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb
* 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb:
uwb: Orphan the UWB and WUSB subsystems
uwb: Remove the WLP subsystem and drivers
-rw-r--r-- | MAINTAINERS | 18 | ||||
-rw-r--r-- | drivers/uwb/Kconfig | 20 | ||||
-rw-r--r-- | drivers/uwb/Makefile | 1 | ||||
-rw-r--r-- | drivers/uwb/i1480/Makefile | 1 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480-wlp.h | 200 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/Makefile | 8 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | 283 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/lc.c | 424 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/netdev.c | 331 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/rx.c | 474 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/sysfs.c | 407 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/tx.c | 584 | ||||
-rw-r--r-- | drivers/uwb/wlp/Makefile | 10 | ||||
-rw-r--r-- | drivers/uwb/wlp/driver.c | 43 | ||||
-rw-r--r-- | drivers/uwb/wlp/eda.c | 415 | ||||
-rw-r--r-- | drivers/uwb/wlp/messages.c | 1798 | ||||
-rw-r--r-- | drivers/uwb/wlp/sysfs.c | 708 | ||||
-rw-r--r-- | drivers/uwb/wlp/txrx.c | 354 | ||||
-rw-r--r-- | drivers/uwb/wlp/wlp-internal.h | 224 | ||||
-rw-r--r-- | drivers/uwb/wlp/wlp-lc.c | 560 | ||||
-rw-r--r-- | drivers/uwb/wlp/wss-lc.c | 959 | ||||
-rw-r--r-- | include/linux/wlp.h | 736 |
22 files changed, 3 insertions, 8555 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 3e95a81e71e0..8f72c90aec0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1562,9 +1562,8 @@ F: net/ceph | |||
1562 | F: include/linux/ceph | 1562 | F: include/linux/ceph |
1563 | 1563 | ||
1564 | CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: | 1564 | CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: |
1565 | M: David Vrabel <david.vrabel@csr.com> | ||
1566 | L: linux-usb@vger.kernel.org | 1565 | L: linux-usb@vger.kernel.org |
1567 | S: Supported | 1566 | S: Orphan |
1568 | F: Documentation/usb/WUSB-Design-overview.txt | 1567 | F: Documentation/usb/WUSB-Design-overview.txt |
1569 | F: Documentation/usb/wusb-cbaf | 1568 | F: Documentation/usb/wusb-cbaf |
1570 | F: drivers/usb/host/hwa-hc.c | 1569 | F: drivers/usb/host/hwa-hc.c |
@@ -5991,13 +5990,9 @@ F: Documentation/filesystems/ufs.txt | |||
5991 | F: fs/ufs/ | 5990 | F: fs/ufs/ |
5992 | 5991 | ||
5993 | ULTRA-WIDEBAND (UWB) SUBSYSTEM: | 5992 | ULTRA-WIDEBAND (UWB) SUBSYSTEM: |
5994 | M: David Vrabel <david.vrabel@csr.com> | ||
5995 | L: linux-usb@vger.kernel.org | 5993 | L: linux-usb@vger.kernel.org |
5996 | S: Supported | 5994 | S: Orphan |
5997 | F: drivers/uwb/ | 5995 | F: drivers/uwb/ |
5998 | X: drivers/uwb/wlp/ | ||
5999 | X: drivers/uwb/i1480/i1480u-wlp/ | ||
6000 | X: drivers/uwb/i1480/i1480-wlp.h | ||
6001 | F: include/linux/uwb.h | 5996 | F: include/linux/uwb.h |
6002 | F: include/linux/uwb/ | 5997 | F: include/linux/uwb/ |
6003 | 5998 | ||
@@ -6533,15 +6528,6 @@ F: include/linux/wimax/debug.h | |||
6533 | F: include/net/wimax.h | 6528 | F: include/net/wimax.h |
6534 | F: net/wimax/ | 6529 | F: net/wimax/ |
6535 | 6530 | ||
6536 | WIMEDIA LLC PROTOCOL (WLP) SUBSYSTEM | ||
6537 | M: David Vrabel <david.vrabel@csr.com> | ||
6538 | L: netdev@vger.kernel.org | ||
6539 | S: Maintained | ||
6540 | F: include/linux/wlp.h | ||
6541 | F: drivers/uwb/wlp/ | ||
6542 | F: drivers/uwb/i1480/i1480u-wlp/ | ||
6543 | F: drivers/uwb/i1480/i1480-wlp.h | ||
6544 | |||
6545 | WISTRON LAPTOP BUTTON DRIVER | 6531 | WISTRON LAPTOP BUTTON DRIVER |
6546 | M: Miloslav Trmac <mitr@volny.cz> | 6532 | M: Miloslav Trmac <mitr@volny.cz> |
6547 | S: Maintained | 6533 | S: Maintained |
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig index bac8e7a6f17b..d100f54ed650 100644 --- a/drivers/uwb/Kconfig +++ b/drivers/uwb/Kconfig | |||
@@ -12,8 +12,7 @@ menuconfig UWB | |||
12 | technology using a wide spectrum (3.1-10.6GHz). It is | 12 | technology using a wide spectrum (3.1-10.6GHz). It is |
13 | optimized for in-room use (480Mbps at 2 meters, 110Mbps at | 13 | optimized for in-room use (480Mbps at 2 meters, 110Mbps at |
14 | 10m). It serves as the transport layer for other protocols, | 14 | 10m). It serves as the transport layer for other protocols, |
15 | such as Wireless USB (WUSB), IP (WLP) and upcoming | 15 | such as Wireless USB (WUSB). |
16 | Bluetooth and 1394 | ||
17 | 16 | ||
18 | The topology is peer to peer; however, higher level | 17 | The topology is peer to peer; however, higher level |
19 | protocols (such as WUSB) might impose a master/slave | 18 | protocols (such as WUSB) might impose a master/slave |
@@ -58,13 +57,6 @@ config UWB_WHCI | |||
58 | To compile this driver select Y (built in) or M (module). It | 57 | To compile this driver select Y (built in) or M (module). It |
59 | is safe to select any even if you do not have the hardware. | 58 | is safe to select any even if you do not have the hardware. |
60 | 59 | ||
61 | config UWB_WLP | ||
62 | tristate "Support WiMedia Link Protocol (Ethernet/IP over UWB)" | ||
63 | depends on UWB && NET | ||
64 | help | ||
65 | This is a common library for drivers that implement | ||
66 | networking over UWB. | ||
67 | |||
68 | config UWB_I1480U | 60 | config UWB_I1480U |
69 | tristate "Support for Intel Wireless UWB Link 1480 HWA" | 61 | tristate "Support for Intel Wireless UWB Link 1480 HWA" |
70 | depends on UWB_HWA | 62 | depends on UWB_HWA |
@@ -77,14 +69,4 @@ config UWB_I1480U | |||
77 | To compile this driver select Y (built in) or M (module). It | 69 | To compile this driver select Y (built in) or M (module). It |
78 | is safe to select any even if you do not have the hardware. | 70 | is safe to select any even if you do not have the hardware. |
79 | 71 | ||
80 | config UWB_I1480U_WLP | ||
81 | tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface" | ||
82 | depends on UWB_I1480U && UWB_WLP && NET | ||
83 | help | ||
84 | This driver enables WLP support for the i1480 when connected via | ||
85 | USB. WLP is the WiMedia Link Protocol, or IP over UWB. | ||
86 | |||
87 | To compile this driver select Y (built in) or M (module). It | ||
88 | is safe to select any even if you don't have the hardware. | ||
89 | |||
90 | endif # UWB | 72 | endif # UWB |
diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile index 2f98d080fe78..d47dd6e2942c 100644 --- a/drivers/uwb/Makefile +++ b/drivers/uwb/Makefile | |||
@@ -1,5 +1,4 @@ | |||
1 | obj-$(CONFIG_UWB) += uwb.o | 1 | obj-$(CONFIG_UWB) += uwb.o |
2 | obj-$(CONFIG_UWB_WLP) += wlp/ | ||
3 | obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o | 2 | obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o |
4 | obj-$(CONFIG_UWB_HWA) += hwa-rc.o | 3 | obj-$(CONFIG_UWB_HWA) += hwa-rc.o |
5 | obj-$(CONFIG_UWB_I1480U) += i1480/ | 4 | obj-$(CONFIG_UWB_I1480U) += i1480/ |
diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile index 212bbc7d4c32..d69da1684cfb 100644 --- a/drivers/uwb/i1480/Makefile +++ b/drivers/uwb/i1480/Makefile | |||
@@ -1,2 +1 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o | obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o | |
2 | obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/ | ||
diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h deleted file mode 100644 index 18a8b0e4567b..000000000000 --- a/drivers/uwb/i1480/i1480-wlp.h +++ /dev/null | |||
@@ -1,200 +0,0 @@ | |||
1 | /* | ||
2 | * Intel 1480 Wireless UWB Link | ||
3 | * WLP specific definitions | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * FIXME: docs | ||
25 | */ | ||
26 | |||
27 | #ifndef __i1480_wlp_h__ | ||
28 | #define __i1480_wlp_h__ | ||
29 | |||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/uwb.h> | ||
33 | #include <linux/if_ether.h> | ||
34 | #include <asm/byteorder.h> | ||
35 | |||
36 | /* New simplified header format? */ | ||
37 | #undef WLP_HDR_FMT_2 /* FIXME: rename */ | ||
38 | |||
39 | /** | ||
40 | * Values of the Delivery ID & Type field when PCA or DRP | ||
41 | * | ||
42 | * The Delivery ID & Type field in the WLP TX header indicates whether | ||
43 | * the frame is PCA or DRP. This is done based on the high level bit of | ||
44 | * this field. | ||
45 | * We use this constant to test if the traffic is PCA or DRP as follows: | ||
46 | * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP) | ||
47 | * this is DRP traffic | ||
48 | * else | ||
49 | * this is PCA traffic | ||
50 | */ | ||
51 | enum deliver_id_type_bit { | ||
52 | WLP_DRP = 8, | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * WLP TX header | ||
57 | * | ||
58 | * Indicates UWB/WLP-specific transmission parameters for a network | ||
59 | * packet. | ||
60 | */ | ||
61 | struct wlp_tx_hdr { | ||
62 | /* dword 0 */ | ||
63 | struct uwb_dev_addr dstaddr; | ||
64 | u8 key_index; | ||
65 | u8 mac_params; | ||
66 | /* dword 1 */ | ||
67 | u8 phy_params; | ||
68 | #ifndef WLP_HDR_FMT_2 | ||
69 | u8 reserved; | ||
70 | __le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */ | ||
71 | /* dword 2 */ | ||
72 | u8 oui2; /* if all LE, it could be merged */ | ||
73 | __le16 prid; | ||
74 | #endif | ||
75 | } __attribute__((packed)); | ||
76 | |||
77 | static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr) | ||
78 | { | ||
79 | return hdr->mac_params & 0x0f; | ||
80 | } | ||
81 | |||
82 | static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr) | ||
83 | { | ||
84 | return (hdr->mac_params >> 4) & 0x07; | ||
85 | } | ||
86 | |||
87 | static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr) | ||
88 | { | ||
89 | return (hdr->mac_params >> 7) & 0x01; | ||
90 | } | ||
91 | |||
92 | static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id) | ||
93 | { | ||
94 | hdr->mac_params = (hdr->mac_params & ~0x0f) | id; | ||
95 | } | ||
96 | |||
97 | static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr, | ||
98 | enum uwb_ack_pol policy) | ||
99 | { | ||
100 | hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4); | ||
101 | } | ||
102 | |||
103 | static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts) | ||
104 | { | ||
105 | hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7); | ||
106 | } | ||
107 | |||
108 | static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr) | ||
109 | { | ||
110 | return hdr->phy_params & 0x0f; | ||
111 | } | ||
112 | |||
113 | static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr) | ||
114 | { | ||
115 | return (hdr->phy_params >> 4) & 0x0f; | ||
116 | } | ||
117 | |||
118 | static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate) | ||
119 | { | ||
120 | hdr->phy_params = (hdr->phy_params & ~0x0f) | rate; | ||
121 | } | ||
122 | |||
123 | static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr) | ||
124 | { | ||
125 | hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * WLP RX header | ||
131 | * | ||
132 | * Provides UWB/WLP-specific transmission data for a received | ||
133 | * network packet. | ||
134 | */ | ||
135 | struct wlp_rx_hdr { | ||
136 | /* dword 0 */ | ||
137 | struct uwb_dev_addr dstaddr; | ||
138 | struct uwb_dev_addr srcaddr; | ||
139 | /* dword 1 */ | ||
140 | u8 LQI; | ||
141 | s8 RSSI; | ||
142 | u8 reserved3; | ||
143 | #ifndef WLP_HDR_FMT_2 | ||
144 | u8 oui0; | ||
145 | /* dword 2 */ | ||
146 | __le16 oui12; | ||
147 | __le16 prid; | ||
148 | #endif | ||
149 | } __attribute__((packed)); | ||
150 | |||
151 | |||
152 | /** User configurable options for WLP */ | ||
153 | struct wlp_options { | ||
154 | struct mutex mutex; /* access to user configurable options*/ | ||
155 | struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */ | ||
156 | u8 pca_base_priority; | ||
157 | u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/ | ||
158 | }; | ||
159 | |||
160 | |||
161 | static inline | ||
162 | void wlp_options_init(struct wlp_options *options) | ||
163 | { | ||
164 | mutex_init(&options->mutex); | ||
165 | wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM); | ||
166 | wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1); | ||
167 | /* FIXME: default to phy caps */ | ||
168 | wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480); | ||
169 | #ifndef WLP_HDR_FMT_2 | ||
170 | options->def_tx_hdr.prid = cpu_to_le16(0x0000); | ||
171 | #endif | ||
172 | } | ||
173 | |||
174 | |||
175 | /* sysfs helpers */ | ||
176 | |||
177 | extern ssize_t uwb_pca_base_priority_store(struct wlp_options *, | ||
178 | const char *, size_t); | ||
179 | extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *); | ||
180 | extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t); | ||
181 | extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *); | ||
182 | extern ssize_t uwb_ack_policy_store(struct wlp_options *, | ||
183 | const char *, size_t); | ||
184 | extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *); | ||
185 | extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t); | ||
186 | extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *); | ||
187 | extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t); | ||
188 | extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *); | ||
189 | |||
190 | |||
191 | /** Simple bandwidth allocation (temporary and too simple) */ | ||
192 | struct wlp_bw_allocs { | ||
193 | const char *name; | ||
194 | struct { | ||
195 | u8 mask, stream; | ||
196 | } tx, rx; | ||
197 | }; | ||
198 | |||
199 | |||
200 | #endif /* #ifndef __i1480_wlp_h__ */ | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile deleted file mode 100644 index fe6709b8e68b..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/Makefile +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o | ||
2 | |||
3 | i1480u-wlp-objs := \ | ||
4 | lc.o \ | ||
5 | netdev.o \ | ||
6 | rx.o \ | ||
7 | sysfs.o \ | ||
8 | tx.o | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h deleted file mode 100644 index 2e31f536a347..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h +++ /dev/null | |||
@@ -1,283 +0,0 @@ | |||
1 | /* | ||
2 | * Intel 1480 Wireless UWB Link USB | ||
3 | * Header formats, constants, general internal interfaces | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * This is not an standard interface. | ||
25 | * | ||
26 | * FIXME: docs | ||
27 | * | ||
28 | * i1480u-wlp is pretty simple: two endpoints, one for tx, one for | ||
29 | * rx. rx is polled. Network packets (ethernet, whatever) are wrapped | ||
30 | * in i1480 TX or RX headers (for sending over the air), and these | ||
31 | * packets are wrapped in UNTD headers (for sending to the WLP UWB | ||
32 | * controller). | ||
33 | * | ||
34 | * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets | ||
35 | * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the | ||
36 | * i1480 packet is broken in chunks/packets: | ||
37 | * | ||
38 | * UNTD-1st.hdr + i1480.hdr + payload | ||
39 | * UNTD-next.hdr + payload | ||
40 | * ... | ||
41 | * UNTD-last.hdr + payload | ||
42 | * | ||
43 | * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE. | ||
44 | * | ||
45 | * All HW structures and bitmaps are little endian, so we need to play | ||
46 | * ugly tricks when defining bitfields. Hoping for the day GCC | ||
47 | * implements __attribute__((endian(1234))). | ||
48 | * | ||
49 | * FIXME: ROADMAP to the whole implementation | ||
50 | */ | ||
51 | |||
52 | #ifndef __i1480u_wlp_h__ | ||
53 | #define __i1480u_wlp_h__ | ||
54 | |||
55 | #include <linux/usb.h> | ||
56 | #include <linux/netdevice.h> | ||
57 | #include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */ | ||
58 | #include <linux/wlp.h> | ||
59 | #include "../i1480-wlp.h" | ||
60 | |||
61 | #undef i1480u_FLOW_CONTROL /* Enable flow control code */ | ||
62 | |||
63 | /** | ||
64 | * Basic flow control | ||
65 | */ | ||
66 | enum { | ||
67 | i1480u_TX_INFLIGHT_MAX = 1000, | ||
68 | i1480u_TX_INFLIGHT_THRESHOLD = 100, | ||
69 | }; | ||
70 | |||
71 | /** Maximum size of a transaction that we can tx/rx */ | ||
72 | enum { | ||
73 | /* Maximum packet size computed as follows: max UNTD header (8) + | ||
74 | * i1480 RX header (8) + max Ethernet header and payload (4096) + | ||
75 | * Padding added by skb_reserve (2) to make post Ethernet payload | ||
76 | * start on 16 byte boundary*/ | ||
77 | i1480u_MAX_RX_PKT_SIZE = 4114, | ||
78 | i1480u_MAX_FRG_SIZE = 512, | ||
79 | i1480u_RX_BUFS = 9, | ||
80 | }; | ||
81 | |||
82 | |||
83 | /** | ||
84 | * UNTD packet type | ||
85 | * | ||
86 | * We need to fragment any payload whose UNTD packet is going to be | ||
87 | * bigger than i1480u_MAX_FRG_SIZE. | ||
88 | */ | ||
89 | enum i1480u_pkt_type { | ||
90 | i1480u_PKT_FRAG_1ST = 0x1, | ||
91 | i1480u_PKT_FRAG_NXT = 0x0, | ||
92 | i1480u_PKT_FRAG_LST = 0x2, | ||
93 | i1480u_PKT_FRAG_CMP = 0x3 | ||
94 | }; | ||
95 | enum { | ||
96 | i1480u_PKT_NONE = 0x4, | ||
97 | }; | ||
98 | |||
99 | /** USB Network Transfer Descriptor - common */ | ||
100 | struct untd_hdr { | ||
101 | u8 type; | ||
102 | __le16 len; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr) | ||
106 | { | ||
107 | return hdr->type & 0x03; | ||
108 | } | ||
109 | |||
110 | static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr) | ||
111 | { | ||
112 | return (hdr->type >> 2) & 0x01; | ||
113 | } | ||
114 | |||
115 | static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type) | ||
116 | { | ||
117 | hdr->type = (hdr->type & ~0x03) | type; | ||
118 | } | ||
119 | |||
120 | static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx) | ||
121 | { | ||
122 | hdr->type = (hdr->type & ~0x04) | (rx_tx << 2); | ||
123 | } | ||
124 | |||
125 | |||
126 | /** | ||
127 | * USB Network Transfer Descriptor - Complete Packet | ||
128 | * | ||
129 | * This is for a packet that is smaller (header + payload) than | ||
130 | * i1480u_MAX_FRG_SIZE. | ||
131 | * | ||
132 | * @hdr.total_len is the size of the payload; the payload doesn't | ||
133 | * count this header nor the padding, but includes the size of i1480 | ||
134 | * header. | ||
135 | */ | ||
136 | struct untd_hdr_cmp { | ||
137 | struct untd_hdr hdr; | ||
138 | u8 padding; | ||
139 | } __attribute__((packed)); | ||
140 | |||
141 | |||
142 | /** | ||
143 | * USB Network Transfer Descriptor - First fragment | ||
144 | * | ||
145 | * @hdr.len is the size of the *whole packet* (excluding UNTD | ||
146 | * headers); @fragment_len is the size of the payload (excluding UNTD | ||
147 | * headers, but including i1480 headers). | ||
148 | */ | ||
149 | struct untd_hdr_1st { | ||
150 | struct untd_hdr hdr; | ||
151 | __le16 fragment_len; | ||
152 | u8 padding[3]; | ||
153 | } __attribute__((packed)); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * USB Network Transfer Descriptor - Next / Last [Rest] | ||
158 | * | ||
159 | * @hdr.len is the size of the payload, not including headrs. | ||
160 | */ | ||
161 | struct untd_hdr_rst { | ||
162 | struct untd_hdr hdr; | ||
163 | u8 padding; | ||
164 | } __attribute__((packed)); | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Transmission context | ||
169 | * | ||
170 | * Wraps all the stuff needed to track a pending/active tx | ||
171 | * operation. | ||
172 | */ | ||
173 | struct i1480u_tx { | ||
174 | struct list_head list_node; | ||
175 | struct i1480u *i1480u; | ||
176 | struct urb *urb; | ||
177 | |||
178 | struct sk_buff *skb; | ||
179 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
180 | |||
181 | void *buf; /* if NULL, no new buf was used */ | ||
182 | size_t buf_size; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * Basic flow control | ||
187 | * | ||
188 | * We maintain a basic flow control counter. "count" how many TX URBs are | ||
189 | * outstanding. Only allow "max" | ||
190 | * TX URBs to be outstanding. If this value is reached the queue will be | ||
191 | * stopped. The queue will be restarted when there are | ||
192 | * "threshold" URBs outstanding. | ||
193 | * Maintain a counter of how many time the TX queue needed to be restarted | ||
194 | * due to the "max" being exceeded and the "threshold" reached again. The | ||
195 | * timestamp "restart_ts" is to keep track from when the counter was last | ||
196 | * queried (see sysfs handling of file wlp_tx_inflight). | ||
197 | */ | ||
198 | struct i1480u_tx_inflight { | ||
199 | atomic_t count; | ||
200 | unsigned long max; | ||
201 | unsigned long threshold; | ||
202 | unsigned long restart_ts; | ||
203 | atomic_t restart_count; | ||
204 | }; | ||
205 | |||
206 | /** | ||
207 | * Instance of a i1480u WLP interface | ||
208 | * | ||
209 | * Keeps references to the USB device that wraps it, as well as it's | ||
210 | * interface and associated UWB host controller. As well, it also | ||
211 | * keeps a link to the netdevice for integration into the networking | ||
212 | * stack. | ||
213 | * We maintian separate error history for the tx and rx endpoints because | ||
214 | * the implementation does not rely on locking - having one shared | ||
215 | * structure between endpoints may cause problems. Adding locking to the | ||
216 | * implementation will have higher cost than adding a separate structure. | ||
217 | */ | ||
218 | struct i1480u { | ||
219 | struct usb_device *usb_dev; | ||
220 | struct usb_interface *usb_iface; | ||
221 | struct net_device *net_dev; | ||
222 | |||
223 | spinlock_t lock; | ||
224 | |||
225 | /* RX context handling */ | ||
226 | struct sk_buff *rx_skb; | ||
227 | struct uwb_dev_addr rx_srcaddr; | ||
228 | size_t rx_untd_pkt_size; | ||
229 | struct i1480u_rx_buf { | ||
230 | struct i1480u *i1480u; /* back pointer */ | ||
231 | struct urb *urb; | ||
232 | struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */ | ||
233 | } rx_buf[i1480u_RX_BUFS]; /* N bufs */ | ||
234 | |||
235 | spinlock_t tx_list_lock; /* TX context */ | ||
236 | struct list_head tx_list; | ||
237 | u8 tx_stream; | ||
238 | |||
239 | struct stats lqe_stats, rssi_stats; /* radio statistics */ | ||
240 | |||
241 | /* Options we can set from sysfs */ | ||
242 | struct wlp_options options; | ||
243 | struct uwb_notifs_handler uwb_notifs_handler; | ||
244 | struct edc tx_errors; | ||
245 | struct edc rx_errors; | ||
246 | struct wlp wlp; | ||
247 | #ifdef i1480u_FLOW_CONTROL | ||
248 | struct urb *notif_urb; | ||
249 | struct edc notif_edc; /* error density counter */ | ||
250 | u8 notif_buffer[1]; | ||
251 | #endif | ||
252 | struct i1480u_tx_inflight tx_inflight; | ||
253 | }; | ||
254 | |||
255 | /* Internal interfaces */ | ||
256 | extern void i1480u_rx_cb(struct urb *urb); | ||
257 | extern int i1480u_rx_setup(struct i1480u *); | ||
258 | extern void i1480u_rx_release(struct i1480u *); | ||
259 | extern void i1480u_tx_release(struct i1480u *); | ||
260 | extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *, | ||
261 | struct uwb_dev_addr *); | ||
262 | extern void i1480u_stop_queue(struct wlp *); | ||
263 | extern void i1480u_start_queue(struct wlp *); | ||
264 | extern int i1480u_sysfs_setup(struct i1480u *); | ||
265 | extern void i1480u_sysfs_release(struct i1480u *); | ||
266 | |||
267 | /* netdev interface */ | ||
268 | extern int i1480u_open(struct net_device *); | ||
269 | extern int i1480u_stop(struct net_device *); | ||
270 | extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *, | ||
271 | struct net_device *); | ||
272 | extern void i1480u_tx_timeout(struct net_device *); | ||
273 | extern int i1480u_set_config(struct net_device *, struct ifmap *); | ||
274 | extern int i1480u_change_mtu(struct net_device *, int); | ||
275 | extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs); | ||
276 | |||
277 | /* bandwidth allocation callback */ | ||
278 | extern void i1480u_bw_alloc_cb(struct uwb_rsv *); | ||
279 | |||
280 | /* Sys FS */ | ||
281 | extern struct attribute_group i1480u_wlp_attr_group; | ||
282 | |||
283 | #endif /* #ifndef __i1480u_wlp_h__ */ | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c deleted file mode 100644 index def778cf2216..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/lc.c +++ /dev/null | |||
@@ -1,424 +0,0 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * This implements a very simple network driver for the WLP USB | ||
26 | * device that is associated to a UWB (Ultra Wide Band) host. | ||
27 | * | ||
28 | * This is seen as an interface of a composite device. Once the UWB | ||
29 | * host has an association to another WLP capable device, the | ||
30 | * networking interface (aka WLP) can start to send packets back and | ||
31 | * forth. | ||
32 | * | ||
33 | * Limitations: | ||
34 | * | ||
35 | * - Hand cranked; can't ifup the interface until there is an association | ||
36 | * | ||
37 | * - BW allocation very simplistic [see i1480u_mas_set() and callees]. | ||
38 | * | ||
39 | * | ||
40 | * ROADMAP: | ||
41 | * | ||
42 | * ENTRY POINTS (driver model): | ||
43 | * | ||
44 | * i1480u_driver_{exit,init}(): initialization of the driver. | ||
45 | * | ||
46 | * i1480u_probe(): called by the driver code when a device | ||
47 | * matching 'i1480u_id_table' is connected. | ||
48 | * | ||
49 | * This allocs a netdev instance, inits with | ||
50 | * i1480u_add(), then registers_netdev(). | ||
51 | * i1480u_init() | ||
52 | * i1480u_add() | ||
53 | * | ||
54 | * i1480u_disconnect(): device has been disconnected/module | ||
55 | * is being removed. | ||
56 | * i1480u_rm() | ||
57 | */ | ||
58 | #include <linux/gfp.h> | ||
59 | #include <linux/if_arp.h> | ||
60 | #include <linux/etherdevice.h> | ||
61 | |||
62 | #include "i1480u-wlp.h" | ||
63 | |||
64 | |||
65 | |||
66 | static inline | ||
67 | void i1480u_init(struct i1480u *i1480u) | ||
68 | { | ||
69 | /* nothing so far... doesn't it suck? */ | ||
70 | spin_lock_init(&i1480u->lock); | ||
71 | INIT_LIST_HEAD(&i1480u->tx_list); | ||
72 | spin_lock_init(&i1480u->tx_list_lock); | ||
73 | wlp_options_init(&i1480u->options); | ||
74 | edc_init(&i1480u->tx_errors); | ||
75 | edc_init(&i1480u->rx_errors); | ||
76 | #ifdef i1480u_FLOW_CONTROL | ||
77 | edc_init(&i1480u->notif_edc); | ||
78 | #endif | ||
79 | stats_init(&i1480u->lqe_stats); | ||
80 | stats_init(&i1480u->rssi_stats); | ||
81 | wlp_init(&i1480u->wlp); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Fill WLP device information structure | ||
86 | * | ||
87 | * The structure will contain a few character arrays, each ending with a | ||
88 | * null terminated string. Each string has to fit (excluding terminating | ||
89 | * character) into a specified range obtained from the WLP substack. | ||
90 | * | ||
91 | * It is still not clear exactly how this device information should be | ||
92 | * obtained. Until we find out we use the USB device descriptor as backup, some | ||
93 | * information elements have intuitive mappings, other not. | ||
94 | */ | ||
95 | static | ||
96 | void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info) | ||
97 | { | ||
98 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
99 | struct usb_device *usb_dev = i1480u->usb_dev; | ||
100 | /* Treat device name and model name the same */ | ||
101 | if (usb_dev->descriptor.iProduct) { | ||
102 | usb_string(usb_dev, usb_dev->descriptor.iProduct, | ||
103 | dev_info->name, sizeof(dev_info->name)); | ||
104 | usb_string(usb_dev, usb_dev->descriptor.iProduct, | ||
105 | dev_info->model_name, sizeof(dev_info->model_name)); | ||
106 | } | ||
107 | if (usb_dev->descriptor.iManufacturer) | ||
108 | usb_string(usb_dev, usb_dev->descriptor.iManufacturer, | ||
109 | dev_info->manufacturer, | ||
110 | sizeof(dev_info->manufacturer)); | ||
111 | scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x", | ||
112 | __le16_to_cpu(usb_dev->descriptor.bcdDevice)); | ||
113 | if (usb_dev->descriptor.iSerialNumber) | ||
114 | usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, | ||
115 | dev_info->serial, sizeof(dev_info->serial)); | ||
116 | /* FIXME: where should we obtain category? */ | ||
117 | dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER); | ||
118 | /* FIXME: Complete OUI and OUIsubdiv attributes */ | ||
119 | } | ||
120 | |||
121 | #ifdef i1480u_FLOW_CONTROL | ||
122 | /** | ||
123 | * Callback for the notification endpoint | ||
124 | * | ||
125 | * This mostly controls the xon/xoff protocol. In case of hard error, | ||
126 | * we stop the queue. If not, we always retry. | ||
127 | */ | ||
128 | static | ||
129 | void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs) | ||
130 | { | ||
131 | struct i1480u *i1480u = urb->context; | ||
132 | struct usb_interface *usb_iface = i1480u->usb_iface; | ||
133 | struct device *dev = &usb_iface->dev; | ||
134 | int result; | ||
135 | |||
136 | switch (urb->status) { | ||
137 | case 0: /* Got valid data, do xon/xoff */ | ||
138 | switch (i1480u->notif_buffer[0]) { | ||
139 | case 'N': | ||
140 | dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies); | ||
141 | netif_stop_queue(i1480u->net_dev); | ||
142 | break; | ||
143 | case 'A': | ||
144 | dev_err(dev, "XON STARTING queue at %lu\n", jiffies); | ||
145 | netif_start_queue(i1480u->net_dev); | ||
146 | break; | ||
147 | default: | ||
148 | dev_err(dev, "NEP: unknown data 0x%02hhx\n", | ||
149 | i1480u->notif_buffer[0]); | ||
150 | } | ||
151 | break; | ||
152 | case -ECONNRESET: /* Controlled situation ... */ | ||
153 | case -ENOENT: /* we killed the URB... */ | ||
154 | dev_err(dev, "NEP: URB reset/noent %d\n", urb->status); | ||
155 | goto error; | ||
156 | case -ESHUTDOWN: /* going away! */ | ||
157 | dev_err(dev, "NEP: URB down %d\n", urb->status); | ||
158 | goto error; | ||
159 | default: /* Retry unless it gets ugly */ | ||
160 | if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS, | ||
161 | EDC_ERROR_TIMEFRAME)) { | ||
162 | dev_err(dev, "NEP: URB max acceptable errors " | ||
163 | "exceeded; resetting device\n"); | ||
164 | goto error_reset; | ||
165 | } | ||
166 | dev_err(dev, "NEP: URB error %d\n", urb->status); | ||
167 | break; | ||
168 | } | ||
169 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
170 | if (result < 0) { | ||
171 | dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n", | ||
172 | result); | ||
173 | goto error_reset; | ||
174 | } | ||
175 | return; | ||
176 | |||
177 | error_reset: | ||
178 | wlp_reset_all(&i1480-wlp); | ||
179 | error: | ||
180 | netif_stop_queue(i1480u->net_dev); | ||
181 | return; | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | static const struct net_device_ops i1480u_netdev_ops = { | ||
186 | .ndo_open = i1480u_open, | ||
187 | .ndo_stop = i1480u_stop, | ||
188 | .ndo_start_xmit = i1480u_hard_start_xmit, | ||
189 | .ndo_tx_timeout = i1480u_tx_timeout, | ||
190 | .ndo_set_config = i1480u_set_config, | ||
191 | .ndo_change_mtu = i1480u_change_mtu, | ||
192 | }; | ||
193 | |||
194 | static | ||
195 | int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) | ||
196 | { | ||
197 | int result = -ENODEV; | ||
198 | struct wlp *wlp = &i1480u->wlp; | ||
199 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
200 | struct net_device *net_dev = i1480u->net_dev; | ||
201 | struct uwb_rc *rc; | ||
202 | struct uwb_dev *uwb_dev; | ||
203 | #ifdef i1480u_FLOW_CONTROL | ||
204 | struct usb_endpoint_descriptor *epd; | ||
205 | #endif | ||
206 | |||
207 | i1480u->usb_dev = usb_get_dev(usb_dev); | ||
208 | i1480u->usb_iface = iface; | ||
209 | rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev); | ||
210 | if (rc == NULL) { | ||
211 | dev_err(&iface->dev, "Cannot get associated UWB Radio " | ||
212 | "Controller\n"); | ||
213 | goto out; | ||
214 | } | ||
215 | wlp->xmit_frame = i1480u_xmit_frame; | ||
216 | wlp->fill_device_info = i1480u_fill_device_info; | ||
217 | wlp->stop_queue = i1480u_stop_queue; | ||
218 | wlp->start_queue = i1480u_start_queue; | ||
219 | result = wlp_setup(wlp, rc, net_dev); | ||
220 | if (result < 0) { | ||
221 | dev_err(&iface->dev, "Cannot setup WLP\n"); | ||
222 | goto error_wlp_setup; | ||
223 | } | ||
224 | result = 0; | ||
225 | ether_setup(net_dev); /* make it an etherdevice */ | ||
226 | uwb_dev = &rc->uwb_dev; | ||
227 | /* FIXME: hookup address change notifications? */ | ||
228 | |||
229 | memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data, | ||
230 | sizeof(net_dev->dev_addr)); | ||
231 | |||
232 | net_dev->hard_header_len = sizeof(struct untd_hdr_cmp) | ||
233 | + sizeof(struct wlp_tx_hdr) | ||
234 | + WLP_DATA_HLEN | ||
235 | + ETH_HLEN; | ||
236 | net_dev->mtu = 3500; | ||
237 | net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */ | ||
238 | |||
239 | /* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */ | ||
240 | /* FIXME: multicast disabled */ | ||
241 | net_dev->flags &= ~IFF_MULTICAST; | ||
242 | net_dev->features &= ~NETIF_F_SG; | ||
243 | net_dev->features &= ~NETIF_F_FRAGLIST; | ||
244 | /* All NETIF_F_*_CSUM disabled */ | ||
245 | net_dev->features |= NETIF_F_HIGHDMA; | ||
246 | net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ | ||
247 | |||
248 | net_dev->netdev_ops = &i1480u_netdev_ops; | ||
249 | |||
250 | #ifdef i1480u_FLOW_CONTROL | ||
251 | /* Notification endpoint setup (submitted when we open the device) */ | ||
252 | i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
253 | if (i1480u->notif_urb == NULL) { | ||
254 | dev_err(&iface->dev, "Unable to allocate notification URB\n"); | ||
255 | result = -ENOMEM; | ||
256 | goto error_urb_alloc; | ||
257 | } | ||
258 | epd = &iface->cur_altsetting->endpoint[0].desc; | ||
259 | usb_fill_int_urb(i1480u->notif_urb, usb_dev, | ||
260 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | ||
261 | i1480u->notif_buffer, sizeof(i1480u->notif_buffer), | ||
262 | i1480u_notif_cb, i1480u, epd->bInterval); | ||
263 | |||
264 | #endif | ||
265 | |||
266 | i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX; | ||
267 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | ||
268 | i1480u->tx_inflight.restart_ts = jiffies; | ||
269 | usb_set_intfdata(iface, i1480u); | ||
270 | return result; | ||
271 | |||
272 | #ifdef i1480u_FLOW_CONTROL | ||
273 | error_urb_alloc: | ||
274 | #endif | ||
275 | wlp_remove(wlp); | ||
276 | error_wlp_setup: | ||
277 | uwb_rc_put(rc); | ||
278 | out: | ||
279 | usb_put_dev(i1480u->usb_dev); | ||
280 | return result; | ||
281 | } | ||
282 | |||
283 | static void i1480u_rm(struct i1480u *i1480u) | ||
284 | { | ||
285 | struct uwb_rc *rc = i1480u->wlp.rc; | ||
286 | usb_set_intfdata(i1480u->usb_iface, NULL); | ||
287 | #ifdef i1480u_FLOW_CONTROL | ||
288 | usb_kill_urb(i1480u->notif_urb); | ||
289 | usb_free_urb(i1480u->notif_urb); | ||
290 | #endif | ||
291 | wlp_remove(&i1480u->wlp); | ||
292 | uwb_rc_put(rc); | ||
293 | usb_put_dev(i1480u->usb_dev); | ||
294 | } | ||
295 | |||
296 | /** Just setup @net_dev's i1480u private data */ | ||
297 | static void i1480u_netdev_setup(struct net_device *net_dev) | ||
298 | { | ||
299 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
300 | /* Initialize @i1480u */ | ||
301 | memset(i1480u, 0, sizeof(*i1480u)); | ||
302 | i1480u_init(i1480u); | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * Probe a i1480u interface and register it | ||
307 | * | ||
308 | * @iface: USB interface to link to | ||
309 | * @id: USB class/subclass/protocol id | ||
310 | * @returns: 0 if ok, < 0 errno code on error. | ||
311 | * | ||
312 | * Does basic housekeeping stuff and then allocs a netdev with space | ||
313 | * for the i1480u data. Initializes, registers in i1480u, registers in | ||
314 | * netdev, ready to go. | ||
315 | */ | ||
316 | static int i1480u_probe(struct usb_interface *iface, | ||
317 | const struct usb_device_id *id) | ||
318 | { | ||
319 | int result; | ||
320 | struct net_device *net_dev; | ||
321 | struct device *dev = &iface->dev; | ||
322 | struct i1480u *i1480u; | ||
323 | |||
324 | /* Allocate instance [calls i1480u_netdev_setup() on it] */ | ||
325 | result = -ENOMEM; | ||
326 | net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup); | ||
327 | if (net_dev == NULL) { | ||
328 | dev_err(dev, "no memory for network device instance\n"); | ||
329 | goto error_alloc_netdev; | ||
330 | } | ||
331 | SET_NETDEV_DEV(net_dev, dev); | ||
332 | i1480u = netdev_priv(net_dev); | ||
333 | i1480u->net_dev = net_dev; | ||
334 | result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */ | ||
335 | if (result < 0) { | ||
336 | dev_err(dev, "cannot add i1480u device: %d\n", result); | ||
337 | goto error_i1480u_add; | ||
338 | } | ||
339 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | ||
340 | if (result < 0) { | ||
341 | dev_err(dev, "cannot register network device: %d\n", result); | ||
342 | goto error_register_netdev; | ||
343 | } | ||
344 | i1480u_sysfs_setup(i1480u); | ||
345 | if (result < 0) | ||
346 | goto error_sysfs_init; | ||
347 | return 0; | ||
348 | |||
349 | error_sysfs_init: | ||
350 | unregister_netdev(net_dev); | ||
351 | error_register_netdev: | ||
352 | i1480u_rm(i1480u); | ||
353 | error_i1480u_add: | ||
354 | free_netdev(net_dev); | ||
355 | error_alloc_netdev: | ||
356 | return result; | ||
357 | } | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Disconect a i1480u from the system. | ||
362 | * | ||
363 | * i1480u_stop() has been called before, so al the rx and tx contexts | ||
364 | * have been taken down already. Make sure the queue is stopped, | ||
365 | * unregister netdev and i1480u, free and kill. | ||
366 | */ | ||
367 | static void i1480u_disconnect(struct usb_interface *iface) | ||
368 | { | ||
369 | struct i1480u *i1480u; | ||
370 | struct net_device *net_dev; | ||
371 | |||
372 | i1480u = usb_get_intfdata(iface); | ||
373 | net_dev = i1480u->net_dev; | ||
374 | netif_stop_queue(net_dev); | ||
375 | #ifdef i1480u_FLOW_CONTROL | ||
376 | usb_kill_urb(i1480u->notif_urb); | ||
377 | #endif | ||
378 | i1480u_sysfs_release(i1480u); | ||
379 | unregister_netdev(net_dev); | ||
380 | i1480u_rm(i1480u); | ||
381 | free_netdev(net_dev); | ||
382 | } | ||
383 | |||
384 | static struct usb_device_id i1480u_id_table[] = { | ||
385 | { | ||
386 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ | ||
387 | | USB_DEVICE_ID_MATCH_DEV_INFO \ | ||
388 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
389 | .idVendor = 0x8086, | ||
390 | .idProduct = 0x0c3b, | ||
391 | .bDeviceClass = 0xef, | ||
392 | .bDeviceSubClass = 0x02, | ||
393 | .bDeviceProtocol = 0x02, | ||
394 | .bInterfaceClass = 0xff, | ||
395 | .bInterfaceSubClass = 0xff, | ||
396 | .bInterfaceProtocol = 0xff, | ||
397 | }, | ||
398 | {}, | ||
399 | }; | ||
400 | MODULE_DEVICE_TABLE(usb, i1480u_id_table); | ||
401 | |||
402 | static struct usb_driver i1480u_driver = { | ||
403 | .name = KBUILD_MODNAME, | ||
404 | .probe = i1480u_probe, | ||
405 | .disconnect = i1480u_disconnect, | ||
406 | .id_table = i1480u_id_table, | ||
407 | }; | ||
408 | |||
409 | static int __init i1480u_driver_init(void) | ||
410 | { | ||
411 | return usb_register(&i1480u_driver); | ||
412 | } | ||
413 | module_init(i1480u_driver_init); | ||
414 | |||
415 | |||
416 | static void __exit i1480u_driver_exit(void) | ||
417 | { | ||
418 | usb_deregister(&i1480u_driver); | ||
419 | } | ||
420 | module_exit(i1480u_driver_exit); | ||
421 | |||
422 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
423 | MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB"); | ||
424 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c deleted file mode 100644 index f98f6ce8b9e7..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/netdev.c +++ /dev/null | |||
@@ -1,331 +0,0 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * Implementation of the netdevice linkage (except tx and rx related stuff). | ||
26 | * | ||
27 | * ROADMAP: | ||
28 | * | ||
29 | * ENTRY POINTS (Net device): | ||
30 | * | ||
31 | * i1480u_open(): Called when we ifconfig up the interface; | ||
32 | * associates to a UWB host controller, reserves | ||
33 | * bandwidth (MAS), sets up RX USB URB and starts | ||
34 | * the queue. | ||
35 | * | ||
36 | * i1480u_stop(): Called when we ifconfig down a interface; | ||
37 | * reverses _open(). | ||
38 | * | ||
39 | * i1480u_set_config(): | ||
40 | */ | ||
41 | |||
42 | #include <linux/slab.h> | ||
43 | #include <linux/if_arp.h> | ||
44 | #include <linux/etherdevice.h> | ||
45 | |||
46 | #include "i1480u-wlp.h" | ||
47 | |||
48 | struct i1480u_cmd_set_ip_mas { | ||
49 | struct uwb_rccb rccb; | ||
50 | struct uwb_dev_addr addr; | ||
51 | u8 stream; | ||
52 | u8 owner; | ||
53 | u8 type; /* enum uwb_drp_type */ | ||
54 | u8 baMAS[32]; | ||
55 | } __attribute__((packed)); | ||
56 | |||
57 | |||
58 | static | ||
59 | int i1480u_set_ip_mas( | ||
60 | struct uwb_rc *rc, | ||
61 | const struct uwb_dev_addr *dstaddr, | ||
62 | u8 stream, u8 owner, u8 type, unsigned long *mas) | ||
63 | { | ||
64 | |||
65 | int result; | ||
66 | struct i1480u_cmd_set_ip_mas *cmd; | ||
67 | struct uwb_rc_evt_confirm reply; | ||
68 | |||
69 | result = -ENOMEM; | ||
70 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
71 | if (cmd == NULL) | ||
72 | goto error_kzalloc; | ||
73 | cmd->rccb.bCommandType = 0xfd; | ||
74 | cmd->rccb.wCommand = cpu_to_le16(0x000e); | ||
75 | cmd->addr = *dstaddr; | ||
76 | cmd->stream = stream; | ||
77 | cmd->owner = owner; | ||
78 | cmd->type = type; | ||
79 | if (mas == NULL) | ||
80 | memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS)); | ||
81 | else | ||
82 | memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS)); | ||
83 | reply.rceb.bEventType = 0xfd; | ||
84 | reply.rceb.wEvent = cpu_to_le16(0x000e); | ||
85 | result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd), | ||
86 | &reply.rceb, sizeof(reply)); | ||
87 | if (result < 0) | ||
88 | goto error_cmd; | ||
89 | if (reply.bResultCode != UWB_RC_RES_FAIL) { | ||
90 | dev_err(&rc->uwb_dev.dev, | ||
91 | "SET-IP-MAS: command execution failed: %d\n", | ||
92 | reply.bResultCode); | ||
93 | result = -EIO; | ||
94 | } | ||
95 | error_cmd: | ||
96 | kfree(cmd); | ||
97 | error_kzalloc: | ||
98 | return result; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Inform a WLP interface of a MAS reservation | ||
103 | * | ||
104 | * @rc is assumed refcnted. | ||
105 | */ | ||
106 | /* FIXME: detect if remote device is WLP capable? */ | ||
107 | static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc, | ||
108 | u8 stream, u8 owner, u8 type, unsigned long *mas) | ||
109 | { | ||
110 | int result = 0; | ||
111 | struct device *dev = &rc->uwb_dev.dev; | ||
112 | |||
113 | result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner, | ||
114 | type, mas); | ||
115 | if (result < 0) { | ||
116 | char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE]; | ||
117 | uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf), | ||
118 | &rc->uwb_dev.dev_addr); | ||
119 | uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf), | ||
120 | &uwb_dev->dev_addr); | ||
121 | dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n", | ||
122 | rcaddrbuf, devaddrbuf, result); | ||
123 | } | ||
124 | return result; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * Called by bandwidth allocator when change occurs in reservation. | ||
129 | * | ||
130 | * @rsv: The reservation that is being established, modified, or | ||
131 | * terminated. | ||
132 | * | ||
133 | * When a reservation is established, modified, or terminated the upper layer | ||
134 | * (WLP here) needs set/update the currently available Media Access Slots | ||
135 | * that can be use for IP traffic. | ||
136 | * | ||
137 | * Our action taken during failure depends on how the reservation is being | ||
138 | * changed: | ||
139 | * - if reservation is being established we do nothing if we cannot set the | ||
140 | * new MAS to be used | ||
141 | * - if reservation is being terminated we revert back to PCA whether the | ||
142 | * SET IP MAS command succeeds or not. | ||
143 | */ | ||
144 | void i1480u_bw_alloc_cb(struct uwb_rsv *rsv) | ||
145 | { | ||
146 | int result = 0; | ||
147 | struct i1480u *i1480u = rsv->pal_priv; | ||
148 | struct device *dev = &i1480u->usb_iface->dev; | ||
149 | struct uwb_dev *target_dev = rsv->target.dev; | ||
150 | struct uwb_rc *rc = i1480u->wlp.rc; | ||
151 | u8 stream = rsv->stream; | ||
152 | int type = rsv->type; | ||
153 | int is_owner = rsv->owner == &rc->uwb_dev; | ||
154 | unsigned long *bmp = rsv->mas.bm; | ||
155 | |||
156 | dev_err(dev, "WLP callback called - sending set ip mas\n"); | ||
157 | /*user cannot change options while setting configuration*/ | ||
158 | mutex_lock(&i1480u->options.mutex); | ||
159 | switch (rsv->state) { | ||
160 | case UWB_RSV_STATE_T_ACCEPTED: | ||
161 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
162 | result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, | ||
163 | type, bmp); | ||
164 | if (result < 0) { | ||
165 | dev_err(dev, "MAS reservation failed: %d\n", result); | ||
166 | goto out; | ||
167 | } | ||
168 | if (is_owner) { | ||
169 | wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, | ||
170 | WLP_DRP | stream); | ||
171 | wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0); | ||
172 | } | ||
173 | break; | ||
174 | case UWB_RSV_STATE_NONE: | ||
175 | /* revert back to PCA */ | ||
176 | result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, | ||
177 | type, bmp); | ||
178 | if (result < 0) | ||
179 | dev_err(dev, "MAS reservation failed: %d\n", result); | ||
180 | /* Revert to PCA even though SET IP MAS failed. */ | ||
181 | wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, | ||
182 | i1480u->options.pca_base_priority); | ||
183 | wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1); | ||
184 | break; | ||
185 | default: | ||
186 | dev_err(dev, "unexpected WLP reservation state: %s (%d).\n", | ||
187 | uwb_rsv_state_str(rsv->state), rsv->state); | ||
188 | break; | ||
189 | } | ||
190 | out: | ||
191 | mutex_unlock(&i1480u->options.mutex); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * | ||
197 | * Called on 'ifconfig up' | ||
198 | */ | ||
199 | int i1480u_open(struct net_device *net_dev) | ||
200 | { | ||
201 | int result; | ||
202 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
203 | struct wlp *wlp = &i1480u->wlp; | ||
204 | struct uwb_rc *rc; | ||
205 | struct device *dev = &i1480u->usb_iface->dev; | ||
206 | |||
207 | rc = wlp->rc; | ||
208 | result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */ | ||
209 | if (result < 0) | ||
210 | goto error_rx_setup; | ||
211 | |||
212 | result = uwb_radio_start(&wlp->pal); | ||
213 | if (result < 0) | ||
214 | goto error_radio_start; | ||
215 | |||
216 | netif_wake_queue(net_dev); | ||
217 | #ifdef i1480u_FLOW_CONTROL | ||
218 | result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL); | ||
219 | if (result < 0) { | ||
220 | dev_err(dev, "Can't submit notification URB: %d\n", result); | ||
221 | goto error_notif_urb_submit; | ||
222 | } | ||
223 | #endif | ||
224 | /* Interface is up with an address, now we can create WSS */ | ||
225 | result = wlp_wss_setup(net_dev, &wlp->wss); | ||
226 | if (result < 0) { | ||
227 | dev_err(dev, "Can't create WSS: %d. \n", result); | ||
228 | goto error_wss_setup; | ||
229 | } | ||
230 | return 0; | ||
231 | error_wss_setup: | ||
232 | #ifdef i1480u_FLOW_CONTROL | ||
233 | usb_kill_urb(i1480u->notif_urb); | ||
234 | error_notif_urb_submit: | ||
235 | #endif | ||
236 | uwb_radio_stop(&wlp->pal); | ||
237 | error_radio_start: | ||
238 | netif_stop_queue(net_dev); | ||
239 | i1480u_rx_release(i1480u); | ||
240 | error_rx_setup: | ||
241 | return result; | ||
242 | } | ||
243 | |||
244 | |||
245 | /** | ||
246 | * Called on 'ifconfig down' | ||
247 | */ | ||
248 | int i1480u_stop(struct net_device *net_dev) | ||
249 | { | ||
250 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
251 | struct wlp *wlp = &i1480u->wlp; | ||
252 | |||
253 | BUG_ON(wlp->rc == NULL); | ||
254 | wlp_wss_remove(&wlp->wss); | ||
255 | netif_carrier_off(net_dev); | ||
256 | #ifdef i1480u_FLOW_CONTROL | ||
257 | usb_kill_urb(i1480u->notif_urb); | ||
258 | #endif | ||
259 | netif_stop_queue(net_dev); | ||
260 | uwb_radio_stop(&wlp->pal); | ||
261 | i1480u_rx_release(i1480u); | ||
262 | i1480u_tx_release(i1480u); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * | ||
268 | * Change the interface config--we probably don't have to do anything. | ||
269 | */ | ||
270 | int i1480u_set_config(struct net_device *net_dev, struct ifmap *map) | ||
271 | { | ||
272 | int result; | ||
273 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
274 | BUG_ON(i1480u->wlp.rc == NULL); | ||
275 | result = 0; | ||
276 | return result; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * Change the MTU of the interface | ||
281 | */ | ||
282 | int i1480u_change_mtu(struct net_device *net_dev, int mtu) | ||
283 | { | ||
284 | static union { | ||
285 | struct wlp_tx_hdr tx; | ||
286 | struct wlp_rx_hdr rx; | ||
287 | } i1480u_all_hdrs; | ||
288 | |||
289 | if (mtu < ETH_HLEN) /* We encap eth frames */ | ||
290 | return -ERANGE; | ||
291 | if (mtu > 4000 - sizeof(i1480u_all_hdrs)) | ||
292 | return -ERANGE; | ||
293 | net_dev->mtu = mtu; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * Stop the network queue | ||
299 | * | ||
300 | * Enable WLP substack to stop network queue. We also set the flow control | ||
301 | * threshold at this time to prevent the flow control from restarting the | ||
302 | * queue. | ||
303 | * | ||
304 | * we are loosing the current threshold value here ... FIXME? | ||
305 | */ | ||
306 | void i1480u_stop_queue(struct wlp *wlp) | ||
307 | { | ||
308 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
309 | struct net_device *net_dev = i1480u->net_dev; | ||
310 | i1480u->tx_inflight.threshold = 0; | ||
311 | netif_stop_queue(net_dev); | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * Start the network queue | ||
316 | * | ||
317 | * Enable WLP substack to start network queue. Also re-enable the flow | ||
318 | * control to manage the queue again. | ||
319 | * | ||
320 | * We re-enable the flow control by storing the default threshold in the | ||
321 | * flow control threshold. This means that if the user modified the | ||
322 | * threshold before the queue was stopped and restarted that information | ||
323 | * will be lost. FIXME? | ||
324 | */ | ||
325 | void i1480u_start_queue(struct wlp *wlp) | ||
326 | { | ||
327 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
328 | struct net_device *net_dev = i1480u->net_dev; | ||
329 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | ||
330 | netif_start_queue(net_dev); | ||
331 | } | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c deleted file mode 100644 index d4e51e108aa4..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/rx.c +++ /dev/null | |||
@@ -1,474 +0,0 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * i1480u's RX handling is simple. i1480u will send the received | ||
24 | * network packets broken up in fragments; 1 to N fragments make a | ||
25 | * packet, we assemble them together and deliver the packet with netif_rx(). | ||
26 | * | ||
27 | * Beacuse each USB transfer is a *single* fragment (except when the | ||
28 | * transfer contains a first fragment), each URB called thus | ||
29 | * back contains one or two fragments. So we queue N URBs, each with its own | ||
30 | * fragment buffer. When a URB is done, we process it (adding to the | ||
31 | * current skb from the fragment buffer until complete). Once | ||
32 | * processed, we requeue the URB. There is always a bunch of URBs | ||
33 | * ready to take data, so the intergap should be minimal. | ||
34 | * | ||
35 | * An URB's transfer buffer is the data field of a socket buffer. This | ||
36 | * reduces copying as data can be passed directly to network layer. If a | ||
37 | * complete packet or 1st fragment is received the URB's transfer buffer is | ||
38 | * taken away from it and used to send data to the network layer. In this | ||
39 | * case a new transfer buffer is allocated to the URB before being requeued. | ||
40 | * If a "NEXT" or "LAST" fragment is received, the fragment contents is | ||
41 | * appended to the RX packet under construction and the transfer buffer | ||
42 | * is reused. To be able to use this buffer to assemble complete packets | ||
43 | * we set each buffer's size to that of the MAX ethernet packet that can | ||
44 | * be received. There is thus room for improvement in memory usage. | ||
45 | * | ||
46 | * When the max tx fragment size increases, we should be able to read | ||
47 | * data into the skbs directly with very simple code. | ||
48 | * | ||
49 | * ROADMAP: | ||
50 | * | ||
51 | * ENTRY POINTS: | ||
52 | * | ||
53 | * i1480u_rx_setup(): setup RX context [from i1480u_open()] | ||
54 | * | ||
55 | * i1480u_rx_release(): release RX context [from i1480u_stop()] | ||
56 | * | ||
57 | * i1480u_rx_cb(): called when the RX USB URB receives a | ||
58 | * packet. It removes the header and pushes it up | ||
59 | * the Linux netdev stack with netif_rx(). | ||
60 | * | ||
61 | * i1480u_rx_buffer() | ||
62 | * i1480u_drop() and i1480u_fix() | ||
63 | * i1480u_skb_deliver | ||
64 | * | ||
65 | */ | ||
66 | |||
67 | #include <linux/gfp.h> | ||
68 | #include <linux/netdevice.h> | ||
69 | #include <linux/etherdevice.h> | ||
70 | #include "i1480u-wlp.h" | ||
71 | |||
72 | /* | ||
73 | * Setup the RX context | ||
74 | * | ||
75 | * Each URB is provided with a transfer_buffer that is the data field | ||
76 | * of a new socket buffer. | ||
77 | */ | ||
78 | int i1480u_rx_setup(struct i1480u *i1480u) | ||
79 | { | ||
80 | int result, cnt; | ||
81 | struct device *dev = &i1480u->usb_iface->dev; | ||
82 | struct net_device *net_dev = i1480u->net_dev; | ||
83 | struct usb_endpoint_descriptor *epd; | ||
84 | struct sk_buff *skb; | ||
85 | |||
86 | /* Alloc RX stuff */ | ||
87 | i1480u->rx_skb = NULL; /* not in process of receiving packet */ | ||
88 | result = -ENOMEM; | ||
89 | epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc; | ||
90 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
91 | struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt]; | ||
92 | rx_buf->i1480u = i1480u; | ||
93 | skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); | ||
94 | if (!skb) { | ||
95 | dev_err(dev, | ||
96 | "RX: cannot allocate RX buffer %d\n", cnt); | ||
97 | result = -ENOMEM; | ||
98 | goto error; | ||
99 | } | ||
100 | skb->dev = net_dev; | ||
101 | skb->ip_summed = CHECKSUM_NONE; | ||
102 | skb_reserve(skb, 2); | ||
103 | rx_buf->data = skb; | ||
104 | rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
105 | if (unlikely(rx_buf->urb == NULL)) { | ||
106 | dev_err(dev, "RX: cannot allocate URB %d\n", cnt); | ||
107 | result = -ENOMEM; | ||
108 | goto error; | ||
109 | } | ||
110 | usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev, | ||
111 | usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress), | ||
112 | rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2, | ||
113 | i1480u_rx_cb, rx_buf); | ||
114 | result = usb_submit_urb(rx_buf->urb, GFP_NOIO); | ||
115 | if (unlikely(result < 0)) { | ||
116 | dev_err(dev, "RX: cannot submit URB %d: %d\n", | ||
117 | cnt, result); | ||
118 | goto error; | ||
119 | } | ||
120 | } | ||
121 | return 0; | ||
122 | |||
123 | error: | ||
124 | i1480u_rx_release(i1480u); | ||
125 | return result; | ||
126 | } | ||
127 | |||
128 | |||
129 | /* Release resources associated to the rx context */ | ||
130 | void i1480u_rx_release(struct i1480u *i1480u) | ||
131 | { | ||
132 | int cnt; | ||
133 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
134 | if (i1480u->rx_buf[cnt].data) | ||
135 | dev_kfree_skb(i1480u->rx_buf[cnt].data); | ||
136 | if (i1480u->rx_buf[cnt].urb) { | ||
137 | usb_kill_urb(i1480u->rx_buf[cnt].urb); | ||
138 | usb_free_urb(i1480u->rx_buf[cnt].urb); | ||
139 | } | ||
140 | } | ||
141 | if (i1480u->rx_skb != NULL) | ||
142 | dev_kfree_skb(i1480u->rx_skb); | ||
143 | } | ||
144 | |||
145 | static | ||
146 | void i1480u_rx_unlink_urbs(struct i1480u *i1480u) | ||
147 | { | ||
148 | int cnt; | ||
149 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
150 | if (i1480u->rx_buf[cnt].urb) | ||
151 | usb_unlink_urb(i1480u->rx_buf[cnt].urb); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /* Fix an out-of-sequence packet */ | ||
156 | #define i1480u_fix(i1480u, msg...) \ | ||
157 | do { \ | ||
158 | if (printk_ratelimit()) \ | ||
159 | dev_err(&i1480u->usb_iface->dev, msg); \ | ||
160 | dev_kfree_skb_irq(i1480u->rx_skb); \ | ||
161 | i1480u->rx_skb = NULL; \ | ||
162 | i1480u->rx_untd_pkt_size = 0; \ | ||
163 | } while (0) | ||
164 | |||
165 | |||
166 | /* Drop an out-of-sequence packet */ | ||
167 | #define i1480u_drop(i1480u, msg...) \ | ||
168 | do { \ | ||
169 | if (printk_ratelimit()) \ | ||
170 | dev_err(&i1480u->usb_iface->dev, msg); \ | ||
171 | i1480u->net_dev->stats.rx_dropped++; \ | ||
172 | } while (0) | ||
173 | |||
174 | |||
175 | |||
176 | |||
177 | /* Finalizes setting up the SKB and delivers it | ||
178 | * | ||
179 | * We first pass the incoming frame to WLP substack for verification. It | ||
180 | * may also be a WLP association frame in which case WLP will take over the | ||
181 | * processing. If WLP does not take it over it will still verify it, if the | ||
182 | * frame is invalid the skb will be freed by WLP and we will not continue | ||
183 | * parsing. | ||
184 | * */ | ||
185 | static | ||
186 | void i1480u_skb_deliver(struct i1480u *i1480u) | ||
187 | { | ||
188 | int should_parse; | ||
189 | struct net_device *net_dev = i1480u->net_dev; | ||
190 | struct device *dev = &i1480u->usb_iface->dev; | ||
191 | |||
192 | should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb, | ||
193 | &i1480u->rx_srcaddr); | ||
194 | if (!should_parse) | ||
195 | goto out; | ||
196 | i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev); | ||
197 | net_dev->stats.rx_packets++; | ||
198 | net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size; | ||
199 | |||
200 | netif_rx(i1480u->rx_skb); /* deliver */ | ||
201 | out: | ||
202 | i1480u->rx_skb = NULL; | ||
203 | i1480u->rx_untd_pkt_size = 0; | ||
204 | } | ||
205 | |||
206 | |||
207 | /* | ||
208 | * Process a buffer of data received from the USB RX endpoint | ||
209 | * | ||
210 | * First fragment arrives with next or last fragment. All other fragments | ||
211 | * arrive alone. | ||
212 | * | ||
213 | * /me hates long functions. | ||
214 | */ | ||
215 | static | ||
216 | void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf) | ||
217 | { | ||
218 | unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */ | ||
219 | size_t untd_hdr_size, untd_frg_size; | ||
220 | size_t i1480u_hdr_size; | ||
221 | struct wlp_rx_hdr *i1480u_hdr = NULL; | ||
222 | |||
223 | struct i1480u *i1480u = rx_buf->i1480u; | ||
224 | struct sk_buff *skb = rx_buf->data; | ||
225 | int size_left = rx_buf->urb->actual_length; | ||
226 | void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */ | ||
227 | struct untd_hdr *untd_hdr; | ||
228 | |||
229 | struct net_device *net_dev = i1480u->net_dev; | ||
230 | struct device *dev = &i1480u->usb_iface->dev; | ||
231 | struct sk_buff *new_skb; | ||
232 | |||
233 | #if 0 | ||
234 | dev_fnstart(dev, | ||
235 | "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left); | ||
236 | dev_err(dev, "RX packet, %zu bytes\n", size_left); | ||
237 | dump_bytes(dev, ptr, size_left); | ||
238 | #endif | ||
239 | i1480u_hdr_size = sizeof(struct wlp_rx_hdr); | ||
240 | |||
241 | while (size_left > 0) { | ||
242 | if (pkt_completed) { | ||
243 | i1480u_drop(i1480u, "RX: fragment follows completed" | ||
244 | "packet in same buffer. Dropping\n"); | ||
245 | break; | ||
246 | } | ||
247 | untd_hdr = ptr; | ||
248 | if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */ | ||
249 | i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n"); | ||
250 | goto out; | ||
251 | } | ||
252 | if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */ | ||
253 | i1480u_drop(i1480u, "RX: TX bit set! Dropping\n"); | ||
254 | goto out; | ||
255 | } | ||
256 | switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */ | ||
257 | case i1480u_PKT_FRAG_1ST: { | ||
258 | struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr; | ||
259 | dev_dbg(dev, "1st fragment\n"); | ||
260 | untd_hdr_size = sizeof(struct untd_hdr_1st); | ||
261 | if (i1480u->rx_skb != NULL) | ||
262 | i1480u_fix(i1480u, "RX: 1st fragment out of " | ||
263 | "sequence! Fixing\n"); | ||
264 | if (size_left < untd_hdr_size + i1480u_hdr_size) { | ||
265 | i1480u_drop(i1480u, "RX: short 1st fragment! " | ||
266 | "Dropping\n"); | ||
267 | goto out; | ||
268 | } | ||
269 | i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len) | ||
270 | - i1480u_hdr_size; | ||
271 | untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len); | ||
272 | if (size_left < untd_hdr_size + untd_frg_size) { | ||
273 | i1480u_drop(i1480u, | ||
274 | "RX: short payload! Dropping\n"); | ||
275 | goto out; | ||
276 | } | ||
277 | i1480u->rx_skb = skb; | ||
278 | i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size; | ||
279 | i1480u->rx_srcaddr = i1480u_hdr->srcaddr; | ||
280 | skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size); | ||
281 | skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); | ||
282 | stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); | ||
283 | stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); | ||
284 | rx_buf->data = NULL; /* need to create new buffer */ | ||
285 | break; | ||
286 | } | ||
287 | case i1480u_PKT_FRAG_NXT: { | ||
288 | dev_dbg(dev, "nxt fragment\n"); | ||
289 | untd_hdr_size = sizeof(struct untd_hdr_rst); | ||
290 | if (i1480u->rx_skb == NULL) { | ||
291 | i1480u_drop(i1480u, "RX: next fragment out of " | ||
292 | "sequence! Dropping\n"); | ||
293 | goto out; | ||
294 | } | ||
295 | if (size_left < untd_hdr_size) { | ||
296 | i1480u_drop(i1480u, "RX: short NXT fragment! " | ||
297 | "Dropping\n"); | ||
298 | goto out; | ||
299 | } | ||
300 | untd_frg_size = le16_to_cpu(untd_hdr->len); | ||
301 | if (size_left < untd_hdr_size + untd_frg_size) { | ||
302 | i1480u_drop(i1480u, | ||
303 | "RX: short payload! Dropping\n"); | ||
304 | goto out; | ||
305 | } | ||
306 | memmove(skb_put(i1480u->rx_skb, untd_frg_size), | ||
307 | ptr + untd_hdr_size, untd_frg_size); | ||
308 | break; | ||
309 | } | ||
310 | case i1480u_PKT_FRAG_LST: { | ||
311 | dev_dbg(dev, "Lst fragment\n"); | ||
312 | untd_hdr_size = sizeof(struct untd_hdr_rst); | ||
313 | if (i1480u->rx_skb == NULL) { | ||
314 | i1480u_drop(i1480u, "RX: last fragment out of " | ||
315 | "sequence! Dropping\n"); | ||
316 | goto out; | ||
317 | } | ||
318 | if (size_left < untd_hdr_size) { | ||
319 | i1480u_drop(i1480u, "RX: short LST fragment! " | ||
320 | "Dropping\n"); | ||
321 | goto out; | ||
322 | } | ||
323 | untd_frg_size = le16_to_cpu(untd_hdr->len); | ||
324 | if (size_left < untd_frg_size + untd_hdr_size) { | ||
325 | i1480u_drop(i1480u, | ||
326 | "RX: short payload! Dropping\n"); | ||
327 | goto out; | ||
328 | } | ||
329 | memmove(skb_put(i1480u->rx_skb, untd_frg_size), | ||
330 | ptr + untd_hdr_size, untd_frg_size); | ||
331 | pkt_completed = 1; | ||
332 | break; | ||
333 | } | ||
334 | case i1480u_PKT_FRAG_CMP: { | ||
335 | dev_dbg(dev, "cmp fragment\n"); | ||
336 | untd_hdr_size = sizeof(struct untd_hdr_cmp); | ||
337 | if (i1480u->rx_skb != NULL) | ||
338 | i1480u_fix(i1480u, "RX: fix out-of-sequence CMP" | ||
339 | " fragment!\n"); | ||
340 | if (size_left < untd_hdr_size + i1480u_hdr_size) { | ||
341 | i1480u_drop(i1480u, "RX: short CMP fragment! " | ||
342 | "Dropping\n"); | ||
343 | goto out; | ||
344 | } | ||
345 | i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len); | ||
346 | untd_frg_size = i1480u->rx_untd_pkt_size; | ||
347 | if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) { | ||
348 | i1480u_drop(i1480u, | ||
349 | "RX: short payload! Dropping\n"); | ||
350 | goto out; | ||
351 | } | ||
352 | i1480u->rx_skb = skb; | ||
353 | i1480u_hdr = (void *) untd_hdr + untd_hdr_size; | ||
354 | i1480u->rx_srcaddr = i1480u_hdr->srcaddr; | ||
355 | stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); | ||
356 | stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); | ||
357 | skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size); | ||
358 | skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); | ||
359 | rx_buf->data = NULL; /* for hand off skb to network stack */ | ||
360 | pkt_completed = 1; | ||
361 | i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */ | ||
362 | break; | ||
363 | } | ||
364 | default: | ||
365 | i1480u_drop(i1480u, "RX: unknown packet type %u! " | ||
366 | "Dropping\n", untd_hdr_type(untd_hdr)); | ||
367 | goto out; | ||
368 | } | ||
369 | size_left -= untd_hdr_size + untd_frg_size; | ||
370 | if (size_left > 0) | ||
371 | ptr += untd_hdr_size + untd_frg_size; | ||
372 | } | ||
373 | if (pkt_completed) | ||
374 | i1480u_skb_deliver(i1480u); | ||
375 | out: | ||
376 | /* recreate needed RX buffers*/ | ||
377 | if (rx_buf->data == NULL) { | ||
378 | /* buffer is being used to receive packet, create new */ | ||
379 | new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); | ||
380 | if (!new_skb) { | ||
381 | if (printk_ratelimit()) | ||
382 | dev_err(dev, | ||
383 | "RX: cannot allocate RX buffer\n"); | ||
384 | } else { | ||
385 | new_skb->dev = net_dev; | ||
386 | new_skb->ip_summed = CHECKSUM_NONE; | ||
387 | skb_reserve(new_skb, 2); | ||
388 | rx_buf->data = new_skb; | ||
389 | } | ||
390 | } | ||
391 | return; | ||
392 | } | ||
393 | |||
394 | |||
395 | /* | ||
396 | * Called when an RX URB has finished receiving or has found some kind | ||
397 | * of error condition. | ||
398 | * | ||
399 | * LIMITATIONS: | ||
400 | * | ||
401 | * - We read USB-transfers, each transfer contains a SINGLE fragment | ||
402 | * (can contain a complete packet, or a 1st, next, or last fragment | ||
403 | * of a packet). | ||
404 | * Looks like a transfer can contain more than one fragment (07/18/06) | ||
405 | * | ||
406 | * - Each transfer buffer is the size of the maximum packet size (minus | ||
407 | * headroom), i1480u_MAX_PKT_SIZE - 2 | ||
408 | * | ||
409 | * - We always read the full USB-transfer, no partials. | ||
410 | * | ||
411 | * - Each transfer is read directly into a skb. This skb will be used to | ||
412 | * send data to the upper layers if it is the first fragment or a complete | ||
413 | * packet. In the other cases the data will be copied from the skb to | ||
414 | * another skb that is being prepared for the upper layers from a prev | ||
415 | * first fragment. | ||
416 | * | ||
417 | * It is simply too much of a pain. Gosh, there should be a unified | ||
418 | * SG infrastructure for *everything* [so that I could declare a SG | ||
419 | * buffer, pass it to USB for receiving, append some space to it if | ||
420 | * I wish, receive more until I have the whole chunk, adapt | ||
421 | * pointers on each fragment to remove hardware headers and then | ||
422 | * attach that to an skbuff and netif_rx()]. | ||
423 | */ | ||
424 | void i1480u_rx_cb(struct urb *urb) | ||
425 | { | ||
426 | int result; | ||
427 | int do_parse_buffer = 1; | ||
428 | struct i1480u_rx_buf *rx_buf = urb->context; | ||
429 | struct i1480u *i1480u = rx_buf->i1480u; | ||
430 | struct device *dev = &i1480u->usb_iface->dev; | ||
431 | unsigned long flags; | ||
432 | u8 rx_buf_idx = rx_buf - i1480u->rx_buf; | ||
433 | |||
434 | switch (urb->status) { | ||
435 | case 0: | ||
436 | break; | ||
437 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
438 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
439 | case -ESHUTDOWN: /* going away! */ | ||
440 | dev_err(dev, "RX URB[%u]: goind down %d\n", | ||
441 | rx_buf_idx, urb->status); | ||
442 | goto error; | ||
443 | default: | ||
444 | dev_err(dev, "RX URB[%u]: unknown status %d\n", | ||
445 | rx_buf_idx, urb->status); | ||
446 | if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS, | ||
447 | EDC_ERROR_TIMEFRAME)) { | ||
448 | dev_err(dev, "RX: max acceptable errors exceeded," | ||
449 | " resetting device.\n"); | ||
450 | i1480u_rx_unlink_urbs(i1480u); | ||
451 | wlp_reset_all(&i1480u->wlp); | ||
452 | goto error; | ||
453 | } | ||
454 | do_parse_buffer = 0; | ||
455 | break; | ||
456 | } | ||
457 | spin_lock_irqsave(&i1480u->lock, flags); | ||
458 | /* chew the data fragments, extract network packets */ | ||
459 | if (do_parse_buffer) { | ||
460 | i1480u_rx_buffer(rx_buf); | ||
461 | if (rx_buf->data) { | ||
462 | rx_buf->urb->transfer_buffer = rx_buf->data->data; | ||
463 | result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC); | ||
464 | if (result < 0) { | ||
465 | dev_err(dev, "RX URB[%u]: cannot submit %d\n", | ||
466 | rx_buf_idx, result); | ||
467 | } | ||
468 | } | ||
469 | } | ||
470 | spin_unlock_irqrestore(&i1480u->lock, flags); | ||
471 | error: | ||
472 | return; | ||
473 | } | ||
474 | |||
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c deleted file mode 100644 index 4ffaf546cc6c..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/sysfs.c +++ /dev/null | |||
@@ -1,407 +0,0 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Sysfs interfaces | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/device.h> | ||
29 | |||
30 | #include "i1480u-wlp.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * | ||
35 | * @dev: Class device from the net_device; assumed refcnted. | ||
36 | * | ||
37 | * Yes, I don't lock--we assume it is refcounted and I am getting a | ||
38 | * single byte value that is kind of atomic to read. | ||
39 | */ | ||
40 | ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf) | ||
41 | { | ||
42 | return sprintf(buf, "%u\n", | ||
43 | wlp_tx_hdr_phy_rate(&options->def_tx_hdr)); | ||
44 | } | ||
45 | EXPORT_SYMBOL_GPL(uwb_phy_rate_show); | ||
46 | |||
47 | |||
48 | ssize_t uwb_phy_rate_store(struct wlp_options *options, | ||
49 | const char *buf, size_t size) | ||
50 | { | ||
51 | ssize_t result; | ||
52 | unsigned rate; | ||
53 | |||
54 | result = sscanf(buf, "%u\n", &rate); | ||
55 | if (result != 1) { | ||
56 | result = -EINVAL; | ||
57 | goto out; | ||
58 | } | ||
59 | result = -EINVAL; | ||
60 | if (rate >= UWB_PHY_RATE_INVALID) | ||
61 | goto out; | ||
62 | wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate); | ||
63 | result = 0; | ||
64 | out: | ||
65 | return result < 0 ? result : size; | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(uwb_phy_rate_store); | ||
68 | |||
69 | |||
70 | ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf) | ||
71 | { | ||
72 | return sprintf(buf, "%u\n", | ||
73 | wlp_tx_hdr_rts_cts(&options->def_tx_hdr)); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(uwb_rts_cts_show); | ||
76 | |||
77 | |||
78 | ssize_t uwb_rts_cts_store(struct wlp_options *options, | ||
79 | const char *buf, size_t size) | ||
80 | { | ||
81 | ssize_t result; | ||
82 | unsigned value; | ||
83 | |||
84 | result = sscanf(buf, "%u\n", &value); | ||
85 | if (result != 1) { | ||
86 | result = -EINVAL; | ||
87 | goto out; | ||
88 | } | ||
89 | result = -EINVAL; | ||
90 | wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value); | ||
91 | result = 0; | ||
92 | out: | ||
93 | return result < 0 ? result : size; | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(uwb_rts_cts_store); | ||
96 | |||
97 | |||
98 | ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf) | ||
99 | { | ||
100 | return sprintf(buf, "%u\n", | ||
101 | wlp_tx_hdr_ack_policy(&options->def_tx_hdr)); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(uwb_ack_policy_show); | ||
104 | |||
105 | |||
106 | ssize_t uwb_ack_policy_store(struct wlp_options *options, | ||
107 | const char *buf, size_t size) | ||
108 | { | ||
109 | ssize_t result; | ||
110 | unsigned value; | ||
111 | |||
112 | result = sscanf(buf, "%u\n", &value); | ||
113 | if (result != 1 || value > UWB_ACK_B_REQ) { | ||
114 | result = -EINVAL; | ||
115 | goto out; | ||
116 | } | ||
117 | wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value); | ||
118 | result = 0; | ||
119 | out: | ||
120 | return result < 0 ? result : size; | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(uwb_ack_policy_store); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Show the PCA base priority. | ||
127 | * | ||
128 | * We can access without locking, as the value is (for now) orthogonal | ||
129 | * to other values. | ||
130 | */ | ||
131 | ssize_t uwb_pca_base_priority_show(const struct wlp_options *options, | ||
132 | char *buf) | ||
133 | { | ||
134 | return sprintf(buf, "%u\n", | ||
135 | options->pca_base_priority); | ||
136 | } | ||
137 | EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show); | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Set the PCA base priority. | ||
142 | * | ||
143 | * We can access without locking, as the value is (for now) orthogonal | ||
144 | * to other values. | ||
145 | */ | ||
146 | ssize_t uwb_pca_base_priority_store(struct wlp_options *options, | ||
147 | const char *buf, size_t size) | ||
148 | { | ||
149 | ssize_t result = -EINVAL; | ||
150 | u8 pca_base_priority; | ||
151 | |||
152 | result = sscanf(buf, "%hhu\n", &pca_base_priority); | ||
153 | if (result != 1) { | ||
154 | result = -EINVAL; | ||
155 | goto out; | ||
156 | } | ||
157 | result = -EINVAL; | ||
158 | if (pca_base_priority >= 8) | ||
159 | goto out; | ||
160 | options->pca_base_priority = pca_base_priority; | ||
161 | /* Update TX header if we are currently using PCA. */ | ||
162 | if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0) | ||
163 | wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority); | ||
164 | result = 0; | ||
165 | out: | ||
166 | return result < 0 ? result : size; | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store); | ||
169 | |||
170 | /** | ||
171 | * Show current inflight values | ||
172 | * | ||
173 | * Will print the current MAX and THRESHOLD values for the basic flow | ||
174 | * control. In addition it will report how many times the TX queue needed | ||
175 | * to be restarted since the last time this query was made. | ||
176 | */ | ||
177 | static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight, | ||
178 | char *buf) | ||
179 | { | ||
180 | ssize_t result; | ||
181 | unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ; | ||
182 | unsigned long restart_count = atomic_read(&inflight->restart_count); | ||
183 | |||
184 | result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n" | ||
185 | "#read: threshold max inflight_count restarts " | ||
186 | "seconds restarts/sec\n" | ||
187 | "#write: threshold max\n", | ||
188 | inflight->threshold, inflight->max, | ||
189 | atomic_read(&inflight->count), | ||
190 | restart_count, sec_elapsed, | ||
191 | sec_elapsed == 0 ? 0 : restart_count/sec_elapsed); | ||
192 | inflight->restart_ts = jiffies; | ||
193 | atomic_set(&inflight->restart_count, 0); | ||
194 | return result; | ||
195 | } | ||
196 | |||
197 | static | ||
198 | ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight, | ||
199 | const char *buf, size_t size) | ||
200 | { | ||
201 | unsigned long in_threshold, in_max; | ||
202 | ssize_t result; | ||
203 | result = sscanf(buf, "%lu %lu", &in_threshold, &in_max); | ||
204 | if (result != 2) | ||
205 | return -EINVAL; | ||
206 | if (in_max <= in_threshold) | ||
207 | return -EINVAL; | ||
208 | inflight->max = in_max; | ||
209 | inflight->threshold = in_threshold; | ||
210 | return size; | ||
211 | } | ||
212 | /* | ||
213 | * Glue (or function adaptors) for accesing info on sysfs | ||
214 | * | ||
215 | * [we need this indirection because the PCI driver does almost the | ||
216 | * same] | ||
217 | * | ||
218 | * Linux 2.6.21 changed how 'struct netdevice' does attributes (from | ||
219 | * having a 'struct class_dev' to having a 'struct device'). That is | ||
220 | * quite of a pain. | ||
221 | * | ||
222 | * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE() | ||
223 | * create adaptors for extracting the 'struct i1480u' from a 'struct | ||
224 | * dev' and calling a function for doing a sysfs operation (as we have | ||
225 | * them factorized already). i1480u_ATTR creates the attribute file | ||
226 | * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a | ||
227 | * class_device_attr_NAME or device_attr_NAME (for group registration). | ||
228 | */ | ||
229 | |||
230 | #define i1480u_SHOW(name, fn, param) \ | ||
231 | static ssize_t i1480u_show_##name(struct device *dev, \ | ||
232 | struct device_attribute *attr,\ | ||
233 | char *buf) \ | ||
234 | { \ | ||
235 | struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ | ||
236 | return fn(&i1480u->param, buf); \ | ||
237 | } | ||
238 | |||
239 | #define i1480u_STORE(name, fn, param) \ | ||
240 | static ssize_t i1480u_store_##name(struct device *dev, \ | ||
241 | struct device_attribute *attr,\ | ||
242 | const char *buf, size_t size)\ | ||
243 | { \ | ||
244 | struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ | ||
245 | return fn(&i1480u->param, buf, size); \ | ||
246 | } | ||
247 | |||
248 | #define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \ | ||
249 | i1480u_show_##name,\ | ||
250 | i1480u_store_##name) | ||
251 | |||
252 | #define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \ | ||
253 | S_IRUGO, \ | ||
254 | i1480u_show_##name, NULL) | ||
255 | |||
256 | #define i1480u_ATTR_NAME(a) (dev_attr_##a) | ||
257 | |||
258 | |||
259 | /* | ||
260 | * Sysfs adaptors | ||
261 | */ | ||
262 | i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options); | ||
263 | i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options); | ||
264 | i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR); | ||
265 | |||
266 | i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options); | ||
267 | i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options); | ||
268 | i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR); | ||
269 | |||
270 | i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options); | ||
271 | i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options); | ||
272 | i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR); | ||
273 | |||
274 | i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options); | ||
275 | i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options); | ||
276 | i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR); | ||
277 | |||
278 | i1480u_SHOW(wlp_eda, wlp_eda_show, wlp); | ||
279 | i1480u_STORE(wlp_eda, wlp_eda_store, wlp); | ||
280 | i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR); | ||
281 | |||
282 | i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp); | ||
283 | i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp); | ||
284 | i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR); | ||
285 | |||
286 | i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp); | ||
287 | i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp); | ||
288 | i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR); | ||
289 | |||
290 | i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp); | ||
291 | i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp); | ||
292 | i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR); | ||
293 | |||
294 | i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp); | ||
295 | i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp); | ||
296 | i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR); | ||
297 | |||
298 | i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp); | ||
299 | i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp); | ||
300 | i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR); | ||
301 | |||
302 | i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp); | ||
303 | i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp); | ||
304 | i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR); | ||
305 | |||
306 | i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp); | ||
307 | i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp); | ||
308 | i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR); | ||
309 | |||
310 | i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp); | ||
311 | i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp); | ||
312 | i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR); | ||
313 | |||
314 | i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp); | ||
315 | i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp); | ||
316 | i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR); | ||
317 | |||
318 | i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp); | ||
319 | i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp); | ||
320 | i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR); | ||
321 | |||
322 | i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp); | ||
323 | i1480u_ATTR_SHOW(wlp_neighborhood); | ||
324 | |||
325 | i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss); | ||
326 | i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss); | ||
327 | i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR); | ||
328 | |||
329 | /* | ||
330 | * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over | ||
331 | * the last 256 received WLP frames (ECMA-368 13.3). | ||
332 | * | ||
333 | * [the -7dB that have to be substracted from the LQI to make the LQE | ||
334 | * are already taken into account]. | ||
335 | */ | ||
336 | i1480u_SHOW(wlp_lqe, stats_show, lqe_stats); | ||
337 | i1480u_STORE(wlp_lqe, stats_store, lqe_stats); | ||
338 | i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR); | ||
339 | |||
340 | /* | ||
341 | * Show the Receive Signal Strength Indicator averaged over all the | ||
342 | * received WLP frames (ECMA-368 13.3). Still is not clear what | ||
343 | * this value is, but is kind of a percentage of the signal strength | ||
344 | * at the antenna. | ||
345 | */ | ||
346 | i1480u_SHOW(wlp_rssi, stats_show, rssi_stats); | ||
347 | i1480u_STORE(wlp_rssi, stats_store, rssi_stats); | ||
348 | i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR); | ||
349 | |||
350 | /** | ||
351 | * We maintain a basic flow control counter. "count" how many TX URBs are | ||
352 | * outstanding. Only allow "max" | ||
353 | * TX URBs to be outstanding. If this value is reached the queue will be | ||
354 | * stopped. The queue will be restarted when there are | ||
355 | * "threshold" URBs outstanding. | ||
356 | */ | ||
357 | i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight); | ||
358 | i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight); | ||
359 | i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR); | ||
360 | |||
361 | static struct attribute *i1480u_attrs[] = { | ||
362 | &i1480u_ATTR_NAME(uwb_phy_rate).attr, | ||
363 | &i1480u_ATTR_NAME(uwb_rts_cts).attr, | ||
364 | &i1480u_ATTR_NAME(uwb_ack_policy).attr, | ||
365 | &i1480u_ATTR_NAME(uwb_pca_base_priority).attr, | ||
366 | &i1480u_ATTR_NAME(wlp_lqe).attr, | ||
367 | &i1480u_ATTR_NAME(wlp_rssi).attr, | ||
368 | &i1480u_ATTR_NAME(wlp_eda).attr, | ||
369 | &i1480u_ATTR_NAME(wlp_uuid).attr, | ||
370 | &i1480u_ATTR_NAME(wlp_dev_name).attr, | ||
371 | &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr, | ||
372 | &i1480u_ATTR_NAME(wlp_dev_model_name).attr, | ||
373 | &i1480u_ATTR_NAME(wlp_dev_model_nr).attr, | ||
374 | &i1480u_ATTR_NAME(wlp_dev_serial).attr, | ||
375 | &i1480u_ATTR_NAME(wlp_dev_prim_category).attr, | ||
376 | &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr, | ||
377 | &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr, | ||
378 | &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr, | ||
379 | &i1480u_ATTR_NAME(wlp_neighborhood).attr, | ||
380 | &i1480u_ATTR_NAME(wss_activate).attr, | ||
381 | &i1480u_ATTR_NAME(wlp_tx_inflight).attr, | ||
382 | NULL, | ||
383 | }; | ||
384 | |||
385 | static struct attribute_group i1480u_attr_group = { | ||
386 | .name = NULL, /* we want them in the same directory */ | ||
387 | .attrs = i1480u_attrs, | ||
388 | }; | ||
389 | |||
390 | int i1480u_sysfs_setup(struct i1480u *i1480u) | ||
391 | { | ||
392 | int result; | ||
393 | struct device *dev = &i1480u->usb_iface->dev; | ||
394 | result = sysfs_create_group(&i1480u->net_dev->dev.kobj, | ||
395 | &i1480u_attr_group); | ||
396 | if (result < 0) | ||
397 | dev_err(dev, "cannot initialize sysfs attributes: %d\n", | ||
398 | result); | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | |||
403 | void i1480u_sysfs_release(struct i1480u *i1480u) | ||
404 | { | ||
405 | sysfs_remove_group(&i1480u->net_dev->dev.kobj, | ||
406 | &i1480u_attr_group); | ||
407 | } | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c deleted file mode 100644 index 3c117a364564..000000000000 --- a/drivers/uwb/i1480/i1480u-wlp/tx.c +++ /dev/null | |||
@@ -1,584 +0,0 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Deal with TX (massaging data to transmit, handling it) | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Transmission engine. Get an skb, create from that a WLP transmit | ||
24 | * context, add a WLP TX header (which we keep prefilled in the | ||
25 | * device's instance), fill out the target-specific fields and | ||
26 | * fire it. | ||
27 | * | ||
28 | * ROADMAP: | ||
29 | * | ||
30 | * Entry points: | ||
31 | * | ||
32 | * i1480u_tx_release(): called by i1480u_disconnect() to release | ||
33 | * pending tx contexts. | ||
34 | * | ||
35 | * i1480u_tx_cb(): callback for TX contexts (USB URBs) | ||
36 | * i1480u_tx_destroy(): | ||
37 | * | ||
38 | * i1480u_tx_timeout(): called for timeout handling from the | ||
39 | * network stack. | ||
40 | * | ||
41 | * i1480u_hard_start_xmit(): called for transmitting an skb from | ||
42 | * the network stack. Will interact with WLP | ||
43 | * substack to verify and prepare frame. | ||
44 | * i1480u_xmit_frame(): actual transmission on hardware | ||
45 | * | ||
46 | * i1480u_tx_create() Creates TX context | ||
47 | * i1480u_tx_create_1() For packets in 1 fragment | ||
48 | * i1480u_tx_create_n() For packets in >1 fragments | ||
49 | * | ||
50 | * TODO: | ||
51 | * | ||
52 | * - FIXME: rewrite using usb_sg_*(), add asynch support to | ||
53 | * usb_sg_*(). It might not make too much sense as most of | ||
54 | * the times the MTU will be smaller than one page... | ||
55 | */ | ||
56 | |||
57 | #include <linux/slab.h> | ||
58 | #include "i1480u-wlp.h" | ||
59 | |||
60 | enum { | ||
61 | /* This is only for Next and Last TX packets */ | ||
62 | i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE | ||
63 | - sizeof(struct untd_hdr_rst), | ||
64 | }; | ||
65 | |||
66 | /* Free resources allocated to a i1480u tx context. */ | ||
67 | static | ||
68 | void i1480u_tx_free(struct i1480u_tx *wtx) | ||
69 | { | ||
70 | kfree(wtx->buf); | ||
71 | if (wtx->skb) | ||
72 | dev_kfree_skb_irq(wtx->skb); | ||
73 | usb_free_urb(wtx->urb); | ||
74 | kfree(wtx); | ||
75 | } | ||
76 | |||
77 | static | ||
78 | void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx) | ||
79 | { | ||
80 | unsigned long flags; | ||
81 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); /* not active any more */ | ||
82 | list_del(&wtx->list_node); | ||
83 | i1480u_tx_free(wtx); | ||
84 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
85 | } | ||
86 | |||
87 | static | ||
88 | void i1480u_tx_unlink_urbs(struct i1480u *i1480u) | ||
89 | { | ||
90 | unsigned long flags; | ||
91 | struct i1480u_tx *wtx, *next; | ||
92 | |||
93 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
94 | list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { | ||
95 | usb_unlink_urb(wtx->urb); | ||
96 | } | ||
97 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
98 | } | ||
99 | |||
100 | |||
101 | /* | ||
102 | * Callback for a completed tx USB URB. | ||
103 | * | ||
104 | * TODO: | ||
105 | * | ||
106 | * - FIXME: recover errors more gracefully | ||
107 | * - FIXME: handle NAKs (I dont think they come here) for flow ctl | ||
108 | */ | ||
109 | static | ||
110 | void i1480u_tx_cb(struct urb *urb) | ||
111 | { | ||
112 | struct i1480u_tx *wtx = urb->context; | ||
113 | struct i1480u *i1480u = wtx->i1480u; | ||
114 | struct net_device *net_dev = i1480u->net_dev; | ||
115 | struct device *dev = &i1480u->usb_iface->dev; | ||
116 | unsigned long flags; | ||
117 | |||
118 | switch (urb->status) { | ||
119 | case 0: | ||
120 | spin_lock_irqsave(&i1480u->lock, flags); | ||
121 | net_dev->stats.tx_packets++; | ||
122 | net_dev->stats.tx_bytes += urb->actual_length; | ||
123 | spin_unlock_irqrestore(&i1480u->lock, flags); | ||
124 | break; | ||
125 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
126 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
127 | dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status); | ||
128 | netif_stop_queue(net_dev); | ||
129 | break; | ||
130 | case -ESHUTDOWN: /* going away! */ | ||
131 | dev_dbg(dev, "notif endp: down %d\n", urb->status); | ||
132 | netif_stop_queue(net_dev); | ||
133 | break; | ||
134 | default: | ||
135 | dev_err(dev, "TX: unknown URB status %d\n", urb->status); | ||
136 | if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS, | ||
137 | EDC_ERROR_TIMEFRAME)) { | ||
138 | dev_err(dev, "TX: max acceptable errors exceeded." | ||
139 | "Reset device.\n"); | ||
140 | netif_stop_queue(net_dev); | ||
141 | i1480u_tx_unlink_urbs(i1480u); | ||
142 | wlp_reset_all(&i1480u->wlp); | ||
143 | } | ||
144 | break; | ||
145 | } | ||
146 | i1480u_tx_destroy(i1480u, wtx); | ||
147 | if (atomic_dec_return(&i1480u->tx_inflight.count) | ||
148 | <= i1480u->tx_inflight.threshold | ||
149 | && netif_queue_stopped(net_dev) | ||
150 | && i1480u->tx_inflight.threshold != 0) { | ||
151 | netif_start_queue(net_dev); | ||
152 | atomic_inc(&i1480u->tx_inflight.restart_count); | ||
153 | } | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | |||
158 | /* | ||
159 | * Given a buffer that doesn't fit in a single fragment, create an | ||
160 | * scatter/gather structure for delivery to the USB pipe. | ||
161 | * | ||
162 | * Implements functionality of i1480u_tx_create(). | ||
163 | * | ||
164 | * @wtx: tx descriptor | ||
165 | * @skb: skb to send | ||
166 | * @gfp_mask: gfp allocation mask | ||
167 | * @returns: Pointer to @wtx if ok, NULL on error. | ||
168 | * | ||
169 | * Sorry, TOO LONG a function, but breaking it up is kind of hard | ||
170 | * | ||
171 | * This will break the buffer in chunks smaller than | ||
172 | * i1480u_MAX_FRG_SIZE (including the header) and add proper headers | ||
173 | * to each: | ||
174 | * | ||
175 | * 1st header \ | ||
176 | * i1480 tx header | fragment 1 | ||
177 | * fragment data / | ||
178 | * nxt header \ fragment 2 | ||
179 | * fragment data / | ||
180 | * .. | ||
181 | * .. | ||
182 | * last header \ fragment 3 | ||
183 | * last fragment data / | ||
184 | * | ||
185 | * This does not fill the i1480 TX header, it is left up to the | ||
186 | * caller to do that; you can get it from @wtx->wlp_tx_hdr. | ||
187 | * | ||
188 | * This function consumes the skb unless there is an error. | ||
189 | */ | ||
190 | static | ||
191 | int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, | ||
192 | gfp_t gfp_mask) | ||
193 | { | ||
194 | int result; | ||
195 | void *pl; | ||
196 | size_t pl_size; | ||
197 | |||
198 | void *pl_itr, *buf_itr; | ||
199 | size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0; | ||
200 | struct untd_hdr_1st *untd_hdr_1st; | ||
201 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
202 | struct untd_hdr_rst *untd_hdr_rst; | ||
203 | |||
204 | wtx->skb = NULL; | ||
205 | pl = skb->data; | ||
206 | pl_itr = pl; | ||
207 | pl_size = skb->len; | ||
208 | pl_size_left = pl_size; /* payload size */ | ||
209 | /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus | ||
210 | * the headers */ | ||
211 | pl_size_1st = i1480u_MAX_FRG_SIZE | ||
212 | - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr); | ||
213 | BUG_ON(pl_size_1st > pl_size); | ||
214 | pl_size_left -= pl_size_1st; | ||
215 | /* The rest have an smaller header (no i1480 TX header). We | ||
216 | * need to break up the payload in blocks smaller than | ||
217 | * i1480u_MAX_PL_SIZE (payload excluding header). */ | ||
218 | frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE; | ||
219 | /* Allocate space for the new buffer. In this new buffer we'll | ||
220 | * place the headers followed by the data fragment, headers, | ||
221 | * data fragments, etc.. | ||
222 | */ | ||
223 | result = -ENOMEM; | ||
224 | wtx->buf_size = sizeof(*untd_hdr_1st) | ||
225 | + sizeof(*wlp_tx_hdr) | ||
226 | + frgs * sizeof(*untd_hdr_rst) | ||
227 | + pl_size; | ||
228 | wtx->buf = kmalloc(wtx->buf_size, gfp_mask); | ||
229 | if (wtx->buf == NULL) | ||
230 | goto error_buf_alloc; | ||
231 | |||
232 | buf_itr = wtx->buf; /* We got the space, let's fill it up */ | ||
233 | /* Fill 1st fragment */ | ||
234 | untd_hdr_1st = buf_itr; | ||
235 | buf_itr += sizeof(*untd_hdr_1st); | ||
236 | untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST); | ||
237 | untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0); | ||
238 | untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr)); | ||
239 | untd_hdr_1st->fragment_len = | ||
240 | cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr)); | ||
241 | memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding)); | ||
242 | /* Set up i1480 header info */ | ||
243 | wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr; | ||
244 | buf_itr += sizeof(*wlp_tx_hdr); | ||
245 | /* Copy the first fragment */ | ||
246 | memcpy(buf_itr, pl_itr, pl_size_1st); | ||
247 | pl_itr += pl_size_1st; | ||
248 | buf_itr += pl_size_1st; | ||
249 | |||
250 | /* Now do each remaining fragment */ | ||
251 | result = -EINVAL; | ||
252 | while (pl_size_left > 0) { | ||
253 | if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf | ||
254 | > wtx->buf_size) { | ||
255 | printk(KERN_ERR "BUG: no space for header\n"); | ||
256 | goto error_bug; | ||
257 | } | ||
258 | untd_hdr_rst = buf_itr; | ||
259 | buf_itr += sizeof(*untd_hdr_rst); | ||
260 | if (pl_size_left > i1480u_MAX_PL_SIZE) { | ||
261 | frg_pl_size = i1480u_MAX_PL_SIZE; | ||
262 | untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT); | ||
263 | } else { | ||
264 | frg_pl_size = pl_size_left; | ||
265 | untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST); | ||
266 | } | ||
267 | untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0); | ||
268 | untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size); | ||
269 | untd_hdr_rst->padding = 0; | ||
270 | if (buf_itr + frg_pl_size - wtx->buf | ||
271 | > wtx->buf_size) { | ||
272 | printk(KERN_ERR "BUG: no space for payload\n"); | ||
273 | goto error_bug; | ||
274 | } | ||
275 | memcpy(buf_itr, pl_itr, frg_pl_size); | ||
276 | buf_itr += frg_pl_size; | ||
277 | pl_itr += frg_pl_size; | ||
278 | pl_size_left -= frg_pl_size; | ||
279 | } | ||
280 | dev_kfree_skb_irq(skb); | ||
281 | return 0; | ||
282 | |||
283 | error_bug: | ||
284 | printk(KERN_ERR | ||
285 | "BUG: skb %u bytes\n" | ||
286 | "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n" | ||
287 | "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n", | ||
288 | skb->len, | ||
289 | frg_pl_size, i1480u_MAX_FRG_SIZE, | ||
290 | buf_itr - wtx->buf, wtx->buf_size, pl_size_left); | ||
291 | |||
292 | kfree(wtx->buf); | ||
293 | error_buf_alloc: | ||
294 | return result; | ||
295 | } | ||
296 | |||
297 | |||
298 | /* | ||
299 | * Given a buffer that fits in a single fragment, fill out a @wtx | ||
300 | * struct for transmitting it down the USB pipe. | ||
301 | * | ||
302 | * Uses the fact that we have space reserved in front of the skbuff | ||
303 | * for hardware headers :] | ||
304 | * | ||
305 | * This does not fill the i1480 TX header, it is left up to the | ||
306 | * caller to do that; you can get it from @wtx->wlp_tx_hdr. | ||
307 | * | ||
308 | * @pl: pointer to payload data | ||
309 | * @pl_size: size of the payuload | ||
310 | * | ||
311 | * This function does not consume the @skb. | ||
312 | */ | ||
313 | static | ||
314 | int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb, | ||
315 | gfp_t gfp_mask) | ||
316 | { | ||
317 | struct untd_hdr_cmp *untd_hdr_cmp; | ||
318 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
319 | |||
320 | wtx->buf = NULL; | ||
321 | wtx->skb = skb; | ||
322 | BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr)); | ||
323 | wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr)); | ||
324 | wtx->wlp_tx_hdr = wlp_tx_hdr; | ||
325 | BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp)); | ||
326 | untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp)); | ||
327 | |||
328 | untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP); | ||
329 | untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0); | ||
330 | untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp)); | ||
331 | untd_hdr_cmp->padding = 0; | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | |||
336 | /* | ||
337 | * Given a skb to transmit, massage it to become palatable for the TX pipe | ||
338 | * | ||
339 | * This will break the buffer in chunks smaller than | ||
340 | * i1480u_MAX_FRG_SIZE and add proper headers to each. | ||
341 | * | ||
342 | * 1st header \ | ||
343 | * i1480 tx header | fragment 1 | ||
344 | * fragment data / | ||
345 | * nxt header \ fragment 2 | ||
346 | * fragment data / | ||
347 | * .. | ||
348 | * .. | ||
349 | * last header \ fragment 3 | ||
350 | * last fragment data / | ||
351 | * | ||
352 | * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE. | ||
353 | * | ||
354 | * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the | ||
355 | * following is composed: | ||
356 | * | ||
357 | * complete header \ | ||
358 | * i1480 tx header | single fragment | ||
359 | * packet data / | ||
360 | * | ||
361 | * We were going to use s/g support, but because the interface is | ||
362 | * synch and at the end there is plenty of overhead to do it, it | ||
363 | * didn't seem that worth for data that is going to be smaller than | ||
364 | * one page. | ||
365 | */ | ||
366 | static | ||
367 | struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u, | ||
368 | struct sk_buff *skb, gfp_t gfp_mask) | ||
369 | { | ||
370 | int result; | ||
371 | struct usb_endpoint_descriptor *epd; | ||
372 | int usb_pipe; | ||
373 | unsigned long flags; | ||
374 | |||
375 | struct i1480u_tx *wtx; | ||
376 | const size_t pl_max_size = | ||
377 | i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp) | ||
378 | - sizeof(struct wlp_tx_hdr); | ||
379 | |||
380 | wtx = kmalloc(sizeof(*wtx), gfp_mask); | ||
381 | if (wtx == NULL) | ||
382 | goto error_wtx_alloc; | ||
383 | wtx->urb = usb_alloc_urb(0, gfp_mask); | ||
384 | if (wtx->urb == NULL) | ||
385 | goto error_urb_alloc; | ||
386 | epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc; | ||
387 | usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress); | ||
388 | /* Fits in a single complete packet or need to split? */ | ||
389 | if (skb->len > pl_max_size) { | ||
390 | result = i1480u_tx_create_n(wtx, skb, gfp_mask); | ||
391 | if (result < 0) | ||
392 | goto error_create; | ||
393 | usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, | ||
394 | wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx); | ||
395 | } else { | ||
396 | result = i1480u_tx_create_1(wtx, skb, gfp_mask); | ||
397 | if (result < 0) | ||
398 | goto error_create; | ||
399 | usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, | ||
400 | skb->data, skb->len, i1480u_tx_cb, wtx); | ||
401 | } | ||
402 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
403 | list_add(&wtx->list_node, &i1480u->tx_list); | ||
404 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
405 | return wtx; | ||
406 | |||
407 | error_create: | ||
408 | kfree(wtx->urb); | ||
409 | error_urb_alloc: | ||
410 | kfree(wtx); | ||
411 | error_wtx_alloc: | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * Actual fragmentation and transmission of frame | ||
417 | * | ||
418 | * @wlp: WLP substack data structure | ||
419 | * @skb: To be transmitted | ||
420 | * @dst: Device address of destination | ||
421 | * @returns: 0 on success, <0 on failure | ||
422 | * | ||
423 | * This function can also be called directly (not just from | ||
424 | * hard_start_xmit), so we also check here if the interface is up before | ||
425 | * taking sending anything. | ||
426 | */ | ||
427 | int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, | ||
428 | struct uwb_dev_addr *dst) | ||
429 | { | ||
430 | int result = -ENXIO; | ||
431 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
432 | struct device *dev = &i1480u->usb_iface->dev; | ||
433 | struct net_device *net_dev = i1480u->net_dev; | ||
434 | struct i1480u_tx *wtx; | ||
435 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
436 | static unsigned char dev_bcast[2] = { 0xff, 0xff }; | ||
437 | |||
438 | BUG_ON(i1480u->wlp.rc == NULL); | ||
439 | if ((net_dev->flags & IFF_UP) == 0) | ||
440 | goto out; | ||
441 | result = -EBUSY; | ||
442 | if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) { | ||
443 | netif_stop_queue(net_dev); | ||
444 | goto error_max_inflight; | ||
445 | } | ||
446 | result = -ENOMEM; | ||
447 | wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC); | ||
448 | if (unlikely(wtx == NULL)) { | ||
449 | if (printk_ratelimit()) | ||
450 | dev_err(dev, "TX: no memory for WLP TX URB," | ||
451 | "dropping packet (in flight %d)\n", | ||
452 | atomic_read(&i1480u->tx_inflight.count)); | ||
453 | netif_stop_queue(net_dev); | ||
454 | goto error_wtx_alloc; | ||
455 | } | ||
456 | wtx->i1480u = i1480u; | ||
457 | /* Fill out the i1480 header; @i1480u->def_tx_hdr read without | ||
458 | * locking. We do so because they are kind of orthogonal to | ||
459 | * each other (and thus not changed in an atomic batch). | ||
460 | * The ETH header is right after the WLP TX header. */ | ||
461 | wlp_tx_hdr = wtx->wlp_tx_hdr; | ||
462 | *wlp_tx_hdr = i1480u->options.def_tx_hdr; | ||
463 | wlp_tx_hdr->dstaddr = *dst; | ||
464 | if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast)) | ||
465 | && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) { | ||
466 | /*Broadcast message directed to DRP host. Send as best effort | ||
467 | * on PCA. */ | ||
468 | wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority); | ||
469 | } | ||
470 | |||
471 | result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */ | ||
472 | if (result < 0) { | ||
473 | dev_err(dev, "TX: cannot submit URB: %d\n", result); | ||
474 | /* We leave the freeing of skb to calling function */ | ||
475 | wtx->skb = NULL; | ||
476 | goto error_tx_urb_submit; | ||
477 | } | ||
478 | atomic_inc(&i1480u->tx_inflight.count); | ||
479 | net_dev->trans_start = jiffies; | ||
480 | return result; | ||
481 | |||
482 | error_tx_urb_submit: | ||
483 | i1480u_tx_destroy(i1480u, wtx); | ||
484 | error_wtx_alloc: | ||
485 | error_max_inflight: | ||
486 | out: | ||
487 | return result; | ||
488 | } | ||
489 | |||
490 | |||
491 | /* | ||
492 | * Transmit an skb Called when an skbuf has to be transmitted | ||
493 | * | ||
494 | * The skb is first passed to WLP substack to ensure this is a valid | ||
495 | * frame. If valid the device address of destination will be filled and | ||
496 | * the WLP header prepended to the skb. If this step fails we fake sending | ||
497 | * the frame, if we return an error the network stack will just keep trying. | ||
498 | * | ||
499 | * Broadcast frames inside a WSS needs to be treated special as multicast is | ||
500 | * not supported. A broadcast frame is sent as unicast to each member of the | ||
501 | * WSS - this is done by the WLP substack when it finds a broadcast frame. | ||
502 | * So, we test if the WLP substack took over the skb and only transmit it | ||
503 | * if it has not (been taken over). | ||
504 | * | ||
505 | * @net_dev->xmit_lock is held | ||
506 | */ | ||
507 | netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *skb, | ||
508 | struct net_device *net_dev) | ||
509 | { | ||
510 | int result; | ||
511 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
512 | struct device *dev = &i1480u->usb_iface->dev; | ||
513 | struct uwb_dev_addr dst; | ||
514 | |||
515 | if ((net_dev->flags & IFF_UP) == 0) | ||
516 | goto error; | ||
517 | result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst); | ||
518 | if (result < 0) { | ||
519 | dev_err(dev, "WLP verification of TX frame failed (%d). " | ||
520 | "Dropping packet.\n", result); | ||
521 | goto error; | ||
522 | } else if (result == 1) { | ||
523 | /* trans_start time will be set when WLP actually transmits | ||
524 | * the frame */ | ||
525 | goto out; | ||
526 | } | ||
527 | result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst); | ||
528 | if (result < 0) { | ||
529 | dev_err(dev, "Frame TX failed (%d).\n", result); | ||
530 | goto error; | ||
531 | } | ||
532 | return NETDEV_TX_OK; | ||
533 | error: | ||
534 | dev_kfree_skb_any(skb); | ||
535 | net_dev->stats.tx_dropped++; | ||
536 | out: | ||
537 | return NETDEV_TX_OK; | ||
538 | } | ||
539 | |||
540 | |||
541 | /* | ||
542 | * Called when a pkt transmission doesn't complete in a reasonable period | ||
543 | * Device reset may sleep - do it outside of interrupt context (delayed) | ||
544 | */ | ||
545 | void i1480u_tx_timeout(struct net_device *net_dev) | ||
546 | { | ||
547 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
548 | |||
549 | wlp_reset_all(&i1480u->wlp); | ||
550 | } | ||
551 | |||
552 | |||
553 | void i1480u_tx_release(struct i1480u *i1480u) | ||
554 | { | ||
555 | unsigned long flags; | ||
556 | struct i1480u_tx *wtx, *next; | ||
557 | int count = 0, empty; | ||
558 | |||
559 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
560 | list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { | ||
561 | count++; | ||
562 | usb_unlink_urb(wtx->urb); | ||
563 | } | ||
564 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
565 | count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */ | ||
566 | /* | ||
567 | * We don't like this sollution too much (dirty as it is), but | ||
568 | * it is cheaper than putting a refcount on each i1480u_tx and | ||
569 | * i1480uting for all of them to go away... | ||
570 | * | ||
571 | * Called when no more packets can be added to tx_list | ||
572 | * so can i1480ut for it to be empty. | ||
573 | */ | ||
574 | while (1) { | ||
575 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
576 | empty = list_empty(&i1480u->tx_list); | ||
577 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
578 | if (empty) | ||
579 | break; | ||
580 | count--; | ||
581 | BUG_ON(count == 0); | ||
582 | msleep(20); | ||
583 | } | ||
584 | } | ||
diff --git a/drivers/uwb/wlp/Makefile b/drivers/uwb/wlp/Makefile deleted file mode 100644 index c72c11db5b1b..000000000000 --- a/drivers/uwb/wlp/Makefile +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | obj-$(CONFIG_UWB_WLP) := wlp.o | ||
2 | |||
3 | wlp-objs := \ | ||
4 | driver.o \ | ||
5 | eda.o \ | ||
6 | messages.o \ | ||
7 | sysfs.o \ | ||
8 | txrx.o \ | ||
9 | wlp-lc.o \ | ||
10 | wss-lc.o | ||
diff --git a/drivers/uwb/wlp/driver.c b/drivers/uwb/wlp/driver.c deleted file mode 100644 index cb8d699b6a67..000000000000 --- a/drivers/uwb/wlp/driver.c +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2007 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Life cycle of WLP substack | ||
23 | * | ||
24 | * FIXME: Docs | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | |||
29 | static int __init wlp_subsys_init(void) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | module_init(wlp_subsys_init); | ||
34 | |||
35 | static void __exit wlp_subsys_exit(void) | ||
36 | { | ||
37 | return; | ||
38 | } | ||
39 | module_exit(wlp_subsys_exit); | ||
40 | |||
41 | MODULE_AUTHOR("Reinette Chatre <reinette.chatre@intel.com>"); | ||
42 | MODULE_DESCRIPTION("WiMedia Logical Link Control Protocol (WLP)"); | ||
43 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c deleted file mode 100644 index 086fc0cf9401..000000000000 --- a/drivers/uwb/wlp/eda.c +++ /dev/null | |||
@@ -1,415 +0,0 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Ethernet to device address cache | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * We need to be able to map ethernet addresses to device addresses | ||
24 | * and back because there is not explicit relationship between the eth | ||
25 | * addresses used in the ETH frames and the device addresses (no, it | ||
26 | * would not have been simpler to force as ETH address the MBOA MAC | ||
27 | * address...no, not at all :). | ||
28 | * | ||
29 | * A device has one MBOA MAC address and one device address. It is possible | ||
30 | * for a device to have more than one virtual MAC address (although a | ||
31 | * virtual address can be the same as the MBOA MAC address). The device | ||
32 | * address is guaranteed to be unique among the devices in the extended | ||
33 | * beacon group (see ECMA 17.1.1). We thus use the device address as index | ||
34 | * to this cache. We do allow searching based on virtual address as this | ||
35 | * is how Ethernet frames will be addressed. | ||
36 | * | ||
37 | * We need to support virtual EUI-48. Although, right now the virtual | ||
38 | * EUI-48 will always be the same as the MAC SAP address. The EDA cache | ||
39 | * entry thus contains a MAC SAP address as well as the virtual address | ||
40 | * (used to map the network stack address to a neighbor). When we move | ||
41 | * to support more than one virtual MAC on a host then this organization | ||
42 | * will have to change. Perhaps a neighbor has a list of WSSs, each with a | ||
43 | * tag and virtual EUI-48. | ||
44 | * | ||
45 | * On data transmission | ||
46 | * it is used to determine if the neighbor is connected and what WSS it | ||
47 | * belongs to. With this we know what tag to add to the WLP frame. Storing | ||
48 | * the WSS in the EDA cache may be overkill because we only support one | ||
49 | * WSS. Hopefully we will support more than one WSS at some point. | ||
50 | * On data reception it is used to determine the WSS based on | ||
51 | * the tag and address of the transmitting neighbor. | ||
52 | */ | ||
53 | |||
54 | #include <linux/netdevice.h> | ||
55 | #include <linux/etherdevice.h> | ||
56 | #include <linux/slab.h> | ||
57 | #include <linux/wlp.h> | ||
58 | #include "wlp-internal.h" | ||
59 | |||
60 | |||
61 | /* FIXME: cache is not purged, only on device close */ | ||
62 | |||
63 | /* FIXME: does not scale, change to dynamic array */ | ||
64 | |||
65 | /* | ||
66 | * Initialize the EDA cache | ||
67 | * | ||
68 | * @returns 0 if ok, < 0 errno code on error | ||
69 | * | ||
70 | * Call when the interface is being brought up | ||
71 | * | ||
72 | * NOTE: Keep it as a separate function as the implementation will | ||
73 | * change and be more complex. | ||
74 | */ | ||
75 | void wlp_eda_init(struct wlp_eda *eda) | ||
76 | { | ||
77 | INIT_LIST_HEAD(&eda->cache); | ||
78 | spin_lock_init(&eda->lock); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Release the EDA cache | ||
83 | * | ||
84 | * @returns 0 if ok, < 0 errno code on error | ||
85 | * | ||
86 | * Called when the interface is brought down | ||
87 | */ | ||
88 | void wlp_eda_release(struct wlp_eda *eda) | ||
89 | { | ||
90 | unsigned long flags; | ||
91 | struct wlp_eda_node *itr, *next; | ||
92 | |||
93 | spin_lock_irqsave(&eda->lock, flags); | ||
94 | list_for_each_entry_safe(itr, next, &eda->cache, list_node) { | ||
95 | list_del(&itr->list_node); | ||
96 | kfree(itr); | ||
97 | } | ||
98 | spin_unlock_irqrestore(&eda->lock, flags); | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Add an address mapping | ||
103 | * | ||
104 | * @returns 0 if ok, < 0 errno code on error | ||
105 | * | ||
106 | * An address mapping is initially created when the neighbor device is seen | ||
107 | * for the first time (it is "onair"). At this time the neighbor is not | ||
108 | * connected or associated with a WSS so we only populate the Ethernet and | ||
109 | * Device address fields. | ||
110 | * | ||
111 | */ | ||
112 | int wlp_eda_create_node(struct wlp_eda *eda, | ||
113 | const unsigned char eth_addr[ETH_ALEN], | ||
114 | const struct uwb_dev_addr *dev_addr) | ||
115 | { | ||
116 | int result = 0; | ||
117 | struct wlp_eda_node *itr; | ||
118 | unsigned long flags; | ||
119 | |||
120 | BUG_ON(dev_addr == NULL || eth_addr == NULL); | ||
121 | spin_lock_irqsave(&eda->lock, flags); | ||
122 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
123 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
124 | printk(KERN_ERR "EDA cache already contains entry " | ||
125 | "for neighbor %02x:%02x\n", | ||
126 | dev_addr->data[1], dev_addr->data[0]); | ||
127 | result = -EEXIST; | ||
128 | goto out_unlock; | ||
129 | } | ||
130 | } | ||
131 | itr = kzalloc(sizeof(*itr), GFP_ATOMIC); | ||
132 | if (itr != NULL) { | ||
133 | memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr)); | ||
134 | itr->dev_addr = *dev_addr; | ||
135 | list_add(&itr->list_node, &eda->cache); | ||
136 | } else | ||
137 | result = -ENOMEM; | ||
138 | out_unlock: | ||
139 | spin_unlock_irqrestore(&eda->lock, flags); | ||
140 | return result; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Remove entry from EDA cache | ||
145 | * | ||
146 | * This is done when the device goes off air. | ||
147 | */ | ||
148 | void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr) | ||
149 | { | ||
150 | struct wlp_eda_node *itr, *next; | ||
151 | unsigned long flags; | ||
152 | |||
153 | spin_lock_irqsave(&eda->lock, flags); | ||
154 | list_for_each_entry_safe(itr, next, &eda->cache, list_node) { | ||
155 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
156 | list_del(&itr->list_node); | ||
157 | kfree(itr); | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | spin_unlock_irqrestore(&eda->lock, flags); | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Update an address mapping | ||
166 | * | ||
167 | * @returns 0 if ok, < 0 errno code on error | ||
168 | */ | ||
169 | int wlp_eda_update_node(struct wlp_eda *eda, | ||
170 | const struct uwb_dev_addr *dev_addr, | ||
171 | struct wlp_wss *wss, | ||
172 | const unsigned char virt_addr[ETH_ALEN], | ||
173 | const u8 tag, const enum wlp_wss_connect state) | ||
174 | { | ||
175 | int result = -ENOENT; | ||
176 | struct wlp_eda_node *itr; | ||
177 | unsigned long flags; | ||
178 | |||
179 | spin_lock_irqsave(&eda->lock, flags); | ||
180 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
181 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
182 | /* Found it, update it */ | ||
183 | itr->wss = wss; | ||
184 | memcpy(itr->virt_addr, virt_addr, | ||
185 | sizeof(itr->virt_addr)); | ||
186 | itr->tag = tag; | ||
187 | itr->state = state; | ||
188 | result = 0; | ||
189 | goto out_unlock; | ||
190 | } | ||
191 | } | ||
192 | /* Not found */ | ||
193 | out_unlock: | ||
194 | spin_unlock_irqrestore(&eda->lock, flags); | ||
195 | return result; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Update only state field of an address mapping | ||
200 | * | ||
201 | * @returns 0 if ok, < 0 errno code on error | ||
202 | */ | ||
203 | int wlp_eda_update_node_state(struct wlp_eda *eda, | ||
204 | const struct uwb_dev_addr *dev_addr, | ||
205 | const enum wlp_wss_connect state) | ||
206 | { | ||
207 | int result = -ENOENT; | ||
208 | struct wlp_eda_node *itr; | ||
209 | unsigned long flags; | ||
210 | |||
211 | spin_lock_irqsave(&eda->lock, flags); | ||
212 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
213 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
214 | /* Found it, update it */ | ||
215 | itr->state = state; | ||
216 | result = 0; | ||
217 | goto out_unlock; | ||
218 | } | ||
219 | } | ||
220 | /* Not found */ | ||
221 | out_unlock: | ||
222 | spin_unlock_irqrestore(&eda->lock, flags); | ||
223 | return result; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * Return contents of EDA cache entry | ||
228 | * | ||
229 | * @dev_addr: index to EDA cache | ||
230 | * @eda_entry: pointer to where contents of EDA cache will be copied | ||
231 | */ | ||
232 | int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr, | ||
233 | struct wlp_eda_node *eda_entry) | ||
234 | { | ||
235 | int result = -ENOENT; | ||
236 | struct wlp_eda_node *itr; | ||
237 | unsigned long flags; | ||
238 | |||
239 | spin_lock_irqsave(&eda->lock, flags); | ||
240 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
241 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
242 | *eda_entry = *itr; | ||
243 | result = 0; | ||
244 | goto out_unlock; | ||
245 | } | ||
246 | } | ||
247 | /* Not found */ | ||
248 | out_unlock: | ||
249 | spin_unlock_irqrestore(&eda->lock, flags); | ||
250 | return result; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Execute function for every element in the cache | ||
255 | * | ||
256 | * @function: function to execute on element of cache (must be atomic) | ||
257 | * @priv: private data of function | ||
258 | * @returns: result of first function that failed, or last function | ||
259 | * executed if no function failed. | ||
260 | * | ||
261 | * Stop executing when function returns error for any element in cache. | ||
262 | * | ||
263 | * IMPORTANT: We are using a spinlock here: the function executed on each | ||
264 | * element has to be atomic. | ||
265 | */ | ||
266 | int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function, | ||
267 | void *priv) | ||
268 | { | ||
269 | int result = 0; | ||
270 | struct wlp *wlp = container_of(eda, struct wlp, eda); | ||
271 | struct wlp_eda_node *entry; | ||
272 | unsigned long flags; | ||
273 | |||
274 | spin_lock_irqsave(&eda->lock, flags); | ||
275 | list_for_each_entry(entry, &eda->cache, list_node) { | ||
276 | result = (*function)(wlp, entry, priv); | ||
277 | if (result < 0) | ||
278 | break; | ||
279 | } | ||
280 | spin_unlock_irqrestore(&eda->lock, flags); | ||
281 | return result; | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Execute function for single element in the cache (return dev addr) | ||
286 | * | ||
287 | * @virt_addr: index into EDA cache used to determine which element to | ||
288 | * execute the function on | ||
289 | * @dev_addr: device address of element in cache will be returned using | ||
290 | * @dev_addr | ||
291 | * @function: function to execute on element of cache (must be atomic) | ||
292 | * @priv: private data of function | ||
293 | * @returns: result of function | ||
294 | * | ||
295 | * IMPORTANT: We are using a spinlock here: the function executed on the | ||
296 | * element has to be atomic. | ||
297 | */ | ||
298 | int wlp_eda_for_virtual(struct wlp_eda *eda, | ||
299 | const unsigned char virt_addr[ETH_ALEN], | ||
300 | struct uwb_dev_addr *dev_addr, | ||
301 | wlp_eda_for_each_f function, | ||
302 | void *priv) | ||
303 | { | ||
304 | int result = 0; | ||
305 | struct wlp *wlp = container_of(eda, struct wlp, eda); | ||
306 | struct wlp_eda_node *itr; | ||
307 | unsigned long flags; | ||
308 | int found = 0; | ||
309 | |||
310 | spin_lock_irqsave(&eda->lock, flags); | ||
311 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
312 | if (!memcmp(itr->virt_addr, virt_addr, | ||
313 | sizeof(itr->virt_addr))) { | ||
314 | result = (*function)(wlp, itr, priv); | ||
315 | *dev_addr = itr->dev_addr; | ||
316 | found = 1; | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | if (!found) | ||
321 | result = -ENODEV; | ||
322 | spin_unlock_irqrestore(&eda->lock, flags); | ||
323 | return result; | ||
324 | } | ||
325 | |||
326 | static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED", | ||
327 | "WLP_WSS_CONNECTED", | ||
328 | "WLP_WSS_CONNECT_FAILED", | ||
329 | }; | ||
330 | |||
331 | static const char *wlp_wss_connect_state_str(unsigned id) | ||
332 | { | ||
333 | if (id >= ARRAY_SIZE(__wlp_wss_connect_state)) | ||
334 | return "unknown WSS connection state"; | ||
335 | return __wlp_wss_connect_state[id]; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * View EDA cache from user space | ||
340 | * | ||
341 | * A debugging feature to give user visibility into the EDA cache. Also | ||
342 | * used to display members of WSS to user (called from wlp_wss_members_show()) | ||
343 | */ | ||
344 | ssize_t wlp_eda_show(struct wlp *wlp, char *buf) | ||
345 | { | ||
346 | ssize_t result = 0; | ||
347 | struct wlp_eda_node *entry; | ||
348 | unsigned long flags; | ||
349 | struct wlp_eda *eda = &wlp->eda; | ||
350 | spin_lock_irqsave(&eda->lock, flags); | ||
351 | result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr " | ||
352 | "tag state virt_addr\n"); | ||
353 | list_for_each_entry(entry, &eda->cache, list_node) { | ||
354 | result += scnprintf(buf + result, PAGE_SIZE - result, | ||
355 | "%pM %02x:%02x %p 0x%02x %s %pM\n", | ||
356 | entry->eth_addr, | ||
357 | entry->dev_addr.data[1], | ||
358 | entry->dev_addr.data[0], entry->wss, | ||
359 | entry->tag, | ||
360 | wlp_wss_connect_state_str(entry->state), | ||
361 | entry->virt_addr); | ||
362 | if (result >= PAGE_SIZE) | ||
363 | break; | ||
364 | } | ||
365 | spin_unlock_irqrestore(&eda->lock, flags); | ||
366 | return result; | ||
367 | } | ||
368 | EXPORT_SYMBOL_GPL(wlp_eda_show); | ||
369 | |||
370 | /* | ||
371 | * Add new EDA cache entry based on user input in sysfs | ||
372 | * | ||
373 | * Should only be used for debugging. | ||
374 | * | ||
375 | * The WSS is assumed to be the only WSS supported. This needs to be | ||
376 | * redesigned when we support more than one WSS. | ||
377 | */ | ||
378 | ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size) | ||
379 | { | ||
380 | ssize_t result; | ||
381 | struct wlp_eda *eda = &wlp->eda; | ||
382 | u8 eth_addr[6]; | ||
383 | struct uwb_dev_addr dev_addr; | ||
384 | u8 tag; | ||
385 | unsigned state; | ||
386 | |||
387 | result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx " | ||
388 | "%02hhx:%02hhx %02hhx %u\n", | ||
389 | ð_addr[0], ð_addr[1], | ||
390 | ð_addr[2], ð_addr[3], | ||
391 | ð_addr[4], ð_addr[5], | ||
392 | &dev_addr.data[1], &dev_addr.data[0], &tag, &state); | ||
393 | switch (result) { | ||
394 | case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */ | ||
395 | /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/ | ||
396 | result = -ENOSYS; | ||
397 | break; | ||
398 | case 10: | ||
399 | state = state >= 1 ? 1 : 0; | ||
400 | result = wlp_eda_create_node(eda, eth_addr, &dev_addr); | ||
401 | if (result < 0 && result != -EEXIST) | ||
402 | goto error; | ||
403 | /* Set virtual addr to be same as MAC */ | ||
404 | result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss, | ||
405 | eth_addr, tag, state); | ||
406 | if (result < 0) | ||
407 | goto error; | ||
408 | break; | ||
409 | default: /* bad format */ | ||
410 | result = -EINVAL; | ||
411 | } | ||
412 | error: | ||
413 | return result < 0 ? result : size; | ||
414 | } | ||
415 | EXPORT_SYMBOL_GPL(wlp_eda_store); | ||
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c deleted file mode 100644 index 3a8e033dce21..000000000000 --- a/drivers/uwb/wlp/messages.c +++ /dev/null | |||
@@ -1,1798 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * Message construction and parsing | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/wlp.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include "wlp-internal.h" | ||
30 | |||
31 | static | ||
32 | const char *__wlp_assoc_frame[] = { | ||
33 | [WLP_ASSOC_D1] = "WLP_ASSOC_D1", | ||
34 | [WLP_ASSOC_D2] = "WLP_ASSOC_D2", | ||
35 | [WLP_ASSOC_M1] = "WLP_ASSOC_M1", | ||
36 | [WLP_ASSOC_M2] = "WLP_ASSOC_M2", | ||
37 | [WLP_ASSOC_M3] = "WLP_ASSOC_M3", | ||
38 | [WLP_ASSOC_M4] = "WLP_ASSOC_M4", | ||
39 | [WLP_ASSOC_M5] = "WLP_ASSOC_M5", | ||
40 | [WLP_ASSOC_M6] = "WLP_ASSOC_M6", | ||
41 | [WLP_ASSOC_M7] = "WLP_ASSOC_M7", | ||
42 | [WLP_ASSOC_M8] = "WLP_ASSOC_M8", | ||
43 | [WLP_ASSOC_F0] = "WLP_ASSOC_F0", | ||
44 | [WLP_ASSOC_E1] = "WLP_ASSOC_E1", | ||
45 | [WLP_ASSOC_E2] = "WLP_ASSOC_E2", | ||
46 | [WLP_ASSOC_C1] = "WLP_ASSOC_C1", | ||
47 | [WLP_ASSOC_C2] = "WLP_ASSOC_C2", | ||
48 | [WLP_ASSOC_C3] = "WLP_ASSOC_C3", | ||
49 | [WLP_ASSOC_C4] = "WLP_ASSOC_C4", | ||
50 | }; | ||
51 | |||
52 | static const char *wlp_assoc_frame_str(unsigned id) | ||
53 | { | ||
54 | if (id >= ARRAY_SIZE(__wlp_assoc_frame)) | ||
55 | return "unknown association frame"; | ||
56 | return __wlp_assoc_frame[id]; | ||
57 | } | ||
58 | |||
59 | static const char *__wlp_assc_error[] = { | ||
60 | "none", | ||
61 | "Authenticator Failure", | ||
62 | "Rogue activity suspected", | ||
63 | "Device busy", | ||
64 | "Setup Locked", | ||
65 | "Registrar not ready", | ||
66 | "Invalid WSS selection", | ||
67 | "Message timeout", | ||
68 | "Enrollment session timeout", | ||
69 | "Device password invalid", | ||
70 | "Unsupported version", | ||
71 | "Internal error", | ||
72 | "Undefined error", | ||
73 | "Numeric comparison failure", | ||
74 | "Waiting for user input", | ||
75 | }; | ||
76 | |||
77 | static const char *wlp_assc_error_str(unsigned id) | ||
78 | { | ||
79 | if (id >= ARRAY_SIZE(__wlp_assc_error)) | ||
80 | return "unknown WLP association error"; | ||
81 | return __wlp_assc_error[id]; | ||
82 | } | ||
83 | |||
84 | static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type, | ||
85 | size_t len) | ||
86 | { | ||
87 | hdr->type = cpu_to_le16(type); | ||
88 | hdr->length = cpu_to_le16(len); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Populate fields of a constant sized attribute | ||
93 | * | ||
94 | * @returns: total size of attribute including size of new value | ||
95 | * | ||
96 | * We have two instances of this function (wlp_pset and wlp_set): one takes | ||
97 | * the value as a parameter, the other takes a pointer to the value as | ||
98 | * parameter. They thus only differ in how the value is assigned to the | ||
99 | * attribute. | ||
100 | * | ||
101 | * We use sizeof(*attr) - sizeof(struct wlp_attr_hdr) instead of | ||
102 | * sizeof(type) to be able to use this same code for the structures that | ||
103 | * contain 8bit enum values and be able to deal with pointer types. | ||
104 | */ | ||
105 | #define wlp_set(type, type_code, name) \ | ||
106 | static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ | ||
107 | { \ | ||
108 | wlp_set_attr_hdr(&attr->hdr, type_code, \ | ||
109 | sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \ | ||
110 | attr->name = value; \ | ||
111 | return sizeof(*attr); \ | ||
112 | } | ||
113 | |||
114 | #define wlp_pset(type, type_code, name) \ | ||
115 | static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ | ||
116 | { \ | ||
117 | wlp_set_attr_hdr(&attr->hdr, type_code, \ | ||
118 | sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \ | ||
119 | attr->name = *value; \ | ||
120 | return sizeof(*attr); \ | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * Populate fields of a variable attribute | ||
125 | * | ||
126 | * @returns: total size of attribute including size of new value | ||
127 | * | ||
128 | * Provided with a pointer to the memory area reserved for the | ||
129 | * attribute structure, the field is populated with the value. The | ||
130 | * reserved memory has to contain enough space for the value. | ||
131 | */ | ||
132 | #define wlp_vset(type, type_code, name) \ | ||
133 | static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \ | ||
134 | size_t len) \ | ||
135 | { \ | ||
136 | wlp_set_attr_hdr(&attr->hdr, type_code, len); \ | ||
137 | memcpy(attr->name, value, len); \ | ||
138 | return sizeof(*attr) + len; \ | ||
139 | } | ||
140 | |||
141 | wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name) | ||
142 | wlp_vset(char *, WLP_ATTR_MANUF, manufacturer) | ||
143 | wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type) | ||
144 | wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name) | ||
145 | wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr) | ||
146 | wlp_vset(char *, WLP_ATTR_SERIAL, serial) | ||
147 | wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name) | ||
148 | wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e) | ||
149 | wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r) | ||
150 | wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid) | ||
151 | wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type) | ||
152 | /*wlp_pset(struct wlp_dev_type *, WLP_ATTR_SEC_DEV_TYPE, sec_dev_type)*/ | ||
153 | wlp_set(u8, WLP_ATTR_WLP_VER, version) | ||
154 | wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err) | ||
155 | wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd) | ||
156 | wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl) | ||
157 | wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status) | ||
158 | wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast) | ||
159 | wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce) | ||
160 | wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce) | ||
161 | wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag) | ||
162 | wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt) | ||
163 | |||
164 | /** | ||
165 | * Fill in the WSS information attributes | ||
166 | * | ||
167 | * We currently only support one WSS, and this is assumed in this function | ||
168 | * that can populate only one WSS information attribute. | ||
169 | */ | ||
170 | static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr, | ||
171 | struct wlp_wss *wss) | ||
172 | { | ||
173 | size_t datalen; | ||
174 | void *ptr = attr->wss_info; | ||
175 | size_t used = sizeof(*attr); | ||
176 | |||
177 | datalen = sizeof(struct wlp_wss_info) + strlen(wss->name); | ||
178 | wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen); | ||
179 | used = wlp_set_wssid(ptr, &wss->wssid); | ||
180 | used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name)); | ||
181 | used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll); | ||
182 | used += wlp_set_wss_sec_status(ptr + used, wss->secure_status); | ||
183 | used += wlp_set_wss_bcast(ptr + used, &wss->bcast); | ||
184 | return sizeof(*attr) + used; | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * Verify attribute header | ||
189 | * | ||
190 | * @hdr: Pointer to attribute header that will be verified. | ||
191 | * @type: Expected attribute type. | ||
192 | * @len: Expected length of attribute value (excluding header). | ||
193 | * | ||
194 | * Most attribute values have a known length even when they do have a | ||
195 | * length field. This knowledge can be used via this function to verify | ||
196 | * that the length field matches the expected value. | ||
197 | */ | ||
198 | static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr, | ||
199 | enum wlp_attr_type type, unsigned len) | ||
200 | { | ||
201 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
202 | |||
203 | if (le16_to_cpu(hdr->type) != type) { | ||
204 | dev_err(dev, "WLP: unexpected header type. Expected " | ||
205 | "%u, got %u.\n", type, le16_to_cpu(hdr->type)); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | if (le16_to_cpu(hdr->length) != len) { | ||
209 | dev_err(dev, "WLP: unexpected length in header. Expected " | ||
210 | "%u, got %u.\n", len, le16_to_cpu(hdr->length)); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * Check if header of WSS information attribute valid | ||
218 | * | ||
219 | * @returns: length of WSS attributes (value of length attribute field) if | ||
220 | * valid WSS information attribute found | ||
221 | * -ENODATA if no WSS information attribute found | ||
222 | * -EIO other error occured | ||
223 | * | ||
224 | * The WSS information attribute is optional. The function will be provided | ||
225 | * with a pointer to data that could _potentially_ be a WSS information | ||
226 | * attribute. If a valid WSS information attribute is found it will return | ||
227 | * 0, if no WSS information attribute is found it will return -ENODATA, and | ||
228 | * another error will be returned if it is a WSS information attribute, but | ||
229 | * some parsing failure occured. | ||
230 | */ | ||
231 | static int wlp_check_wss_info_attr_hdr(struct wlp *wlp, | ||
232 | struct wlp_attr_hdr *hdr, size_t buflen) | ||
233 | { | ||
234 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
235 | size_t len; | ||
236 | int result = 0; | ||
237 | |||
238 | if (buflen < sizeof(*hdr)) { | ||
239 | dev_err(dev, "WLP: Not enough space in buffer to parse" | ||
240 | " WSS information attribute header.\n"); | ||
241 | result = -EIO; | ||
242 | goto out; | ||
243 | } | ||
244 | if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) { | ||
245 | /* WSS information is optional */ | ||
246 | result = -ENODATA; | ||
247 | goto out; | ||
248 | } | ||
249 | len = le16_to_cpu(hdr->length); | ||
250 | if (buflen < sizeof(*hdr) + len) { | ||
251 | dev_err(dev, "WLP: Not enough space in buffer to parse " | ||
252 | "variable data. Got %d, expected %d.\n", | ||
253 | (int)buflen, (int)(sizeof(*hdr) + len)); | ||
254 | result = -EIO; | ||
255 | goto out; | ||
256 | } | ||
257 | result = len; | ||
258 | out: | ||
259 | return result; | ||
260 | } | ||
261 | |||
262 | |||
263 | static ssize_t wlp_get_attribute(struct wlp *wlp, u16 type_code, | ||
264 | struct wlp_attr_hdr *attr_hdr, void *value, ssize_t value_len, | ||
265 | ssize_t buflen) | ||
266 | { | ||
267 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
268 | ssize_t attr_len = sizeof(*attr_hdr) + value_len; | ||
269 | if (buflen < 0) | ||
270 | return -EINVAL; | ||
271 | if (buflen < attr_len) { | ||
272 | dev_err(dev, "WLP: Not enough space in buffer to parse" | ||
273 | " attribute field. Need %d, received %zu\n", | ||
274 | (int)attr_len, buflen); | ||
275 | return -EIO; | ||
276 | } | ||
277 | if (wlp_check_attr_hdr(wlp, attr_hdr, type_code, value_len) < 0) { | ||
278 | dev_err(dev, "WLP: Header verification failed. \n"); | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | memcpy(value, (void *)attr_hdr + sizeof(*attr_hdr), value_len); | ||
282 | return attr_len; | ||
283 | } | ||
284 | |||
285 | static ssize_t wlp_vget_attribute(struct wlp *wlp, u16 type_code, | ||
286 | struct wlp_attr_hdr *attr_hdr, void *value, ssize_t max_value_len, | ||
287 | ssize_t buflen) | ||
288 | { | ||
289 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
290 | size_t len; | ||
291 | if (buflen < 0) | ||
292 | return -EINVAL; | ||
293 | if (buflen < sizeof(*attr_hdr)) { | ||
294 | dev_err(dev, "WLP: Not enough space in buffer to parse" | ||
295 | " header.\n"); | ||
296 | return -EIO; | ||
297 | } | ||
298 | if (le16_to_cpu(attr_hdr->type) != type_code) { | ||
299 | dev_err(dev, "WLP: Unexpected attribute type. Got %u, " | ||
300 | "expected %u.\n", le16_to_cpu(attr_hdr->type), | ||
301 | type_code); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | len = le16_to_cpu(attr_hdr->length); | ||
305 | if (len > max_value_len) { | ||
306 | dev_err(dev, "WLP: Attribute larger than maximum " | ||
307 | "allowed. Received %zu, max is %d.\n", len, | ||
308 | (int)max_value_len); | ||
309 | return -EFBIG; | ||
310 | } | ||
311 | if (buflen < sizeof(*attr_hdr) + len) { | ||
312 | dev_err(dev, "WLP: Not enough space in buffer to parse " | ||
313 | "variable data.\n"); | ||
314 | return -EIO; | ||
315 | } | ||
316 | memcpy(value, (void *)attr_hdr + sizeof(*attr_hdr), len); | ||
317 | return sizeof(*attr_hdr) + len; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * Get value of attribute from fixed size attribute field. | ||
322 | * | ||
323 | * @attr: Pointer to attribute field. | ||
324 | * @value: Pointer to variable in which attribute value will be placed. | ||
325 | * @buflen: Size of buffer in which attribute field (including header) | ||
326 | * can be found. | ||
327 | * @returns: Amount of given buffer consumed by parsing for this attribute. | ||
328 | * | ||
329 | * The size and type of the value is known by the type of the attribute. | ||
330 | */ | ||
331 | #define wlp_get(type, type_code, name) \ | ||
332 | ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr, \ | ||
333 | type *value, ssize_t buflen) \ | ||
334 | { \ | ||
335 | return wlp_get_attribute(wlp, (type_code), &attr->hdr, \ | ||
336 | value, sizeof(*value), buflen); \ | ||
337 | } | ||
338 | |||
339 | #define wlp_get_sparse(type, type_code, name) \ | ||
340 | static wlp_get(type, type_code, name) | ||
341 | |||
342 | /** | ||
343 | * Get value of attribute from variable sized attribute field. | ||
344 | * | ||
345 | * @max: The maximum size of this attribute. This value is dictated by | ||
346 | * the maximum value from the WLP specification. | ||
347 | * | ||
348 | * @attr: Pointer to attribute field. | ||
349 | * @value: Pointer to variable that will contain the value. The memory | ||
350 | * must already have been allocated for this value. | ||
351 | * @buflen: Size of buffer in which attribute field (including header) | ||
352 | * can be found. | ||
353 | * @returns: Amount of given bufferconsumed by parsing for this attribute. | ||
354 | */ | ||
355 | #define wlp_vget(type_val, type_code, name, max) \ | ||
356 | static ssize_t wlp_get_##name(struct wlp *wlp, \ | ||
357 | struct wlp_attr_##name *attr, \ | ||
358 | type_val *value, ssize_t buflen) \ | ||
359 | { \ | ||
360 | return wlp_vget_attribute(wlp, (type_code), &attr->hdr, \ | ||
361 | value, (max), buflen); \ | ||
362 | } | ||
363 | |||
364 | wlp_get(u8, WLP_ATTR_WLP_VER, version) | ||
365 | wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd) | ||
366 | wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type) | ||
367 | wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err) | ||
368 | wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e) | ||
369 | wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r) | ||
370 | wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid) | ||
371 | wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl) | ||
372 | wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status) | ||
373 | wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast) | ||
374 | wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag) | ||
375 | wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt) | ||
376 | wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce) | ||
377 | wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce) | ||
378 | |||
379 | /* The buffers for the device info attributes can be found in the | ||
380 | * wlp_device_info struct. These buffers contain one byte more than the | ||
381 | * max allowed by the spec - this is done to be able to add the | ||
382 | * terminating \0 for user display. This terminating byte is not required | ||
383 | * in the actual attribute field (because it has a length field) so the | ||
384 | * maximum allowed for this value is one less than its size in the | ||
385 | * structure. | ||
386 | */ | ||
387 | wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name, | ||
388 | FIELD_SIZEOF(struct wlp_wss, name) - 1) | ||
389 | wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name, | ||
390 | FIELD_SIZEOF(struct wlp_device_info, name) - 1) | ||
391 | wlp_vget(char, WLP_ATTR_MANUF, manufacturer, | ||
392 | FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1) | ||
393 | wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name, | ||
394 | FIELD_SIZEOF(struct wlp_device_info, model_name) - 1) | ||
395 | wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr, | ||
396 | FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1) | ||
397 | wlp_vget(char, WLP_ATTR_SERIAL, serial, | ||
398 | FIELD_SIZEOF(struct wlp_device_info, serial) - 1) | ||
399 | |||
400 | /** | ||
401 | * Retrieve WSS Name, Accept enroll, Secure status, Broadcast from WSS info | ||
402 | * | ||
403 | * @attr: pointer to WSS name attribute in WSS information attribute field | ||
404 | * @info: structure that will be populated with data from WSS information | ||
405 | * field (WSS name, Accept enroll, secure status, broadcast address) | ||
406 | * @buflen: size of buffer | ||
407 | * | ||
408 | * Although the WSSID attribute forms part of the WSS info attribute it is | ||
409 | * retrieved separately and stored in a different location. | ||
410 | */ | ||
411 | static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp, | ||
412 | struct wlp_attr_hdr *attr, | ||
413 | struct wlp_wss_tmp_info *info, | ||
414 | ssize_t buflen) | ||
415 | { | ||
416 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
417 | void *ptr = attr; | ||
418 | size_t used = 0; | ||
419 | ssize_t result = -EINVAL; | ||
420 | |||
421 | result = wlp_get_wss_name(wlp, ptr, info->name, buflen); | ||
422 | if (result < 0) { | ||
423 | dev_err(dev, "WLP: unable to obtain WSS name from " | ||
424 | "WSS info in D2 message.\n"); | ||
425 | goto error_parse; | ||
426 | } | ||
427 | used += result; | ||
428 | |||
429 | result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll, | ||
430 | buflen - used); | ||
431 | if (result < 0) { | ||
432 | dev_err(dev, "WLP: unable to obtain accepting " | ||
433 | "enrollment from WSS info in D2 message.\n"); | ||
434 | goto error_parse; | ||
435 | } | ||
436 | if (info->accept_enroll != 0 && info->accept_enroll != 1) { | ||
437 | dev_err(dev, "WLP: invalid value for accepting " | ||
438 | "enrollment in D2 message.\n"); | ||
439 | result = -EINVAL; | ||
440 | goto error_parse; | ||
441 | } | ||
442 | used += result; | ||
443 | |||
444 | result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status, | ||
445 | buflen - used); | ||
446 | if (result < 0) { | ||
447 | dev_err(dev, "WLP: unable to obtain secure " | ||
448 | "status from WSS info in D2 message.\n"); | ||
449 | goto error_parse; | ||
450 | } | ||
451 | if (info->sec_status != 0 && info->sec_status != 1) { | ||
452 | dev_err(dev, "WLP: invalid value for secure " | ||
453 | "status in D2 message.\n"); | ||
454 | result = -EINVAL; | ||
455 | goto error_parse; | ||
456 | } | ||
457 | used += result; | ||
458 | |||
459 | result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast, | ||
460 | buflen - used); | ||
461 | if (result < 0) { | ||
462 | dev_err(dev, "WLP: unable to obtain broadcast " | ||
463 | "address from WSS info in D2 message.\n"); | ||
464 | goto error_parse; | ||
465 | } | ||
466 | used += result; | ||
467 | result = used; | ||
468 | error_parse: | ||
469 | return result; | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * Create a new WSSID entry for the neighbor, allocate temporary storage | ||
474 | * | ||
475 | * Each neighbor can have many WSS active. We maintain a list of WSSIDs | ||
476 | * advertised by neighbor. During discovery we also cache information about | ||
477 | * these WSS in temporary storage. | ||
478 | * | ||
479 | * The temporary storage will be removed after it has been used (eg. | ||
480 | * displayed to user), the wssid element will be removed from the list when | ||
481 | * the neighbor is rediscovered or when it disappears. | ||
482 | */ | ||
483 | static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp, | ||
484 | struct wlp_neighbor_e *neighbor) | ||
485 | { | ||
486 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
487 | struct wlp_wssid_e *wssid_e; | ||
488 | |||
489 | wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL); | ||
490 | if (wssid_e == NULL) { | ||
491 | dev_err(dev, "WLP: unable to allocate memory " | ||
492 | "for WSS information.\n"); | ||
493 | goto error_alloc; | ||
494 | } | ||
495 | wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL); | ||
496 | if (wssid_e->info == NULL) { | ||
497 | dev_err(dev, "WLP: unable to allocate memory " | ||
498 | "for temporary WSS information.\n"); | ||
499 | kfree(wssid_e); | ||
500 | wssid_e = NULL; | ||
501 | goto error_alloc; | ||
502 | } | ||
503 | list_add(&wssid_e->node, &neighbor->wssid); | ||
504 | error_alloc: | ||
505 | return wssid_e; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * Parse WSS information attribute | ||
510 | * | ||
511 | * @attr: pointer to WSS information attribute header | ||
512 | * @buflen: size of buffer in which WSS information attribute appears | ||
513 | * @wssid: will place wssid from WSS info attribute in this location | ||
514 | * @wss_info: will place other information from WSS information attribute | ||
515 | * in this location | ||
516 | * | ||
517 | * memory for @wssid and @wss_info must be allocated when calling this | ||
518 | */ | ||
519 | static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr, | ||
520 | size_t buflen, struct wlp_uuid *wssid, | ||
521 | struct wlp_wss_tmp_info *wss_info) | ||
522 | { | ||
523 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
524 | ssize_t result; | ||
525 | size_t len; | ||
526 | size_t used = 0; | ||
527 | void *ptr; | ||
528 | |||
529 | result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr, | ||
530 | buflen); | ||
531 | if (result < 0) | ||
532 | goto out; | ||
533 | len = result; | ||
534 | used = sizeof(*attr); | ||
535 | ptr = attr; | ||
536 | |||
537 | result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used); | ||
538 | if (result < 0) { | ||
539 | dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n"); | ||
540 | goto out; | ||
541 | } | ||
542 | used += result; | ||
543 | result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info, | ||
544 | buflen - used); | ||
545 | if (result < 0) { | ||
546 | dev_err(dev, "WLP: unable to obtain WSS information " | ||
547 | "from WSS information attributes. \n"); | ||
548 | goto out; | ||
549 | } | ||
550 | used += result; | ||
551 | if (len + sizeof(*attr) != used) { | ||
552 | dev_err(dev, "WLP: Amount of data parsed does not " | ||
553 | "match length field. Parsed %zu, length " | ||
554 | "field %zu. \n", used, len); | ||
555 | result = -EINVAL; | ||
556 | goto out; | ||
557 | } | ||
558 | result = used; | ||
559 | out: | ||
560 | return result; | ||
561 | } | ||
562 | |||
563 | /** | ||
564 | * Retrieve WSS info from association frame | ||
565 | * | ||
566 | * @attr: pointer to WSS information attribute | ||
567 | * @neighbor: ptr to neighbor being discovered, NULL if enrollment in | ||
568 | * progress | ||
569 | * @wss: ptr to WSS being enrolled in, NULL if discovery in progress | ||
570 | * @buflen: size of buffer in which WSS information appears | ||
571 | * | ||
572 | * The WSS information attribute appears in the D2 association message. | ||
573 | * This message is used in two ways: to discover all neighbors or to enroll | ||
574 | * into a WSS activated by a neighbor. During discovery we only want to | ||
575 | * store the WSS info in a cache, to be deleted right after it has been | ||
576 | * used (eg. displayed to the user). During enrollment we store the WSS | ||
577 | * information for the lifetime of enrollment. | ||
578 | * | ||
579 | * During discovery we are interested in all WSS information, during | ||
580 | * enrollment we are only interested in the WSS being enrolled in. Even so, | ||
581 | * when in enrollment we keep parsing the message after finding the WSS of | ||
582 | * interest, this simplifies the calling routine in that it can be sure | ||
583 | * that all WSS information attributes have been parsed out of the message. | ||
584 | * | ||
585 | * Association frame is process with nbmutex held. The list access is safe. | ||
586 | */ | ||
587 | static ssize_t wlp_get_all_wss_info(struct wlp *wlp, | ||
588 | struct wlp_attr_wss_info *attr, | ||
589 | struct wlp_neighbor_e *neighbor, | ||
590 | struct wlp_wss *wss, ssize_t buflen) | ||
591 | { | ||
592 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
593 | size_t used = 0; | ||
594 | ssize_t result = -EINVAL; | ||
595 | struct wlp_attr_wss_info *cur; | ||
596 | struct wlp_uuid wssid; | ||
597 | struct wlp_wss_tmp_info wss_info; | ||
598 | unsigned enroll; /* 0 - discovery to cache, 1 - enrollment */ | ||
599 | struct wlp_wssid_e *wssid_e; | ||
600 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
601 | |||
602 | if (buflen < 0) | ||
603 | goto out; | ||
604 | |||
605 | if (neighbor != NULL && wss == NULL) | ||
606 | enroll = 0; /* discovery */ | ||
607 | else if (wss != NULL && neighbor == NULL) | ||
608 | enroll = 1; /* enrollment */ | ||
609 | else | ||
610 | goto out; | ||
611 | |||
612 | cur = attr; | ||
613 | while (buflen - used > 0) { | ||
614 | memset(&wss_info, 0, sizeof(wss_info)); | ||
615 | cur = (void *)cur + used; | ||
616 | result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid, | ||
617 | &wss_info); | ||
618 | if (result == -ENODATA) { | ||
619 | result = used; | ||
620 | goto out; | ||
621 | } else if (result < 0) { | ||
622 | dev_err(dev, "WLP: Unable to parse WSS information " | ||
623 | "from WSS information attribute. \n"); | ||
624 | result = -EINVAL; | ||
625 | goto error_parse; | ||
626 | } | ||
627 | if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) { | ||
628 | if (wss_info.accept_enroll != 1) { | ||
629 | dev_err(dev, "WLP: Requested WSS does " | ||
630 | "not accept enrollment.\n"); | ||
631 | result = -EINVAL; | ||
632 | goto out; | ||
633 | } | ||
634 | memcpy(wss->name, wss_info.name, sizeof(wss->name)); | ||
635 | wss->bcast = wss_info.bcast; | ||
636 | wss->secure_status = wss_info.sec_status; | ||
637 | wss->accept_enroll = wss_info.accept_enroll; | ||
638 | wss->state = WLP_WSS_STATE_PART_ENROLLED; | ||
639 | wlp_wss_uuid_print(buf, sizeof(buf), &wssid); | ||
640 | dev_dbg(dev, "WLP: Found WSS %s. Enrolling.\n", buf); | ||
641 | } else { | ||
642 | wssid_e = wlp_create_wssid_e(wlp, neighbor); | ||
643 | if (wssid_e == NULL) { | ||
644 | dev_err(dev, "WLP: Cannot create new WSSID " | ||
645 | "entry for neighbor %02x:%02x.\n", | ||
646 | neighbor->uwb_dev->dev_addr.data[1], | ||
647 | neighbor->uwb_dev->dev_addr.data[0]); | ||
648 | result = -ENOMEM; | ||
649 | goto out; | ||
650 | } | ||
651 | wssid_e->wssid = wssid; | ||
652 | *wssid_e->info = wss_info; | ||
653 | } | ||
654 | used += result; | ||
655 | } | ||
656 | result = used; | ||
657 | error_parse: | ||
658 | if (result < 0 && !enroll) /* this was a discovery */ | ||
659 | wlp_remove_neighbor_tmp_info(neighbor); | ||
660 | out: | ||
661 | return result; | ||
662 | |||
663 | } | ||
664 | |||
665 | /** | ||
666 | * Parse WSS information attributes into cache for discovery | ||
667 | * | ||
668 | * @attr: the first WSS information attribute in message | ||
669 | * @neighbor: the neighbor whose cache will be populated | ||
670 | * @buflen: size of the input buffer | ||
671 | */ | ||
672 | static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp, | ||
673 | struct wlp_attr_wss_info *attr, | ||
674 | struct wlp_neighbor_e *neighbor, | ||
675 | ssize_t buflen) | ||
676 | { | ||
677 | return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen); | ||
678 | } | ||
679 | |||
680 | /** | ||
681 | * Parse WSS information attributes into WSS struct for enrollment | ||
682 | * | ||
683 | * @attr: the first WSS information attribute in message | ||
684 | * @wss: the WSS that will be enrolled | ||
685 | * @buflen: size of the input buffer | ||
686 | */ | ||
687 | static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp, | ||
688 | struct wlp_attr_wss_info *attr, | ||
689 | struct wlp_wss *wss, ssize_t buflen) | ||
690 | { | ||
691 | return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen); | ||
692 | } | ||
693 | |||
694 | /** | ||
695 | * Construct a D1 association frame | ||
696 | * | ||
697 | * We use the radio control functions to determine the values of the device | ||
698 | * properties. These are of variable length and the total space needed is | ||
699 | * tallied first before we start constructing the message. The radio | ||
700 | * control functions return strings that are terminated with \0. This | ||
701 | * character should not be included in the message (there is a length field | ||
702 | * accompanying it in the attribute). | ||
703 | */ | ||
704 | static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss, | ||
705 | struct sk_buff **skb) | ||
706 | { | ||
707 | |||
708 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
709 | int result = 0; | ||
710 | struct wlp_device_info *info; | ||
711 | size_t used = 0; | ||
712 | struct wlp_frame_assoc *_d1; | ||
713 | struct sk_buff *_skb; | ||
714 | void *d1_itr; | ||
715 | |||
716 | if (wlp->dev_info == NULL) { | ||
717 | result = __wlp_setup_device_info(wlp); | ||
718 | if (result < 0) { | ||
719 | dev_err(dev, "WLP: Unable to setup device " | ||
720 | "information for D1 message.\n"); | ||
721 | goto error; | ||
722 | } | ||
723 | } | ||
724 | info = wlp->dev_info; | ||
725 | _skb = dev_alloc_skb(sizeof(*_d1) | ||
726 | + sizeof(struct wlp_attr_uuid_e) | ||
727 | + sizeof(struct wlp_attr_wss_sel_mthd) | ||
728 | + sizeof(struct wlp_attr_dev_name) | ||
729 | + strlen(info->name) | ||
730 | + sizeof(struct wlp_attr_manufacturer) | ||
731 | + strlen(info->manufacturer) | ||
732 | + sizeof(struct wlp_attr_model_name) | ||
733 | + strlen(info->model_name) | ||
734 | + sizeof(struct wlp_attr_model_nr) | ||
735 | + strlen(info->model_nr) | ||
736 | + sizeof(struct wlp_attr_serial) | ||
737 | + strlen(info->serial) | ||
738 | + sizeof(struct wlp_attr_prim_dev_type) | ||
739 | + sizeof(struct wlp_attr_wlp_assc_err)); | ||
740 | if (_skb == NULL) { | ||
741 | dev_err(dev, "WLP: Cannot allocate memory for association " | ||
742 | "message.\n"); | ||
743 | result = -ENOMEM; | ||
744 | goto error; | ||
745 | } | ||
746 | _d1 = (void *) _skb->data; | ||
747 | _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
748 | _d1->hdr.type = WLP_FRAME_ASSOCIATION; | ||
749 | _d1->type = WLP_ASSOC_D1; | ||
750 | |||
751 | wlp_set_version(&_d1->version, WLP_VERSION); | ||
752 | wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1); | ||
753 | d1_itr = _d1->attr; | ||
754 | used = wlp_set_uuid_e(d1_itr, &wlp->uuid); | ||
755 | used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT); | ||
756 | used += wlp_set_dev_name(d1_itr + used, info->name, | ||
757 | strlen(info->name)); | ||
758 | used += wlp_set_manufacturer(d1_itr + used, info->manufacturer, | ||
759 | strlen(info->manufacturer)); | ||
760 | used += wlp_set_model_name(d1_itr + used, info->model_name, | ||
761 | strlen(info->model_name)); | ||
762 | used += wlp_set_model_nr(d1_itr + used, info->model_nr, | ||
763 | strlen(info->model_nr)); | ||
764 | used += wlp_set_serial(d1_itr + used, info->serial, | ||
765 | strlen(info->serial)); | ||
766 | used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type); | ||
767 | used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE); | ||
768 | skb_put(_skb, sizeof(*_d1) + used); | ||
769 | *skb = _skb; | ||
770 | error: | ||
771 | return result; | ||
772 | } | ||
773 | |||
774 | /** | ||
775 | * Construct a D2 association frame | ||
776 | * | ||
777 | * We use the radio control functions to determine the values of the device | ||
778 | * properties. These are of variable length and the total space needed is | ||
779 | * tallied first before we start constructing the message. The radio | ||
780 | * control functions return strings that are terminated with \0. This | ||
781 | * character should not be included in the message (there is a length field | ||
782 | * accompanying it in the attribute). | ||
783 | */ | ||
784 | static | ||
785 | int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss, | ||
786 | struct sk_buff **skb, struct wlp_uuid *uuid_e) | ||
787 | { | ||
788 | |||
789 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
790 | int result = 0; | ||
791 | struct wlp_device_info *info; | ||
792 | size_t used = 0; | ||
793 | struct wlp_frame_assoc *_d2; | ||
794 | struct sk_buff *_skb; | ||
795 | void *d2_itr; | ||
796 | size_t mem_needed; | ||
797 | |||
798 | if (wlp->dev_info == NULL) { | ||
799 | result = __wlp_setup_device_info(wlp); | ||
800 | if (result < 0) { | ||
801 | dev_err(dev, "WLP: Unable to setup device " | ||
802 | "information for D2 message.\n"); | ||
803 | goto error; | ||
804 | } | ||
805 | } | ||
806 | info = wlp->dev_info; | ||
807 | mem_needed = sizeof(*_d2) | ||
808 | + sizeof(struct wlp_attr_uuid_e) | ||
809 | + sizeof(struct wlp_attr_uuid_r) | ||
810 | + sizeof(struct wlp_attr_dev_name) | ||
811 | + strlen(info->name) | ||
812 | + sizeof(struct wlp_attr_manufacturer) | ||
813 | + strlen(info->manufacturer) | ||
814 | + sizeof(struct wlp_attr_model_name) | ||
815 | + strlen(info->model_name) | ||
816 | + sizeof(struct wlp_attr_model_nr) | ||
817 | + strlen(info->model_nr) | ||
818 | + sizeof(struct wlp_attr_serial) | ||
819 | + strlen(info->serial) | ||
820 | + sizeof(struct wlp_attr_prim_dev_type) | ||
821 | + sizeof(struct wlp_attr_wlp_assc_err); | ||
822 | if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE) | ||
823 | mem_needed += sizeof(struct wlp_attr_wss_info) | ||
824 | + sizeof(struct wlp_wss_info) | ||
825 | + strlen(wlp->wss.name); | ||
826 | _skb = dev_alloc_skb(mem_needed); | ||
827 | if (_skb == NULL) { | ||
828 | dev_err(dev, "WLP: Cannot allocate memory for association " | ||
829 | "message.\n"); | ||
830 | result = -ENOMEM; | ||
831 | goto error; | ||
832 | } | ||
833 | _d2 = (void *) _skb->data; | ||
834 | _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
835 | _d2->hdr.type = WLP_FRAME_ASSOCIATION; | ||
836 | _d2->type = WLP_ASSOC_D2; | ||
837 | |||
838 | wlp_set_version(&_d2->version, WLP_VERSION); | ||
839 | wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2); | ||
840 | d2_itr = _d2->attr; | ||
841 | used = wlp_set_uuid_e(d2_itr, uuid_e); | ||
842 | used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid); | ||
843 | if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE) | ||
844 | used += wlp_set_wss_info(d2_itr + used, &wlp->wss); | ||
845 | used += wlp_set_dev_name(d2_itr + used, info->name, | ||
846 | strlen(info->name)); | ||
847 | used += wlp_set_manufacturer(d2_itr + used, info->manufacturer, | ||
848 | strlen(info->manufacturer)); | ||
849 | used += wlp_set_model_name(d2_itr + used, info->model_name, | ||
850 | strlen(info->model_name)); | ||
851 | used += wlp_set_model_nr(d2_itr + used, info->model_nr, | ||
852 | strlen(info->model_nr)); | ||
853 | used += wlp_set_serial(d2_itr + used, info->serial, | ||
854 | strlen(info->serial)); | ||
855 | used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type); | ||
856 | used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE); | ||
857 | skb_put(_skb, sizeof(*_d2) + used); | ||
858 | *skb = _skb; | ||
859 | error: | ||
860 | return result; | ||
861 | } | ||
862 | |||
863 | /** | ||
864 | * Allocate memory for and populate fields of F0 association frame | ||
865 | * | ||
866 | * Currently (while focusing on unsecure enrollment) we ignore the | ||
867 | * nonce's that could be placed in the message. Only the error field is | ||
868 | * populated by the value provided by the caller. | ||
869 | */ | ||
870 | static | ||
871 | int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb, | ||
872 | enum wlp_assc_error error) | ||
873 | { | ||
874 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
875 | int result = -ENOMEM; | ||
876 | struct { | ||
877 | struct wlp_frame_assoc f0_hdr; | ||
878 | struct wlp_attr_enonce enonce; | ||
879 | struct wlp_attr_rnonce rnonce; | ||
880 | struct wlp_attr_wlp_assc_err assc_err; | ||
881 | } *f0; | ||
882 | struct sk_buff *_skb; | ||
883 | struct wlp_nonce tmp; | ||
884 | |||
885 | _skb = dev_alloc_skb(sizeof(*f0)); | ||
886 | if (_skb == NULL) { | ||
887 | dev_err(dev, "WLP: Unable to allocate memory for F0 " | ||
888 | "association frame. \n"); | ||
889 | goto error_alloc; | ||
890 | } | ||
891 | f0 = (void *) _skb->data; | ||
892 | f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
893 | f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION; | ||
894 | f0->f0_hdr.type = WLP_ASSOC_F0; | ||
895 | wlp_set_version(&f0->f0_hdr.version, WLP_VERSION); | ||
896 | wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0); | ||
897 | memset(&tmp, 0, sizeof(tmp)); | ||
898 | wlp_set_enonce(&f0->enonce, &tmp); | ||
899 | wlp_set_rnonce(&f0->rnonce, &tmp); | ||
900 | wlp_set_wlp_assc_err(&f0->assc_err, error); | ||
901 | skb_put(_skb, sizeof(*f0)); | ||
902 | *skb = _skb; | ||
903 | result = 0; | ||
904 | error_alloc: | ||
905 | return result; | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * Parse F0 frame | ||
910 | * | ||
911 | * We just retrieve the values and print it as an error to the user. | ||
912 | * Calling function already knows an error occured (F0 indicates error), so | ||
913 | * we just parse the content as debug for higher layers. | ||
914 | */ | ||
915 | int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb) | ||
916 | { | ||
917 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
918 | struct wlp_frame_assoc *f0 = (void *) skb->data; | ||
919 | void *ptr = skb->data; | ||
920 | size_t len = skb->len; | ||
921 | size_t used; | ||
922 | ssize_t result; | ||
923 | struct wlp_nonce enonce, rnonce; | ||
924 | enum wlp_assc_error assc_err; | ||
925 | char enonce_buf[WLP_WSS_NONCE_STRSIZE]; | ||
926 | char rnonce_buf[WLP_WSS_NONCE_STRSIZE]; | ||
927 | |||
928 | used = sizeof(*f0); | ||
929 | result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used); | ||
930 | if (result < 0) { | ||
931 | dev_err(dev, "WLP: unable to obtain Enrollee nonce " | ||
932 | "attribute from F0 message.\n"); | ||
933 | goto error_parse; | ||
934 | } | ||
935 | used += result; | ||
936 | result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used); | ||
937 | if (result < 0) { | ||
938 | dev_err(dev, "WLP: unable to obtain Registrar nonce " | ||
939 | "attribute from F0 message.\n"); | ||
940 | goto error_parse; | ||
941 | } | ||
942 | used += result; | ||
943 | result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used); | ||
944 | if (result < 0) { | ||
945 | dev_err(dev, "WLP: unable to obtain WLP Association error " | ||
946 | "attribute from F0 message.\n"); | ||
947 | goto error_parse; | ||
948 | } | ||
949 | wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce); | ||
950 | wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce); | ||
951 | dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee " | ||
952 | "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n", | ||
953 | enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err)); | ||
954 | result = 0; | ||
955 | error_parse: | ||
956 | return result; | ||
957 | } | ||
958 | |||
959 | /** | ||
960 | * Retrieve variable device information from association message | ||
961 | * | ||
962 | * The device information parsed is not required in any message. This | ||
963 | * routine will thus not fail if an attribute is not present. | ||
964 | * The attributes are expected in a certain order, even if all are not | ||
965 | * present. The "attribute type" value is used to ensure the attributes | ||
966 | * are parsed in the correct order. | ||
967 | * | ||
968 | * If an error is encountered during parsing the function will return an | ||
969 | * error code, when this happens the given device_info structure may be | ||
970 | * partially filled. | ||
971 | */ | ||
972 | static | ||
973 | int wlp_get_variable_info(struct wlp *wlp, void *data, | ||
974 | struct wlp_device_info *dev_info, ssize_t len) | ||
975 | { | ||
976 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
977 | size_t used = 0; | ||
978 | struct wlp_attr_hdr *hdr; | ||
979 | ssize_t result = 0; | ||
980 | unsigned last = 0; | ||
981 | |||
982 | while (len - used > 0) { | ||
983 | if (len - used < sizeof(*hdr)) { | ||
984 | dev_err(dev, "WLP: Partial data in frame, cannot " | ||
985 | "parse. \n"); | ||
986 | goto error_parse; | ||
987 | } | ||
988 | hdr = data + used; | ||
989 | switch (le16_to_cpu(hdr->type)) { | ||
990 | case WLP_ATTR_MANUF: | ||
991 | if (last >= WLP_ATTR_MANUF) { | ||
992 | dev_err(dev, "WLP: Incorrect order of " | ||
993 | "attribute values in D1 msg.\n"); | ||
994 | goto error_parse; | ||
995 | } | ||
996 | result = wlp_get_manufacturer(wlp, data + used, | ||
997 | dev_info->manufacturer, | ||
998 | len - used); | ||
999 | if (result < 0) { | ||
1000 | dev_err(dev, "WLP: Unable to obtain " | ||
1001 | "Manufacturer attribute from D1 " | ||
1002 | "message.\n"); | ||
1003 | goto error_parse; | ||
1004 | } | ||
1005 | last = WLP_ATTR_MANUF; | ||
1006 | used += result; | ||
1007 | break; | ||
1008 | case WLP_ATTR_MODEL_NAME: | ||
1009 | if (last >= WLP_ATTR_MODEL_NAME) { | ||
1010 | dev_err(dev, "WLP: Incorrect order of " | ||
1011 | "attribute values in D1 msg.\n"); | ||
1012 | goto error_parse; | ||
1013 | } | ||
1014 | result = wlp_get_model_name(wlp, data + used, | ||
1015 | dev_info->model_name, | ||
1016 | len - used); | ||
1017 | if (result < 0) { | ||
1018 | dev_err(dev, "WLP: Unable to obtain Model " | ||
1019 | "name attribute from D1 message.\n"); | ||
1020 | goto error_parse; | ||
1021 | } | ||
1022 | last = WLP_ATTR_MODEL_NAME; | ||
1023 | used += result; | ||
1024 | break; | ||
1025 | case WLP_ATTR_MODEL_NR: | ||
1026 | if (last >= WLP_ATTR_MODEL_NR) { | ||
1027 | dev_err(dev, "WLP: Incorrect order of " | ||
1028 | "attribute values in D1 msg.\n"); | ||
1029 | goto error_parse; | ||
1030 | } | ||
1031 | result = wlp_get_model_nr(wlp, data + used, | ||
1032 | dev_info->model_nr, | ||
1033 | len - used); | ||
1034 | if (result < 0) { | ||
1035 | dev_err(dev, "WLP: Unable to obtain Model " | ||
1036 | "number attribute from D1 message.\n"); | ||
1037 | goto error_parse; | ||
1038 | } | ||
1039 | last = WLP_ATTR_MODEL_NR; | ||
1040 | used += result; | ||
1041 | break; | ||
1042 | case WLP_ATTR_SERIAL: | ||
1043 | if (last >= WLP_ATTR_SERIAL) { | ||
1044 | dev_err(dev, "WLP: Incorrect order of " | ||
1045 | "attribute values in D1 msg.\n"); | ||
1046 | goto error_parse; | ||
1047 | } | ||
1048 | result = wlp_get_serial(wlp, data + used, | ||
1049 | dev_info->serial, len - used); | ||
1050 | if (result < 0) { | ||
1051 | dev_err(dev, "WLP: Unable to obtain Serial " | ||
1052 | "number attribute from D1 message.\n"); | ||
1053 | goto error_parse; | ||
1054 | } | ||
1055 | last = WLP_ATTR_SERIAL; | ||
1056 | used += result; | ||
1057 | break; | ||
1058 | case WLP_ATTR_PRI_DEV_TYPE: | ||
1059 | if (last >= WLP_ATTR_PRI_DEV_TYPE) { | ||
1060 | dev_err(dev, "WLP: Incorrect order of " | ||
1061 | "attribute values in D1 msg.\n"); | ||
1062 | goto error_parse; | ||
1063 | } | ||
1064 | result = wlp_get_prim_dev_type(wlp, data + used, | ||
1065 | &dev_info->prim_dev_type, | ||
1066 | len - used); | ||
1067 | if (result < 0) { | ||
1068 | dev_err(dev, "WLP: Unable to obtain Primary " | ||
1069 | "device type attribute from D1 " | ||
1070 | "message.\n"); | ||
1071 | goto error_parse; | ||
1072 | } | ||
1073 | dev_info->prim_dev_type.category = | ||
1074 | le16_to_cpu(dev_info->prim_dev_type.category); | ||
1075 | dev_info->prim_dev_type.subID = | ||
1076 | le16_to_cpu(dev_info->prim_dev_type.subID); | ||
1077 | last = WLP_ATTR_PRI_DEV_TYPE; | ||
1078 | used += result; | ||
1079 | break; | ||
1080 | default: | ||
1081 | /* This is not variable device information. */ | ||
1082 | goto out; | ||
1083 | break; | ||
1084 | } | ||
1085 | } | ||
1086 | out: | ||
1087 | return used; | ||
1088 | error_parse: | ||
1089 | return -EINVAL; | ||
1090 | } | ||
1091 | |||
1092 | /** | ||
1093 | * Parse incoming D1 frame, populate attribute values | ||
1094 | * | ||
1095 | * Caller provides pointers to memory already allocated for attributes | ||
1096 | * expected in the D1 frame. These variables will be populated. | ||
1097 | */ | ||
1098 | static | ||
1099 | int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb, | ||
1100 | struct wlp_uuid *uuid_e, | ||
1101 | enum wlp_wss_sel_mthd *sel_mthd, | ||
1102 | struct wlp_device_info *dev_info, | ||
1103 | enum wlp_assc_error *assc_err) | ||
1104 | { | ||
1105 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1106 | struct wlp_frame_assoc *d1 = (void *) skb->data; | ||
1107 | void *ptr = skb->data; | ||
1108 | size_t len = skb->len; | ||
1109 | size_t used; | ||
1110 | ssize_t result; | ||
1111 | |||
1112 | used = sizeof(*d1); | ||
1113 | result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used); | ||
1114 | if (result < 0) { | ||
1115 | dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 " | ||
1116 | "message.\n"); | ||
1117 | goto error_parse; | ||
1118 | } | ||
1119 | used += result; | ||
1120 | result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used); | ||
1121 | if (result < 0) { | ||
1122 | dev_err(dev, "WLP: unable to obtain WSS selection method " | ||
1123 | "from D1 message.\n"); | ||
1124 | goto error_parse; | ||
1125 | } | ||
1126 | used += result; | ||
1127 | result = wlp_get_dev_name(wlp, ptr + used, dev_info->name, | ||
1128 | len - used); | ||
1129 | if (result < 0) { | ||
1130 | dev_err(dev, "WLP: unable to obtain Device Name from D1 " | ||
1131 | "message.\n"); | ||
1132 | goto error_parse; | ||
1133 | } | ||
1134 | used += result; | ||
1135 | result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used); | ||
1136 | if (result < 0) { | ||
1137 | dev_err(dev, "WLP: unable to obtain Device Information from " | ||
1138 | "D1 message.\n"); | ||
1139 | goto error_parse; | ||
1140 | } | ||
1141 | used += result; | ||
1142 | result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used); | ||
1143 | if (result < 0) { | ||
1144 | dev_err(dev, "WLP: unable to obtain WLP Association Error " | ||
1145 | "Information from D1 message.\n"); | ||
1146 | goto error_parse; | ||
1147 | } | ||
1148 | result = 0; | ||
1149 | error_parse: | ||
1150 | return result; | ||
1151 | } | ||
1152 | /** | ||
1153 | * Handle incoming D1 frame | ||
1154 | * | ||
1155 | * The frame has already been verified to contain an Association header with | ||
1156 | * the correct version number. Parse the incoming frame, construct and send | ||
1157 | * a D2 frame in response. | ||
1158 | * | ||
1159 | * It is not clear what to do with most fields in the incoming D1 frame. We | ||
1160 | * retrieve and discard the information here for now. | ||
1161 | */ | ||
1162 | void wlp_handle_d1_frame(struct work_struct *ws) | ||
1163 | { | ||
1164 | struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws, | ||
1165 | struct wlp_assoc_frame_ctx, | ||
1166 | ws); | ||
1167 | struct wlp *wlp = frame_ctx->wlp; | ||
1168 | struct wlp_wss *wss = &wlp->wss; | ||
1169 | struct sk_buff *skb = frame_ctx->skb; | ||
1170 | struct uwb_dev_addr *src = &frame_ctx->src; | ||
1171 | int result; | ||
1172 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1173 | struct wlp_uuid uuid_e; | ||
1174 | enum wlp_wss_sel_mthd sel_mthd = 0; | ||
1175 | struct wlp_device_info dev_info; | ||
1176 | enum wlp_assc_error assc_err; | ||
1177 | struct sk_buff *resp = NULL; | ||
1178 | |||
1179 | /* Parse D1 frame */ | ||
1180 | mutex_lock(&wss->mutex); | ||
1181 | mutex_lock(&wlp->mutex); /* to access wlp->uuid */ | ||
1182 | memset(&dev_info, 0, sizeof(dev_info)); | ||
1183 | result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info, | ||
1184 | &assc_err); | ||
1185 | if (result < 0) { | ||
1186 | dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n"); | ||
1187 | kfree_skb(skb); | ||
1188 | goto out; | ||
1189 | } | ||
1190 | |||
1191 | kfree_skb(skb); | ||
1192 | if (!wlp_uuid_is_set(&wlp->uuid)) { | ||
1193 | dev_err(dev, "WLP: UUID is not set. Set via sysfs to " | ||
1194 | "proceed. Respong to D1 message with error F0.\n"); | ||
1195 | result = wlp_build_assoc_f0(wlp, &resp, | ||
1196 | WLP_ASSOC_ERROR_NOT_READY); | ||
1197 | if (result < 0) { | ||
1198 | dev_err(dev, "WLP: Unable to construct F0 message.\n"); | ||
1199 | goto out; | ||
1200 | } | ||
1201 | } else { | ||
1202 | /* Construct D2 frame */ | ||
1203 | result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e); | ||
1204 | if (result < 0) { | ||
1205 | dev_err(dev, "WLP: Unable to construct D2 message.\n"); | ||
1206 | goto out; | ||
1207 | } | ||
1208 | } | ||
1209 | /* Send D2 frame */ | ||
1210 | BUG_ON(wlp->xmit_frame == NULL); | ||
1211 | result = wlp->xmit_frame(wlp, resp, src); | ||
1212 | if (result < 0) { | ||
1213 | dev_err(dev, "WLP: Unable to transmit D2 association " | ||
1214 | "message: %d\n", result); | ||
1215 | if (result == -ENXIO) | ||
1216 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
1217 | /* We could try again ... */ | ||
1218 | dev_kfree_skb_any(resp); /* we need to free if tx fails */ | ||
1219 | } | ||
1220 | out: | ||
1221 | kfree(frame_ctx); | ||
1222 | mutex_unlock(&wlp->mutex); | ||
1223 | mutex_unlock(&wss->mutex); | ||
1224 | } | ||
1225 | |||
1226 | /** | ||
1227 | * Parse incoming D2 frame, create and populate temporary cache | ||
1228 | * | ||
1229 | * @skb: socket buffer in which D2 frame can be found | ||
1230 | * @neighbor: the neighbor that sent the D2 frame | ||
1231 | * | ||
1232 | * Will allocate memory for temporary storage of information learned during | ||
1233 | * discovery. | ||
1234 | */ | ||
1235 | int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb, | ||
1236 | struct wlp_neighbor_e *neighbor) | ||
1237 | { | ||
1238 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1239 | struct wlp_frame_assoc *d2 = (void *) skb->data; | ||
1240 | void *ptr = skb->data; | ||
1241 | size_t len = skb->len; | ||
1242 | size_t used; | ||
1243 | ssize_t result; | ||
1244 | struct wlp_uuid uuid_e; | ||
1245 | struct wlp_device_info *nb_info; | ||
1246 | enum wlp_assc_error assc_err; | ||
1247 | |||
1248 | used = sizeof(*d2); | ||
1249 | result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used); | ||
1250 | if (result < 0) { | ||
1251 | dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 " | ||
1252 | "message.\n"); | ||
1253 | goto error_parse; | ||
1254 | } | ||
1255 | if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) { | ||
1256 | dev_err(dev, "WLP: UUID-E in incoming D2 does not match " | ||
1257 | "local UUID sent in D1. \n"); | ||
1258 | goto error_parse; | ||
1259 | } | ||
1260 | used += result; | ||
1261 | result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used); | ||
1262 | if (result < 0) { | ||
1263 | dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 " | ||
1264 | "message.\n"); | ||
1265 | goto error_parse; | ||
1266 | } | ||
1267 | used += result; | ||
1268 | result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor, | ||
1269 | len - used); | ||
1270 | if (result < 0) { | ||
1271 | dev_err(dev, "WLP: unable to obtain WSS information " | ||
1272 | "from D2 message.\n"); | ||
1273 | goto error_parse; | ||
1274 | } | ||
1275 | used += result; | ||
1276 | neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL); | ||
1277 | if (neighbor->info == NULL) { | ||
1278 | dev_err(dev, "WLP: cannot allocate memory to store device " | ||
1279 | "info.\n"); | ||
1280 | result = -ENOMEM; | ||
1281 | goto error_parse; | ||
1282 | } | ||
1283 | nb_info = neighbor->info; | ||
1284 | result = wlp_get_dev_name(wlp, ptr + used, nb_info->name, | ||
1285 | len - used); | ||
1286 | if (result < 0) { | ||
1287 | dev_err(dev, "WLP: unable to obtain Device Name from D2 " | ||
1288 | "message.\n"); | ||
1289 | goto error_parse; | ||
1290 | } | ||
1291 | used += result; | ||
1292 | result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used); | ||
1293 | if (result < 0) { | ||
1294 | dev_err(dev, "WLP: unable to obtain Device Information from " | ||
1295 | "D2 message.\n"); | ||
1296 | goto error_parse; | ||
1297 | } | ||
1298 | used += result; | ||
1299 | result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used); | ||
1300 | if (result < 0) { | ||
1301 | dev_err(dev, "WLP: unable to obtain WLP Association Error " | ||
1302 | "Information from D2 message.\n"); | ||
1303 | goto error_parse; | ||
1304 | } | ||
1305 | if (assc_err != WLP_ASSOC_ERROR_NONE) { | ||
1306 | dev_err(dev, "WLP: neighbor device returned association " | ||
1307 | "error %d\n", assc_err); | ||
1308 | result = -EINVAL; | ||
1309 | goto error_parse; | ||
1310 | } | ||
1311 | result = 0; | ||
1312 | error_parse: | ||
1313 | if (result < 0) | ||
1314 | wlp_remove_neighbor_tmp_info(neighbor); | ||
1315 | return result; | ||
1316 | } | ||
1317 | |||
1318 | /** | ||
1319 | * Parse incoming D2 frame, populate attribute values of WSS bein enrolled in | ||
1320 | * | ||
1321 | * @wss: our WSS that will be enrolled | ||
1322 | * @skb: socket buffer in which D2 frame can be found | ||
1323 | * @neighbor: the neighbor that sent the D2 frame | ||
1324 | * @wssid: the wssid of the WSS in which we want to enroll | ||
1325 | * | ||
1326 | * Forms part of enrollment sequence. We are trying to enroll in WSS with | ||
1327 | * @wssid by using @neighbor as registrar. A D1 message was sent to | ||
1328 | * @neighbor and now we need to parse the D2 response. The neighbor's | ||
1329 | * response is searched for the requested WSS and if found (and it accepts | ||
1330 | * enrollment), we store the information. | ||
1331 | */ | ||
1332 | int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb, | ||
1333 | struct wlp_neighbor_e *neighbor, | ||
1334 | struct wlp_uuid *wssid) | ||
1335 | { | ||
1336 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
1337 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1338 | void *ptr = skb->data; | ||
1339 | size_t len = skb->len; | ||
1340 | size_t used; | ||
1341 | ssize_t result; | ||
1342 | struct wlp_uuid uuid_e; | ||
1343 | struct wlp_uuid uuid_r; | ||
1344 | struct wlp_device_info nb_info; | ||
1345 | enum wlp_assc_error assc_err; | ||
1346 | char uuid_bufA[WLP_WSS_UUID_STRSIZE]; | ||
1347 | char uuid_bufB[WLP_WSS_UUID_STRSIZE]; | ||
1348 | |||
1349 | used = sizeof(struct wlp_frame_assoc); | ||
1350 | result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used); | ||
1351 | if (result < 0) { | ||
1352 | dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 " | ||
1353 | "message.\n"); | ||
1354 | goto error_parse; | ||
1355 | } | ||
1356 | if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) { | ||
1357 | dev_err(dev, "WLP: UUID-E in incoming D2 does not match " | ||
1358 | "local UUID sent in D1. \n"); | ||
1359 | goto error_parse; | ||
1360 | } | ||
1361 | used += result; | ||
1362 | result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used); | ||
1363 | if (result < 0) { | ||
1364 | dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 " | ||
1365 | "message.\n"); | ||
1366 | goto error_parse; | ||
1367 | } | ||
1368 | if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) { | ||
1369 | wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA), | ||
1370 | &neighbor->uuid); | ||
1371 | wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r); | ||
1372 | dev_err(dev, "WLP: UUID of neighbor does not match UUID " | ||
1373 | "learned during discovery. Originally discovered: %s, " | ||
1374 | "now from D2 message: %s\n", uuid_bufA, uuid_bufB); | ||
1375 | result = -EINVAL; | ||
1376 | goto error_parse; | ||
1377 | } | ||
1378 | used += result; | ||
1379 | wss->wssid = *wssid; | ||
1380 | result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used); | ||
1381 | if (result < 0) { | ||
1382 | dev_err(dev, "WLP: unable to obtain WSS information " | ||
1383 | "from D2 message.\n"); | ||
1384 | goto error_parse; | ||
1385 | } | ||
1386 | if (wss->state != WLP_WSS_STATE_PART_ENROLLED) { | ||
1387 | dev_err(dev, "WLP: D2 message did not contain information " | ||
1388 | "for successful enrollment. \n"); | ||
1389 | result = -EINVAL; | ||
1390 | goto error_parse; | ||
1391 | } | ||
1392 | used += result; | ||
1393 | /* Place device information on stack to continue parsing of message */ | ||
1394 | result = wlp_get_dev_name(wlp, ptr + used, nb_info.name, | ||
1395 | len - used); | ||
1396 | if (result < 0) { | ||
1397 | dev_err(dev, "WLP: unable to obtain Device Name from D2 " | ||
1398 | "message.\n"); | ||
1399 | goto error_parse; | ||
1400 | } | ||
1401 | used += result; | ||
1402 | result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used); | ||
1403 | if (result < 0) { | ||
1404 | dev_err(dev, "WLP: unable to obtain Device Information from " | ||
1405 | "D2 message.\n"); | ||
1406 | goto error_parse; | ||
1407 | } | ||
1408 | used += result; | ||
1409 | result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used); | ||
1410 | if (result < 0) { | ||
1411 | dev_err(dev, "WLP: unable to obtain WLP Association Error " | ||
1412 | "Information from D2 message.\n"); | ||
1413 | goto error_parse; | ||
1414 | } | ||
1415 | if (assc_err != WLP_ASSOC_ERROR_NONE) { | ||
1416 | dev_err(dev, "WLP: neighbor device returned association " | ||
1417 | "error %d\n", assc_err); | ||
1418 | if (wss->state == WLP_WSS_STATE_PART_ENROLLED) { | ||
1419 | dev_err(dev, "WLP: Enrolled in WSS (should not " | ||
1420 | "happen according to spec). Undoing. \n"); | ||
1421 | wlp_wss_reset(wss); | ||
1422 | } | ||
1423 | result = -EINVAL; | ||
1424 | goto error_parse; | ||
1425 | } | ||
1426 | result = 0; | ||
1427 | error_parse: | ||
1428 | return result; | ||
1429 | } | ||
1430 | |||
1431 | /** | ||
1432 | * Parse C3/C4 frame into provided variables | ||
1433 | * | ||
1434 | * @wssid: will point to copy of wssid retrieved from C3/C4 frame | ||
1435 | * @tag: will point to copy of tag retrieved from C3/C4 frame | ||
1436 | * @virt_addr: will point to copy of virtual address retrieved from C3/C4 | ||
1437 | * frame. | ||
1438 | * | ||
1439 | * Calling function has to allocate memory for these values. | ||
1440 | * | ||
1441 | * skb contains a valid C3/C4 frame, return the individual fields of this | ||
1442 | * frame in the provided variables. | ||
1443 | */ | ||
1444 | int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb, | ||
1445 | struct wlp_uuid *wssid, u8 *tag, | ||
1446 | struct uwb_mac_addr *virt_addr) | ||
1447 | { | ||
1448 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1449 | int result; | ||
1450 | void *ptr = skb->data; | ||
1451 | size_t len = skb->len; | ||
1452 | size_t used; | ||
1453 | struct wlp_frame_assoc *assoc = ptr; | ||
1454 | |||
1455 | used = sizeof(*assoc); | ||
1456 | result = wlp_get_wssid(wlp, ptr + used, wssid, len - used); | ||
1457 | if (result < 0) { | ||
1458 | dev_err(dev, "WLP: unable to obtain WSSID attribute from " | ||
1459 | "%s message.\n", wlp_assoc_frame_str(assoc->type)); | ||
1460 | goto error_parse; | ||
1461 | } | ||
1462 | used += result; | ||
1463 | result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used); | ||
1464 | if (result < 0) { | ||
1465 | dev_err(dev, "WLP: unable to obtain WSS tag attribute from " | ||
1466 | "%s message.\n", wlp_assoc_frame_str(assoc->type)); | ||
1467 | goto error_parse; | ||
1468 | } | ||
1469 | used += result; | ||
1470 | result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used); | ||
1471 | if (result < 0) { | ||
1472 | dev_err(dev, "WLP: unable to obtain WSS virtual address " | ||
1473 | "attribute from %s message.\n", | ||
1474 | wlp_assoc_frame_str(assoc->type)); | ||
1475 | goto error_parse; | ||
1476 | } | ||
1477 | error_parse: | ||
1478 | return result; | ||
1479 | } | ||
1480 | |||
1481 | /** | ||
1482 | * Allocate memory for and populate fields of C1 or C2 association frame | ||
1483 | * | ||
1484 | * The C1 and C2 association frames appear identical - except for the type. | ||
1485 | */ | ||
1486 | static | ||
1487 | int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss, | ||
1488 | struct sk_buff **skb, enum wlp_assoc_type type) | ||
1489 | { | ||
1490 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1491 | int result = -ENOMEM; | ||
1492 | struct { | ||
1493 | struct wlp_frame_assoc c_hdr; | ||
1494 | struct wlp_attr_wssid wssid; | ||
1495 | } *c; | ||
1496 | struct sk_buff *_skb; | ||
1497 | |||
1498 | _skb = dev_alloc_skb(sizeof(*c)); | ||
1499 | if (_skb == NULL) { | ||
1500 | dev_err(dev, "WLP: Unable to allocate memory for C1/C2 " | ||
1501 | "association frame. \n"); | ||
1502 | goto error_alloc; | ||
1503 | } | ||
1504 | c = (void *) _skb->data; | ||
1505 | c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
1506 | c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION; | ||
1507 | c->c_hdr.type = type; | ||
1508 | wlp_set_version(&c->c_hdr.version, WLP_VERSION); | ||
1509 | wlp_set_msg_type(&c->c_hdr.msg_type, type); | ||
1510 | wlp_set_wssid(&c->wssid, &wss->wssid); | ||
1511 | skb_put(_skb, sizeof(*c)); | ||
1512 | *skb = _skb; | ||
1513 | result = 0; | ||
1514 | error_alloc: | ||
1515 | return result; | ||
1516 | } | ||
1517 | |||
1518 | |||
1519 | static | ||
1520 | int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss, | ||
1521 | struct sk_buff **skb) | ||
1522 | { | ||
1523 | return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1); | ||
1524 | } | ||
1525 | |||
1526 | static | ||
1527 | int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss, | ||
1528 | struct sk_buff **skb) | ||
1529 | { | ||
1530 | return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2); | ||
1531 | } | ||
1532 | |||
1533 | |||
1534 | /** | ||
1535 | * Allocate memory for and populate fields of C3 or C4 association frame | ||
1536 | * | ||
1537 | * The C3 and C4 association frames appear identical - except for the type. | ||
1538 | */ | ||
1539 | static | ||
1540 | int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss, | ||
1541 | struct sk_buff **skb, enum wlp_assoc_type type) | ||
1542 | { | ||
1543 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1544 | int result = -ENOMEM; | ||
1545 | struct { | ||
1546 | struct wlp_frame_assoc c_hdr; | ||
1547 | struct wlp_attr_wssid wssid; | ||
1548 | struct wlp_attr_wss_tag wss_tag; | ||
1549 | struct wlp_attr_wss_virt wss_virt; | ||
1550 | } *c; | ||
1551 | struct sk_buff *_skb; | ||
1552 | |||
1553 | _skb = dev_alloc_skb(sizeof(*c)); | ||
1554 | if (_skb == NULL) { | ||
1555 | dev_err(dev, "WLP: Unable to allocate memory for C3/C4 " | ||
1556 | "association frame. \n"); | ||
1557 | goto error_alloc; | ||
1558 | } | ||
1559 | c = (void *) _skb->data; | ||
1560 | c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
1561 | c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION; | ||
1562 | c->c_hdr.type = type; | ||
1563 | wlp_set_version(&c->c_hdr.version, WLP_VERSION); | ||
1564 | wlp_set_msg_type(&c->c_hdr.msg_type, type); | ||
1565 | wlp_set_wssid(&c->wssid, &wss->wssid); | ||
1566 | wlp_set_wss_tag(&c->wss_tag, wss->tag); | ||
1567 | wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr); | ||
1568 | skb_put(_skb, sizeof(*c)); | ||
1569 | *skb = _skb; | ||
1570 | result = 0; | ||
1571 | error_alloc: | ||
1572 | return result; | ||
1573 | } | ||
1574 | |||
1575 | static | ||
1576 | int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss, | ||
1577 | struct sk_buff **skb) | ||
1578 | { | ||
1579 | return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3); | ||
1580 | } | ||
1581 | |||
1582 | static | ||
1583 | int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss, | ||
1584 | struct sk_buff **skb) | ||
1585 | { | ||
1586 | return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4); | ||
1587 | } | ||
1588 | |||
1589 | |||
1590 | #define wlp_send_assoc(type, id) \ | ||
1591 | static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \ | ||
1592 | struct uwb_dev_addr *dev_addr) \ | ||
1593 | { \ | ||
1594 | struct device *dev = &wlp->rc->uwb_dev.dev; \ | ||
1595 | int result; \ | ||
1596 | struct sk_buff *skb = NULL; \ | ||
1597 | \ | ||
1598 | /* Build the frame */ \ | ||
1599 | result = wlp_build_assoc_##type(wlp, wss, &skb); \ | ||
1600 | if (result < 0) { \ | ||
1601 | dev_err(dev, "WLP: Unable to construct %s association " \ | ||
1602 | "frame: %d\n", wlp_assoc_frame_str(id), result);\ | ||
1603 | goto error_build_assoc; \ | ||
1604 | } \ | ||
1605 | /* Send the frame */ \ | ||
1606 | BUG_ON(wlp->xmit_frame == NULL); \ | ||
1607 | result = wlp->xmit_frame(wlp, skb, dev_addr); \ | ||
1608 | if (result < 0) { \ | ||
1609 | dev_err(dev, "WLP: Unable to transmit %s association " \ | ||
1610 | "message: %d\n", wlp_assoc_frame_str(id), \ | ||
1611 | result); \ | ||
1612 | if (result == -ENXIO) \ | ||
1613 | dev_err(dev, "WLP: Is network interface " \ | ||
1614 | "up? \n"); \ | ||
1615 | goto error_xmit; \ | ||
1616 | } \ | ||
1617 | return 0; \ | ||
1618 | error_xmit: \ | ||
1619 | /* We could try again ... */ \ | ||
1620 | dev_kfree_skb_any(skb);/*we need to free if tx fails*/ \ | ||
1621 | error_build_assoc: \ | ||
1622 | return result; \ | ||
1623 | } | ||
1624 | |||
1625 | wlp_send_assoc(d1, WLP_ASSOC_D1) | ||
1626 | wlp_send_assoc(c1, WLP_ASSOC_C1) | ||
1627 | wlp_send_assoc(c3, WLP_ASSOC_C3) | ||
1628 | |||
1629 | int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss, | ||
1630 | struct uwb_dev_addr *dev_addr, | ||
1631 | enum wlp_assoc_type type) | ||
1632 | { | ||
1633 | int result = 0; | ||
1634 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1635 | switch (type) { | ||
1636 | case WLP_ASSOC_D1: | ||
1637 | result = wlp_send_assoc_d1(wlp, wss, dev_addr); | ||
1638 | break; | ||
1639 | case WLP_ASSOC_C1: | ||
1640 | result = wlp_send_assoc_c1(wlp, wss, dev_addr); | ||
1641 | break; | ||
1642 | case WLP_ASSOC_C3: | ||
1643 | result = wlp_send_assoc_c3(wlp, wss, dev_addr); | ||
1644 | break; | ||
1645 | default: | ||
1646 | dev_err(dev, "WLP: Received request to send unknown " | ||
1647 | "association message.\n"); | ||
1648 | result = -EINVAL; | ||
1649 | break; | ||
1650 | } | ||
1651 | return result; | ||
1652 | } | ||
1653 | |||
1654 | /** | ||
1655 | * Handle incoming C1 frame | ||
1656 | * | ||
1657 | * The frame has already been verified to contain an Association header with | ||
1658 | * the correct version number. Parse the incoming frame, construct and send | ||
1659 | * a C2 frame in response. | ||
1660 | */ | ||
1661 | void wlp_handle_c1_frame(struct work_struct *ws) | ||
1662 | { | ||
1663 | struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws, | ||
1664 | struct wlp_assoc_frame_ctx, | ||
1665 | ws); | ||
1666 | struct wlp *wlp = frame_ctx->wlp; | ||
1667 | struct wlp_wss *wss = &wlp->wss; | ||
1668 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1669 | struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data; | ||
1670 | unsigned int len = frame_ctx->skb->len; | ||
1671 | struct uwb_dev_addr *src = &frame_ctx->src; | ||
1672 | int result; | ||
1673 | struct wlp_uuid wssid; | ||
1674 | struct sk_buff *resp = NULL; | ||
1675 | |||
1676 | /* Parse C1 frame */ | ||
1677 | mutex_lock(&wss->mutex); | ||
1678 | result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid, | ||
1679 | len - sizeof(*c1)); | ||
1680 | if (result < 0) { | ||
1681 | dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n"); | ||
1682 | goto out; | ||
1683 | } | ||
1684 | if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)) | ||
1685 | && wss->state == WLP_WSS_STATE_ACTIVE) { | ||
1686 | /* Construct C2 frame */ | ||
1687 | result = wlp_build_assoc_c2(wlp, wss, &resp); | ||
1688 | if (result < 0) { | ||
1689 | dev_err(dev, "WLP: Unable to construct C2 message.\n"); | ||
1690 | goto out; | ||
1691 | } | ||
1692 | } else { | ||
1693 | /* Construct F0 frame */ | ||
1694 | result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV); | ||
1695 | if (result < 0) { | ||
1696 | dev_err(dev, "WLP: Unable to construct F0 message.\n"); | ||
1697 | goto out; | ||
1698 | } | ||
1699 | } | ||
1700 | /* Send C2 frame */ | ||
1701 | BUG_ON(wlp->xmit_frame == NULL); | ||
1702 | result = wlp->xmit_frame(wlp, resp, src); | ||
1703 | if (result < 0) { | ||
1704 | dev_err(dev, "WLP: Unable to transmit response association " | ||
1705 | "message: %d\n", result); | ||
1706 | if (result == -ENXIO) | ||
1707 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
1708 | /* We could try again ... */ | ||
1709 | dev_kfree_skb_any(resp); /* we need to free if tx fails */ | ||
1710 | } | ||
1711 | out: | ||
1712 | kfree_skb(frame_ctx->skb); | ||
1713 | kfree(frame_ctx); | ||
1714 | mutex_unlock(&wss->mutex); | ||
1715 | } | ||
1716 | |||
1717 | /** | ||
1718 | * Handle incoming C3 frame | ||
1719 | * | ||
1720 | * The frame has already been verified to contain an Association header with | ||
1721 | * the correct version number. Parse the incoming frame, construct and send | ||
1722 | * a C4 frame in response. If the C3 frame identifies a WSS that is locally | ||
1723 | * active then we connect to this neighbor (add it to our EDA cache). | ||
1724 | */ | ||
1725 | void wlp_handle_c3_frame(struct work_struct *ws) | ||
1726 | { | ||
1727 | struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws, | ||
1728 | struct wlp_assoc_frame_ctx, | ||
1729 | ws); | ||
1730 | struct wlp *wlp = frame_ctx->wlp; | ||
1731 | struct wlp_wss *wss = &wlp->wss; | ||
1732 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1733 | struct sk_buff *skb = frame_ctx->skb; | ||
1734 | struct uwb_dev_addr *src = &frame_ctx->src; | ||
1735 | int result; | ||
1736 | struct sk_buff *resp = NULL; | ||
1737 | struct wlp_uuid wssid; | ||
1738 | u8 tag; | ||
1739 | struct uwb_mac_addr virt_addr; | ||
1740 | |||
1741 | /* Parse C3 frame */ | ||
1742 | mutex_lock(&wss->mutex); | ||
1743 | result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr); | ||
1744 | if (result < 0) { | ||
1745 | dev_err(dev, "WLP: unable to obtain values from C3 frame.\n"); | ||
1746 | goto out; | ||
1747 | } | ||
1748 | if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)) | ||
1749 | && wss->state >= WLP_WSS_STATE_ACTIVE) { | ||
1750 | result = wlp_eda_update_node(&wlp->eda, src, wss, | ||
1751 | (void *) virt_addr.data, tag, | ||
1752 | WLP_WSS_CONNECTED); | ||
1753 | if (result < 0) { | ||
1754 | dev_err(dev, "WLP: Unable to update EDA cache " | ||
1755 | "with new connected neighbor information.\n"); | ||
1756 | result = wlp_build_assoc_f0(wlp, &resp, | ||
1757 | WLP_ASSOC_ERROR_INT); | ||
1758 | if (result < 0) { | ||
1759 | dev_err(dev, "WLP: Unable to construct F0 " | ||
1760 | "message.\n"); | ||
1761 | goto out; | ||
1762 | } | ||
1763 | } else { | ||
1764 | wss->state = WLP_WSS_STATE_CONNECTED; | ||
1765 | /* Construct C4 frame */ | ||
1766 | result = wlp_build_assoc_c4(wlp, wss, &resp); | ||
1767 | if (result < 0) { | ||
1768 | dev_err(dev, "WLP: Unable to construct C4 " | ||
1769 | "message.\n"); | ||
1770 | goto out; | ||
1771 | } | ||
1772 | } | ||
1773 | } else { | ||
1774 | /* Construct F0 frame */ | ||
1775 | result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV); | ||
1776 | if (result < 0) { | ||
1777 | dev_err(dev, "WLP: Unable to construct F0 message.\n"); | ||
1778 | goto out; | ||
1779 | } | ||
1780 | } | ||
1781 | /* Send C4 frame */ | ||
1782 | BUG_ON(wlp->xmit_frame == NULL); | ||
1783 | result = wlp->xmit_frame(wlp, resp, src); | ||
1784 | if (result < 0) { | ||
1785 | dev_err(dev, "WLP: Unable to transmit response association " | ||
1786 | "message: %d\n", result); | ||
1787 | if (result == -ENXIO) | ||
1788 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
1789 | /* We could try again ... */ | ||
1790 | dev_kfree_skb_any(resp); /* we need to free if tx fails */ | ||
1791 | } | ||
1792 | out: | ||
1793 | kfree_skb(frame_ctx->skb); | ||
1794 | kfree(frame_ctx); | ||
1795 | mutex_unlock(&wss->mutex); | ||
1796 | } | ||
1797 | |||
1798 | |||
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c deleted file mode 100644 index 6627c94cc854..000000000000 --- a/drivers/uwb/wlp/sysfs.c +++ /dev/null | |||
@@ -1,708 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * sysfs functions | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: Docs | ||
24 | * | ||
25 | */ | ||
26 | #include <linux/wlp.h> | ||
27 | |||
28 | #include "wlp-internal.h" | ||
29 | |||
30 | static | ||
31 | size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize, | ||
32 | struct wlp_wssid_e *wssid_e) | ||
33 | { | ||
34 | size_t used = 0; | ||
35 | used += scnprintf(buf, bufsize, " WSS: "); | ||
36 | used += wlp_wss_uuid_print(buf + used, bufsize - used, | ||
37 | &wssid_e->wssid); | ||
38 | |||
39 | if (wssid_e->info != NULL) { | ||
40 | used += scnprintf(buf + used, bufsize - used, " "); | ||
41 | used += uwb_mac_addr_print(buf + used, bufsize - used, | ||
42 | &wssid_e->info->bcast); | ||
43 | used += scnprintf(buf + used, bufsize - used, " %u %u %s\n", | ||
44 | wssid_e->info->accept_enroll, | ||
45 | wssid_e->info->sec_status, | ||
46 | wssid_e->info->name); | ||
47 | } | ||
48 | return used; | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Print out information learned from neighbor discovery | ||
53 | * | ||
54 | * Some fields being printed may not be included in the device discovery | ||
55 | * information (it is not mandatory). We are thus careful how the | ||
56 | * information is printed to ensure it is clear to the user what field is | ||
57 | * being referenced. | ||
58 | * The information being printed is for one time use - temporary storage is | ||
59 | * cleaned after it is printed. | ||
60 | * | ||
61 | * Ideally sysfs output should be on one line. The information printed here | ||
62 | * contain a few strings so it will be hard to parse if they are all | ||
63 | * printed on the same line - without agreeing on a standard field | ||
64 | * separator. | ||
65 | */ | ||
66 | static | ||
67 | ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf, | ||
68 | size_t bufsize) | ||
69 | { | ||
70 | size_t used = 0; | ||
71 | struct wlp_neighbor_e *neighb; | ||
72 | struct wlp_wssid_e *wssid_e; | ||
73 | |||
74 | mutex_lock(&wlp->nbmutex); | ||
75 | used = scnprintf(buf, bufsize, "#Neighbor information\n" | ||
76 | "#uuid dev_addr\n" | ||
77 | "# Device Name:\n# Model Name:\n# Manufacturer:\n" | ||
78 | "# Model Nr:\n# Serial:\n" | ||
79 | "# Pri Dev type: CategoryID OUI OUISubdiv " | ||
80 | "SubcategoryID\n" | ||
81 | "# WSS: WSSID WSS_name accept_enroll sec_status " | ||
82 | "bcast\n" | ||
83 | "# WSS: WSSID WSS_name accept_enroll sec_status " | ||
84 | "bcast\n\n"); | ||
85 | list_for_each_entry(neighb, &wlp->neighbors, node) { | ||
86 | if (bufsize - used <= 0) | ||
87 | goto out; | ||
88 | used += wlp_wss_uuid_print(buf + used, bufsize - used, | ||
89 | &neighb->uuid); | ||
90 | buf[used++] = ' '; | ||
91 | used += uwb_dev_addr_print(buf + used, bufsize - used, | ||
92 | &neighb->uwb_dev->dev_addr); | ||
93 | if (neighb->info != NULL) | ||
94 | used += scnprintf(buf + used, bufsize - used, | ||
95 | "\n Device Name: %s\n" | ||
96 | " Model Name: %s\n" | ||
97 | " Manufacturer:%s \n" | ||
98 | " Model Nr: %s\n" | ||
99 | " Serial: %s\n" | ||
100 | " Pri Dev type: " | ||
101 | "%u %02x:%02x:%02x %u %u\n", | ||
102 | neighb->info->name, | ||
103 | neighb->info->model_name, | ||
104 | neighb->info->manufacturer, | ||
105 | neighb->info->model_nr, | ||
106 | neighb->info->serial, | ||
107 | neighb->info->prim_dev_type.category, | ||
108 | neighb->info->prim_dev_type.OUI[0], | ||
109 | neighb->info->prim_dev_type.OUI[1], | ||
110 | neighb->info->prim_dev_type.OUI[2], | ||
111 | neighb->info->prim_dev_type.OUIsubdiv, | ||
112 | neighb->info->prim_dev_type.subID); | ||
113 | list_for_each_entry(wssid_e, &neighb->wssid, node) { | ||
114 | used += wlp_wss_wssid_e_print(buf + used, | ||
115 | bufsize - used, | ||
116 | wssid_e); | ||
117 | } | ||
118 | buf[used++] = '\n'; | ||
119 | wlp_remove_neighbor_tmp_info(neighb); | ||
120 | } | ||
121 | |||
122 | |||
123 | out: | ||
124 | mutex_unlock(&wlp->nbmutex); | ||
125 | return used; | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Show properties of all WSS in neighborhood. | ||
131 | * | ||
132 | * Will trigger a complete discovery of WSS activated by this device and | ||
133 | * its neighbors. | ||
134 | */ | ||
135 | ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf) | ||
136 | { | ||
137 | wlp_discover(wlp); | ||
138 | return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE); | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(wlp_neighborhood_show); | ||
141 | |||
142 | static | ||
143 | ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf, | ||
144 | size_t bufsize) | ||
145 | { | ||
146 | ssize_t result; | ||
147 | |||
148 | result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid); | ||
149 | result += scnprintf(buf + result, bufsize - result, " "); | ||
150 | result += uwb_mac_addr_print(buf + result, bufsize - result, | ||
151 | &wss->bcast); | ||
152 | result += scnprintf(buf + result, bufsize - result, | ||
153 | " 0x%02x %u ", wss->hash, wss->secure_status); | ||
154 | result += wlp_wss_key_print(buf + result, bufsize - result, | ||
155 | wss->master_key); | ||
156 | result += scnprintf(buf + result, bufsize - result, " 0x%02x ", | ||
157 | wss->tag); | ||
158 | result += uwb_mac_addr_print(buf + result, bufsize - result, | ||
159 | &wss->virtual_addr); | ||
160 | result += scnprintf(buf + result, bufsize - result, " %s", wss->name); | ||
161 | result += scnprintf(buf + result, bufsize - result, | ||
162 | "\n\n#WSSID\n#WSS broadcast address\n" | ||
163 | "#WSS hash\n#WSS secure status\n" | ||
164 | "#WSS master key\n#WSS local tag\n" | ||
165 | "#WSS local virtual EUI-48\n#WSS name\n"); | ||
166 | return result; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * Show which WSS is activated. | ||
171 | */ | ||
172 | ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf) | ||
173 | { | ||
174 | int result = 0; | ||
175 | |||
176 | if (mutex_lock_interruptible(&wss->mutex)) | ||
177 | goto out; | ||
178 | if (wss->state >= WLP_WSS_STATE_ACTIVE) | ||
179 | result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE); | ||
180 | else | ||
181 | result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n"); | ||
182 | result += scnprintf(buf + result, PAGE_SIZE - result, | ||
183 | "\n\n" | ||
184 | "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT " | ||
185 | "NAME #create new WSS\n" | ||
186 | "# echo WSSID [DEV ADDR] #enroll in and activate " | ||
187 | "existing WSS, can request registrar\n" | ||
188 | "#\n" | ||
189 | "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n" | ||
190 | "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n" | ||
191 | "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n" | ||
192 | "# NAME is the text string identifying the WSS\n" | ||
193 | "# DEV ADDR is the device address of neighbor " | ||
194 | "that should be registrar. Eg. 32:AB\n"); | ||
195 | |||
196 | mutex_unlock(&wss->mutex); | ||
197 | out: | ||
198 | return result; | ||
199 | |||
200 | } | ||
201 | EXPORT_SYMBOL_GPL(wlp_wss_activate_show); | ||
202 | |||
203 | /** | ||
204 | * Create/activate a new WSS or enroll/activate in neighboring WSS | ||
205 | * | ||
206 | * The user can provide the WSSID of a WSS in which it wants to enroll. | ||
207 | * Only the WSSID is necessary if the WSS have been discovered before. If | ||
208 | * the WSS has not been discovered before, or the user wants to use a | ||
209 | * particular neighbor as its registrar, then the user can also provide a | ||
210 | * device address or the neighbor that will be used as registrar. | ||
211 | * | ||
212 | * A new WSS is created when the user provides a WSSID, secure status, and | ||
213 | * WSS name. | ||
214 | */ | ||
215 | ssize_t wlp_wss_activate_store(struct wlp_wss *wss, | ||
216 | const char *buf, size_t size) | ||
217 | { | ||
218 | ssize_t result = -EINVAL; | ||
219 | struct wlp_uuid wssid; | ||
220 | struct uwb_dev_addr dev; | ||
221 | struct uwb_dev_addr bcast = {.data = {0xff, 0xff} }; | ||
222 | char name[65]; | ||
223 | unsigned sec_status, accept; | ||
224 | memset(name, 0, sizeof(name)); | ||
225 | result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx " | ||
226 | "%02hhx %02hhx %02hhx %02hhx " | ||
227 | "%02hhx %02hhx %02hhx %02hhx " | ||
228 | "%02hhx %02hhx %02hhx %02hhx " | ||
229 | "%02hhx:%02hhx", | ||
230 | &wssid.data[0] , &wssid.data[1], | ||
231 | &wssid.data[2] , &wssid.data[3], | ||
232 | &wssid.data[4] , &wssid.data[5], | ||
233 | &wssid.data[6] , &wssid.data[7], | ||
234 | &wssid.data[8] , &wssid.data[9], | ||
235 | &wssid.data[10], &wssid.data[11], | ||
236 | &wssid.data[12], &wssid.data[13], | ||
237 | &wssid.data[14], &wssid.data[15], | ||
238 | &dev.data[1], &dev.data[0]); | ||
239 | if (result == 16 || result == 17) { | ||
240 | result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx " | ||
241 | "%02hhx %02hhx %02hhx %02hhx " | ||
242 | "%02hhx %02hhx %02hhx %02hhx " | ||
243 | "%02hhx %02hhx %02hhx %02hhx " | ||
244 | "%u %u %64c", | ||
245 | &wssid.data[0] , &wssid.data[1], | ||
246 | &wssid.data[2] , &wssid.data[3], | ||
247 | &wssid.data[4] , &wssid.data[5], | ||
248 | &wssid.data[6] , &wssid.data[7], | ||
249 | &wssid.data[8] , &wssid.data[9], | ||
250 | &wssid.data[10], &wssid.data[11], | ||
251 | &wssid.data[12], &wssid.data[13], | ||
252 | &wssid.data[14], &wssid.data[15], | ||
253 | &sec_status, &accept, name); | ||
254 | if (result == 16) | ||
255 | result = wlp_wss_enroll_activate(wss, &wssid, &bcast); | ||
256 | else if (result == 19) { | ||
257 | sec_status = sec_status == 0 ? 0 : 1; | ||
258 | accept = accept == 0 ? 0 : 1; | ||
259 | /* We read name using %c, so the newline needs to be | ||
260 | * removed */ | ||
261 | if (strlen(name) != sizeof(name) - 1) | ||
262 | name[strlen(name) - 1] = '\0'; | ||
263 | result = wlp_wss_create_activate(wss, &wssid, name, | ||
264 | sec_status, accept); | ||
265 | } else | ||
266 | result = -EINVAL; | ||
267 | } else if (result == 18) | ||
268 | result = wlp_wss_enroll_activate(wss, &wssid, &dev); | ||
269 | else | ||
270 | result = -EINVAL; | ||
271 | return result < 0 ? result : size; | ||
272 | } | ||
273 | EXPORT_SYMBOL_GPL(wlp_wss_activate_store); | ||
274 | |||
275 | /** | ||
276 | * Show the UUID of this host | ||
277 | */ | ||
278 | ssize_t wlp_uuid_show(struct wlp *wlp, char *buf) | ||
279 | { | ||
280 | ssize_t result = 0; | ||
281 | |||
282 | mutex_lock(&wlp->mutex); | ||
283 | result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid); | ||
284 | buf[result++] = '\n'; | ||
285 | mutex_unlock(&wlp->mutex); | ||
286 | return result; | ||
287 | } | ||
288 | EXPORT_SYMBOL_GPL(wlp_uuid_show); | ||
289 | |||
290 | /** | ||
291 | * Store a new UUID for this host | ||
292 | * | ||
293 | * According to the spec this should be encoded as an octet string in the | ||
294 | * order the octets are shown in string representation in RFC 4122 (WLP | ||
295 | * 0.99 [Table 6]) | ||
296 | * | ||
297 | * We do not check value provided by user. | ||
298 | */ | ||
299 | ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size) | ||
300 | { | ||
301 | ssize_t result; | ||
302 | struct wlp_uuid uuid; | ||
303 | |||
304 | mutex_lock(&wlp->mutex); | ||
305 | result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx " | ||
306 | "%02hhx %02hhx %02hhx %02hhx " | ||
307 | "%02hhx %02hhx %02hhx %02hhx " | ||
308 | "%02hhx %02hhx %02hhx %02hhx ", | ||
309 | &uuid.data[0] , &uuid.data[1], | ||
310 | &uuid.data[2] , &uuid.data[3], | ||
311 | &uuid.data[4] , &uuid.data[5], | ||
312 | &uuid.data[6] , &uuid.data[7], | ||
313 | &uuid.data[8] , &uuid.data[9], | ||
314 | &uuid.data[10], &uuid.data[11], | ||
315 | &uuid.data[12], &uuid.data[13], | ||
316 | &uuid.data[14], &uuid.data[15]); | ||
317 | if (result != 16) { | ||
318 | result = -EINVAL; | ||
319 | goto error; | ||
320 | } | ||
321 | wlp->uuid = uuid; | ||
322 | error: | ||
323 | mutex_unlock(&wlp->mutex); | ||
324 | return result < 0 ? result : size; | ||
325 | } | ||
326 | EXPORT_SYMBOL_GPL(wlp_uuid_store); | ||
327 | |||
328 | /** | ||
329 | * Show contents of members of device information structure | ||
330 | */ | ||
331 | #define wlp_dev_info_show(type) \ | ||
332 | ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \ | ||
333 | { \ | ||
334 | ssize_t result = 0; \ | ||
335 | mutex_lock(&wlp->mutex); \ | ||
336 | if (wlp->dev_info == NULL) { \ | ||
337 | result = __wlp_setup_device_info(wlp); \ | ||
338 | if (result < 0) \ | ||
339 | goto out; \ | ||
340 | } \ | ||
341 | result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\ | ||
342 | out: \ | ||
343 | mutex_unlock(&wlp->mutex); \ | ||
344 | return result; \ | ||
345 | } \ | ||
346 | EXPORT_SYMBOL_GPL(wlp_dev_##type##_show); | ||
347 | |||
348 | wlp_dev_info_show(name) | ||
349 | wlp_dev_info_show(model_name) | ||
350 | wlp_dev_info_show(model_nr) | ||
351 | wlp_dev_info_show(manufacturer) | ||
352 | wlp_dev_info_show(serial) | ||
353 | |||
354 | /** | ||
355 | * Store contents of members of device information structure | ||
356 | */ | ||
357 | #define wlp_dev_info_store(type, len) \ | ||
358 | ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\ | ||
359 | { \ | ||
360 | ssize_t result; \ | ||
361 | char format[10]; \ | ||
362 | mutex_lock(&wlp->mutex); \ | ||
363 | if (wlp->dev_info == NULL) { \ | ||
364 | result = __wlp_alloc_device_info(wlp); \ | ||
365 | if (result < 0) \ | ||
366 | goto out; \ | ||
367 | } \ | ||
368 | memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \ | ||
369 | sprintf(format, "%%%uc", len); \ | ||
370 | result = sscanf(buf, format, wlp->dev_info->type); \ | ||
371 | out: \ | ||
372 | mutex_unlock(&wlp->mutex); \ | ||
373 | return result < 0 ? result : size; \ | ||
374 | } \ | ||
375 | EXPORT_SYMBOL_GPL(wlp_dev_##type##_store); | ||
376 | |||
377 | wlp_dev_info_store(name, 32) | ||
378 | wlp_dev_info_store(manufacturer, 64) | ||
379 | wlp_dev_info_store(model_name, 32) | ||
380 | wlp_dev_info_store(model_nr, 32) | ||
381 | wlp_dev_info_store(serial, 32) | ||
382 | |||
383 | static | ||
384 | const char *__wlp_dev_category[] = { | ||
385 | [WLP_DEV_CAT_COMPUTER] = "Computer", | ||
386 | [WLP_DEV_CAT_INPUT] = "Input device", | ||
387 | [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or " | ||
388 | "Copier", | ||
389 | [WLP_DEV_CAT_CAMERA] = "Camera", | ||
390 | [WLP_DEV_CAT_STORAGE] = "Storage Network", | ||
391 | [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure", | ||
392 | [WLP_DEV_CAT_DISPLAY] = "Display", | ||
393 | [WLP_DEV_CAT_MULTIM] = "Multimedia device", | ||
394 | [WLP_DEV_CAT_GAMING] = "Gaming device", | ||
395 | [WLP_DEV_CAT_TELEPHONE] = "Telephone", | ||
396 | [WLP_DEV_CAT_OTHER] = "Other", | ||
397 | }; | ||
398 | |||
399 | static | ||
400 | const char *wlp_dev_category_str(unsigned cat) | ||
401 | { | ||
402 | if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE) | ||
403 | || cat == WLP_DEV_CAT_OTHER) | ||
404 | return __wlp_dev_category[cat]; | ||
405 | return "unknown category"; | ||
406 | } | ||
407 | |||
408 | ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf) | ||
409 | { | ||
410 | ssize_t result = 0; | ||
411 | mutex_lock(&wlp->mutex); | ||
412 | if (wlp->dev_info == NULL) { | ||
413 | result = __wlp_setup_device_info(wlp); | ||
414 | if (result < 0) | ||
415 | goto out; | ||
416 | } | ||
417 | result = scnprintf(buf, PAGE_SIZE, "%s\n", | ||
418 | wlp_dev_category_str(wlp->dev_info->prim_dev_type.category)); | ||
419 | out: | ||
420 | mutex_unlock(&wlp->mutex); | ||
421 | return result; | ||
422 | } | ||
423 | EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show); | ||
424 | |||
425 | ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf, | ||
426 | size_t size) | ||
427 | { | ||
428 | ssize_t result; | ||
429 | u16 cat; | ||
430 | mutex_lock(&wlp->mutex); | ||
431 | if (wlp->dev_info == NULL) { | ||
432 | result = __wlp_alloc_device_info(wlp); | ||
433 | if (result < 0) | ||
434 | goto out; | ||
435 | } | ||
436 | result = sscanf(buf, "%hu", &cat); | ||
437 | if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE) | ||
438 | || cat == WLP_DEV_CAT_OTHER) | ||
439 | wlp->dev_info->prim_dev_type.category = cat; | ||
440 | else | ||
441 | result = -EINVAL; | ||
442 | out: | ||
443 | mutex_unlock(&wlp->mutex); | ||
444 | return result < 0 ? result : size; | ||
445 | } | ||
446 | EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store); | ||
447 | |||
448 | ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf) | ||
449 | { | ||
450 | ssize_t result = 0; | ||
451 | mutex_lock(&wlp->mutex); | ||
452 | if (wlp->dev_info == NULL) { | ||
453 | result = __wlp_setup_device_info(wlp); | ||
454 | if (result < 0) | ||
455 | goto out; | ||
456 | } | ||
457 | result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n", | ||
458 | wlp->dev_info->prim_dev_type.OUI[0], | ||
459 | wlp->dev_info->prim_dev_type.OUI[1], | ||
460 | wlp->dev_info->prim_dev_type.OUI[2]); | ||
461 | out: | ||
462 | mutex_unlock(&wlp->mutex); | ||
463 | return result; | ||
464 | } | ||
465 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show); | ||
466 | |||
467 | ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size) | ||
468 | { | ||
469 | ssize_t result; | ||
470 | u8 OUI[3]; | ||
471 | mutex_lock(&wlp->mutex); | ||
472 | if (wlp->dev_info == NULL) { | ||
473 | result = __wlp_alloc_device_info(wlp); | ||
474 | if (result < 0) | ||
475 | goto out; | ||
476 | } | ||
477 | result = sscanf(buf, "%hhx:%hhx:%hhx", | ||
478 | &OUI[0], &OUI[1], &OUI[2]); | ||
479 | if (result != 3) { | ||
480 | result = -EINVAL; | ||
481 | goto out; | ||
482 | } else | ||
483 | memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI)); | ||
484 | out: | ||
485 | mutex_unlock(&wlp->mutex); | ||
486 | return result < 0 ? result : size; | ||
487 | } | ||
488 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store); | ||
489 | |||
490 | |||
491 | ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf) | ||
492 | { | ||
493 | ssize_t result = 0; | ||
494 | mutex_lock(&wlp->mutex); | ||
495 | if (wlp->dev_info == NULL) { | ||
496 | result = __wlp_setup_device_info(wlp); | ||
497 | if (result < 0) | ||
498 | goto out; | ||
499 | } | ||
500 | result = scnprintf(buf, PAGE_SIZE, "%u\n", | ||
501 | wlp->dev_info->prim_dev_type.OUIsubdiv); | ||
502 | out: | ||
503 | mutex_unlock(&wlp->mutex); | ||
504 | return result; | ||
505 | } | ||
506 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show); | ||
507 | |||
508 | ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf, | ||
509 | size_t size) | ||
510 | { | ||
511 | ssize_t result; | ||
512 | unsigned sub; | ||
513 | u8 max_sub = ~0; | ||
514 | mutex_lock(&wlp->mutex); | ||
515 | if (wlp->dev_info == NULL) { | ||
516 | result = __wlp_alloc_device_info(wlp); | ||
517 | if (result < 0) | ||
518 | goto out; | ||
519 | } | ||
520 | result = sscanf(buf, "%u", &sub); | ||
521 | if (sub <= max_sub) | ||
522 | wlp->dev_info->prim_dev_type.OUIsubdiv = sub; | ||
523 | else | ||
524 | result = -EINVAL; | ||
525 | out: | ||
526 | mutex_unlock(&wlp->mutex); | ||
527 | return result < 0 ? result : size; | ||
528 | } | ||
529 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store); | ||
530 | |||
531 | ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf) | ||
532 | { | ||
533 | ssize_t result = 0; | ||
534 | mutex_lock(&wlp->mutex); | ||
535 | if (wlp->dev_info == NULL) { | ||
536 | result = __wlp_setup_device_info(wlp); | ||
537 | if (result < 0) | ||
538 | goto out; | ||
539 | } | ||
540 | result = scnprintf(buf, PAGE_SIZE, "%u\n", | ||
541 | wlp->dev_info->prim_dev_type.subID); | ||
542 | out: | ||
543 | mutex_unlock(&wlp->mutex); | ||
544 | return result; | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show); | ||
547 | |||
548 | ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf, | ||
549 | size_t size) | ||
550 | { | ||
551 | ssize_t result; | ||
552 | unsigned sub; | ||
553 | __le16 max_sub = ~0; | ||
554 | mutex_lock(&wlp->mutex); | ||
555 | if (wlp->dev_info == NULL) { | ||
556 | result = __wlp_alloc_device_info(wlp); | ||
557 | if (result < 0) | ||
558 | goto out; | ||
559 | } | ||
560 | result = sscanf(buf, "%u", &sub); | ||
561 | if (sub <= max_sub) | ||
562 | wlp->dev_info->prim_dev_type.subID = sub; | ||
563 | else | ||
564 | result = -EINVAL; | ||
565 | out: | ||
566 | mutex_unlock(&wlp->mutex); | ||
567 | return result < 0 ? result : size; | ||
568 | } | ||
569 | EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store); | ||
570 | |||
571 | /** | ||
572 | * Subsystem implementation for interaction with individual WSS via sysfs | ||
573 | * | ||
574 | * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt | ||
575 | */ | ||
576 | |||
577 | #define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj) | ||
578 | #define attr_to_wlp_wss_attr(_attr) \ | ||
579 | container_of(_attr, struct wlp_wss_attribute, attr) | ||
580 | |||
581 | /** | ||
582 | * Sysfs subsystem: forward read calls | ||
583 | * | ||
584 | * Sysfs operation for forwarding read call to the show method of the | ||
585 | * attribute owner | ||
586 | */ | ||
587 | static | ||
588 | ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr, | ||
589 | char *buf) | ||
590 | { | ||
591 | struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr); | ||
592 | struct wlp_wss *wss = kobj_to_wlp_wss(kobj); | ||
593 | ssize_t ret = -EIO; | ||
594 | |||
595 | if (wss_attr->show) | ||
596 | ret = wss_attr->show(wss, buf); | ||
597 | return ret; | ||
598 | } | ||
599 | /** | ||
600 | * Sysfs subsystem: forward write calls | ||
601 | * | ||
602 | * Sysfs operation for forwarding write call to the store method of the | ||
603 | * attribute owner | ||
604 | */ | ||
605 | static | ||
606 | ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr, | ||
607 | const char *buf, size_t count) | ||
608 | { | ||
609 | struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr); | ||
610 | struct wlp_wss *wss = kobj_to_wlp_wss(kobj); | ||
611 | ssize_t ret = -EIO; | ||
612 | |||
613 | if (wss_attr->store) | ||
614 | ret = wss_attr->store(wss, buf, count); | ||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static const struct sysfs_ops wss_sysfs_ops = { | ||
619 | .show = wlp_wss_attr_show, | ||
620 | .store = wlp_wss_attr_store, | ||
621 | }; | ||
622 | |||
623 | struct kobj_type wss_ktype = { | ||
624 | .release = wlp_wss_release, | ||
625 | .sysfs_ops = &wss_sysfs_ops, | ||
626 | }; | ||
627 | |||
628 | |||
629 | /** | ||
630 | * Sysfs files for individual WSS | ||
631 | */ | ||
632 | |||
633 | /** | ||
634 | * Print static properties of this WSS | ||
635 | * | ||
636 | * The name of a WSS may not be null teminated. It's max size is 64 bytes | ||
637 | * so we copy it to a larger array just to make sure we print sane data. | ||
638 | */ | ||
639 | static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf) | ||
640 | { | ||
641 | int result = 0; | ||
642 | |||
643 | if (mutex_lock_interruptible(&wss->mutex)) | ||
644 | goto out; | ||
645 | result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE); | ||
646 | mutex_unlock(&wss->mutex); | ||
647 | out: | ||
648 | return result; | ||
649 | } | ||
650 | WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL); | ||
651 | |||
652 | /** | ||
653 | * Print all connected members of this WSS | ||
654 | * The EDA cache contains all members of WSS neighborhood. | ||
655 | */ | ||
656 | static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf) | ||
657 | { | ||
658 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
659 | return wlp_eda_show(wlp, buf); | ||
660 | } | ||
661 | WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL); | ||
662 | |||
663 | static | ||
664 | const char *__wlp_strstate[] = { | ||
665 | "none", | ||
666 | "partially enrolled", | ||
667 | "enrolled", | ||
668 | "active", | ||
669 | "connected", | ||
670 | }; | ||
671 | |||
672 | static const char *wlp_wss_strstate(unsigned state) | ||
673 | { | ||
674 | if (state >= ARRAY_SIZE(__wlp_strstate)) | ||
675 | return "unknown state"; | ||
676 | return __wlp_strstate[state]; | ||
677 | } | ||
678 | |||
679 | /* | ||
680 | * Print current state of this WSS | ||
681 | */ | ||
682 | static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf) | ||
683 | { | ||
684 | int result = 0; | ||
685 | |||
686 | if (mutex_lock_interruptible(&wss->mutex)) | ||
687 | goto out; | ||
688 | result = scnprintf(buf, PAGE_SIZE, "%s\n", | ||
689 | wlp_wss_strstate(wss->state)); | ||
690 | mutex_unlock(&wss->mutex); | ||
691 | out: | ||
692 | return result; | ||
693 | } | ||
694 | WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL); | ||
695 | |||
696 | |||
697 | static | ||
698 | struct attribute *wss_attrs[] = { | ||
699 | &wss_attr_properties.attr, | ||
700 | &wss_attr_members.attr, | ||
701 | &wss_attr_state.attr, | ||
702 | NULL, | ||
703 | }; | ||
704 | |||
705 | struct attribute_group wss_attr_group = { | ||
706 | .name = NULL, /* we want them in the same directory */ | ||
707 | .attrs = wss_attrs, | ||
708 | }; | ||
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c deleted file mode 100644 index 05dde44b3592..000000000000 --- a/drivers/uwb/wlp/txrx.c +++ /dev/null | |||
@@ -1,354 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * Message exchange infrastructure | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: Docs | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/wlp.h> | ||
30 | |||
31 | #include "wlp-internal.h" | ||
32 | |||
33 | /* | ||
34 | * Direct incoming association msg to correct parsing routine | ||
35 | * | ||
36 | * We only expect D1, E1, C1, C3 messages as new. All other incoming | ||
37 | * association messages should form part of an established session that is | ||
38 | * handled elsewhere. | ||
39 | * The handling of these messages often require calling sleeping functions | ||
40 | * - this cannot be done in interrupt context. We use the kernel's | ||
41 | * workqueue to handle these messages. | ||
42 | */ | ||
43 | static | ||
44 | void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb, | ||
45 | struct uwb_dev_addr *src) | ||
46 | { | ||
47 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
48 | struct wlp_frame_assoc *assoc = (void *) skb->data; | ||
49 | struct wlp_assoc_frame_ctx *frame_ctx; | ||
50 | |||
51 | frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC); | ||
52 | if (frame_ctx == NULL) { | ||
53 | dev_err(dev, "WLP: Unable to allocate memory for association " | ||
54 | "frame handling.\n"); | ||
55 | kfree_skb(skb); | ||
56 | return; | ||
57 | } | ||
58 | frame_ctx->wlp = wlp; | ||
59 | frame_ctx->skb = skb; | ||
60 | frame_ctx->src = *src; | ||
61 | switch (assoc->type) { | ||
62 | case WLP_ASSOC_D1: | ||
63 | INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame); | ||
64 | schedule_work(&frame_ctx->ws); | ||
65 | break; | ||
66 | case WLP_ASSOC_E1: | ||
67 | kfree_skb(skb); /* Temporary until we handle it */ | ||
68 | kfree(frame_ctx); /* Temporary until we handle it */ | ||
69 | break; | ||
70 | case WLP_ASSOC_C1: | ||
71 | INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame); | ||
72 | schedule_work(&frame_ctx->ws); | ||
73 | break; | ||
74 | case WLP_ASSOC_C3: | ||
75 | INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame); | ||
76 | schedule_work(&frame_ctx->ws); | ||
77 | break; | ||
78 | default: | ||
79 | dev_err(dev, "Received unexpected association frame. " | ||
80 | "Type = %d \n", assoc->type); | ||
81 | kfree_skb(skb); | ||
82 | kfree(frame_ctx); | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Process incoming association frame | ||
89 | * | ||
90 | * Although it could be possible to deal with some incoming association | ||
91 | * messages without creating a new session we are keeping things simple. We | ||
92 | * do not accept new association messages if there is a session in progress | ||
93 | * and the messages do not belong to that session. | ||
94 | * | ||
95 | * If an association message arrives that causes the creation of a session | ||
96 | * (WLP_ASSOC_E1) while we are in the process of creating a session then we | ||
97 | * rely on the neighbor mutex to protect the data. That is, the new session | ||
98 | * will not be started until the previous is completed. | ||
99 | */ | ||
100 | static | ||
101 | void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb, | ||
102 | struct uwb_dev_addr *src) | ||
103 | { | ||
104 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
105 | struct wlp_frame_assoc *assoc = (void *) skb->data; | ||
106 | struct wlp_session *session = wlp->session; | ||
107 | u8 version; | ||
108 | |||
109 | if (wlp_get_version(wlp, &assoc->version, &version, | ||
110 | sizeof(assoc->version)) < 0) | ||
111 | goto error; | ||
112 | if (version != WLP_VERSION) { | ||
113 | dev_err(dev, "Unsupported WLP version in association " | ||
114 | "message.\n"); | ||
115 | goto error; | ||
116 | } | ||
117 | if (session != NULL) { | ||
118 | /* Function that created this session is still holding the | ||
119 | * &wlp->mutex to protect this session. */ | ||
120 | if (assoc->type == session->exp_message || | ||
121 | assoc->type == WLP_ASSOC_F0) { | ||
122 | if (!memcmp(&session->neighbor_addr, src, | ||
123 | sizeof(*src))) { | ||
124 | session->data = skb; | ||
125 | (session->cb)(wlp); | ||
126 | } else { | ||
127 | dev_err(dev, "Received expected message from " | ||
128 | "unexpected source. Expected message " | ||
129 | "%d or F0 from %02x:%02x, but received " | ||
130 | "it from %02x:%02x. Dropping.\n", | ||
131 | session->exp_message, | ||
132 | session->neighbor_addr.data[1], | ||
133 | session->neighbor_addr.data[0], | ||
134 | src->data[1], src->data[0]); | ||
135 | goto error; | ||
136 | } | ||
137 | } else { | ||
138 | dev_err(dev, "Association already in progress. " | ||
139 | "Dropping.\n"); | ||
140 | goto error; | ||
141 | } | ||
142 | } else { | ||
143 | wlp_direct_assoc_frame(wlp, skb, src); | ||
144 | } | ||
145 | return; | ||
146 | error: | ||
147 | kfree_skb(skb); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * Verify incoming frame is from connected neighbor, prep to pass to WLP client | ||
152 | * | ||
153 | * Verification proceeds according to WLP 0.99 [7.3.1]. The source address | ||
154 | * is used to determine which neighbor is sending the frame and the WSS tag | ||
155 | * is used to know to which WSS the frame belongs (we only support one WSS | ||
156 | * so this test is straight forward). | ||
157 | * With the WSS found we need to ensure that we are connected before | ||
158 | * allowing the exchange of data frames. | ||
159 | */ | ||
160 | static | ||
161 | int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb, | ||
162 | struct uwb_dev_addr *src) | ||
163 | { | ||
164 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
165 | int result = -EINVAL; | ||
166 | struct wlp_eda_node eda_entry; | ||
167 | struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data; | ||
168 | |||
169 | /*verify*/ | ||
170 | result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry); | ||
171 | if (result < 0) { | ||
172 | if (printk_ratelimit()) | ||
173 | dev_err(dev, "WLP: Incoming frame is from unknown " | ||
174 | "neighbor %02x:%02x.\n", src->data[1], | ||
175 | src->data[0]); | ||
176 | goto out; | ||
177 | } | ||
178 | if (hdr->tag != eda_entry.tag) { | ||
179 | if (printk_ratelimit()) | ||
180 | dev_err(dev, "WLP: Tag of incoming frame from " | ||
181 | "%02x:%02x does not match expected tag. " | ||
182 | "Received 0x%02x, expected 0x%02x. \n", | ||
183 | src->data[1], src->data[0], hdr->tag, | ||
184 | eda_entry.tag); | ||
185 | result = -EINVAL; | ||
186 | goto out; | ||
187 | } | ||
188 | if (eda_entry.state != WLP_WSS_CONNECTED) { | ||
189 | if (printk_ratelimit()) | ||
190 | dev_err(dev, "WLP: Incoming frame from " | ||
191 | "%02x:%02x does is not from connected WSS.\n", | ||
192 | src->data[1], src->data[0]); | ||
193 | result = -EINVAL; | ||
194 | goto out; | ||
195 | } | ||
196 | /*prep*/ | ||
197 | skb_pull(skb, sizeof(*hdr)); | ||
198 | out: | ||
199 | return result; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Receive a WLP frame from device | ||
204 | * | ||
205 | * @returns: 1 if calling function should free the skb | ||
206 | * 0 if it successfully handled skb and freed it | ||
207 | * 0 if error occured, will free skb in this case | ||
208 | */ | ||
209 | int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb, | ||
210 | struct uwb_dev_addr *src) | ||
211 | { | ||
212 | unsigned len = skb->len; | ||
213 | void *ptr = skb->data; | ||
214 | struct wlp_frame_hdr *hdr; | ||
215 | int result = 0; | ||
216 | |||
217 | if (len < sizeof(*hdr)) { | ||
218 | dev_err(dev, "Not enough data to parse WLP header.\n"); | ||
219 | result = -EINVAL; | ||
220 | goto out; | ||
221 | } | ||
222 | hdr = ptr; | ||
223 | if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) { | ||
224 | dev_err(dev, "Not a WLP frame type.\n"); | ||
225 | result = -EINVAL; | ||
226 | goto out; | ||
227 | } | ||
228 | switch (hdr->type) { | ||
229 | case WLP_FRAME_STANDARD: | ||
230 | if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) { | ||
231 | dev_err(dev, "Not enough data to parse Standard " | ||
232 | "WLP header.\n"); | ||
233 | goto out; | ||
234 | } | ||
235 | result = wlp_verify_prep_rx_frame(wlp, skb, src); | ||
236 | if (result < 0) { | ||
237 | if (printk_ratelimit()) | ||
238 | dev_err(dev, "WLP: Verification of frame " | ||
239 | "from neighbor %02x:%02x failed.\n", | ||
240 | src->data[1], src->data[0]); | ||
241 | goto out; | ||
242 | } | ||
243 | result = 1; | ||
244 | break; | ||
245 | case WLP_FRAME_ABBREVIATED: | ||
246 | dev_err(dev, "Abbreviated frame received. FIXME?\n"); | ||
247 | kfree_skb(skb); | ||
248 | break; | ||
249 | case WLP_FRAME_CONTROL: | ||
250 | dev_err(dev, "Control frame received. FIXME?\n"); | ||
251 | kfree_skb(skb); | ||
252 | break; | ||
253 | case WLP_FRAME_ASSOCIATION: | ||
254 | if (len < sizeof(struct wlp_frame_assoc)) { | ||
255 | dev_err(dev, "Not enough data to parse Association " | ||
256 | "WLP header.\n"); | ||
257 | goto out; | ||
258 | } | ||
259 | wlp_receive_assoc_frame(wlp, skb, src); | ||
260 | break; | ||
261 | default: | ||
262 | dev_err(dev, "Invalid frame received.\n"); | ||
263 | result = -EINVAL; | ||
264 | break; | ||
265 | } | ||
266 | out: | ||
267 | if (result < 0) { | ||
268 | kfree_skb(skb); | ||
269 | result = 0; | ||
270 | } | ||
271 | return result; | ||
272 | } | ||
273 | EXPORT_SYMBOL_GPL(wlp_receive_frame); | ||
274 | |||
275 | |||
276 | /* | ||
277 | * Verify frame from network stack, prepare for further transmission | ||
278 | * | ||
279 | * @skb: the socket buffer that needs to be prepared for transmission (it | ||
280 | * is in need of a WLP header). If this is a broadcast frame we take | ||
281 | * over the entire transmission. | ||
282 | * If it is a unicast the WSS connection should already be established | ||
283 | * and transmission will be done by the calling function. | ||
284 | * @dst: On return this will contain the device address to which the | ||
285 | * frame is destined. | ||
286 | * @returns: 0 on success no tx : WLP header successfully applied to skb buffer, | ||
287 | * calling function can proceed with tx | ||
288 | * 1 on success with tx : WLP will take over transmission of this | ||
289 | * frame | ||
290 | * <0 on error | ||
291 | * | ||
292 | * The network stack (WLP client) is attempting to transmit a frame. We can | ||
293 | * only transmit data if a local WSS is at least active (connection will be | ||
294 | * done here if this is a broadcast frame and neighbor also has the WSS | ||
295 | * active). | ||
296 | * | ||
297 | * The frame can be either broadcast or unicast. Broadcast in a WSS is | ||
298 | * supported via multicast, but we don't support multicast yet (until | ||
299 | * devices start to support MAB IEs). If a broadcast frame needs to be | ||
300 | * transmitted it is treated as a unicast frame to each neighbor. In this | ||
301 | * case the WLP takes over transmission of the skb and returns 1 | ||
302 | * to the caller to indicate so. Also, in this case, if a neighbor has the | ||
303 | * same WSS activated but is not connected then the WSS connection will be | ||
304 | * done at this time. The neighbor's virtual address will be learned at | ||
305 | * this time. | ||
306 | * | ||
307 | * The destination address in a unicast frame is the virtual address of the | ||
308 | * neighbor. This address only becomes known when a WSS connection is | ||
309 | * established. We thus rely on a broadcast frame to trigger the setup of | ||
310 | * WSS connections to all neighbors before we are able to send unicast | ||
311 | * frames to them. This seems reasonable as IP would usually use ARP first | ||
312 | * before any unicast frames are sent. | ||
313 | * | ||
314 | * If we are already connected to the neighbor (neighbor's virtual address | ||
315 | * is known) we just prepare the WLP header and the caller will continue to | ||
316 | * send the frame. | ||
317 | * | ||
318 | * A failure in this function usually indicates something that cannot be | ||
319 | * fixed automatically. So, if this function fails (@return < 0) the calling | ||
320 | * function should not retry to send the frame as it will very likely keep | ||
321 | * failing. | ||
322 | * | ||
323 | */ | ||
324 | int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp, | ||
325 | struct sk_buff *skb, struct uwb_dev_addr *dst) | ||
326 | { | ||
327 | int result = -EINVAL; | ||
328 | struct ethhdr *eth_hdr = (void *) skb->data; | ||
329 | |||
330 | if (is_multicast_ether_addr(eth_hdr->h_dest)) { | ||
331 | result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb); | ||
332 | if (result < 0) { | ||
333 | if (printk_ratelimit()) | ||
334 | dev_err(dev, "Unable to handle broadcast " | ||
335 | "frame from WLP client.\n"); | ||
336 | goto out; | ||
337 | } | ||
338 | dev_kfree_skb_irq(skb); | ||
339 | result = 1; | ||
340 | /* Frame will be transmitted by WLP. */ | ||
341 | } else { | ||
342 | result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst, | ||
343 | wlp_wss_prep_hdr, skb); | ||
344 | if (unlikely(result < 0)) { | ||
345 | if (printk_ratelimit()) | ||
346 | dev_err(dev, "Unable to prepare " | ||
347 | "skb for transmission. \n"); | ||
348 | goto out; | ||
349 | } | ||
350 | } | ||
351 | out: | ||
352 | return result; | ||
353 | } | ||
354 | EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame); | ||
diff --git a/drivers/uwb/wlp/wlp-internal.h b/drivers/uwb/wlp/wlp-internal.h deleted file mode 100644 index 3e8d5de7c5b9..000000000000 --- a/drivers/uwb/wlp/wlp-internal.h +++ /dev/null | |||
@@ -1,224 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * Internal API | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WLP_INTERNAL_H__ | ||
25 | #define __WLP_INTERNAL_H__ | ||
26 | |||
27 | /** | ||
28 | * State of WSS connection | ||
29 | * | ||
30 | * A device needs to connect to a neighbor in an activated WSS before data | ||
31 | * can be transmitted. The spec also distinguishes between a new connection | ||
32 | * attempt and a connection attempt after previous connection attempts. The | ||
33 | * state WLP_WSS_CONNECT_FAILED is used for this scenario. See WLP 0.99 | ||
34 | * [7.2.6] | ||
35 | */ | ||
36 | enum wlp_wss_connect { | ||
37 | WLP_WSS_UNCONNECTED = 0, | ||
38 | WLP_WSS_CONNECTED, | ||
39 | WLP_WSS_CONNECT_FAILED, | ||
40 | }; | ||
41 | |||
42 | extern struct kobj_type wss_ktype; | ||
43 | extern struct attribute_group wss_attr_group; | ||
44 | |||
45 | /* This should be changed to a dynamic array where entries are sorted | ||
46 | * by eth_addr and search is done in a binary form | ||
47 | * | ||
48 | * Although thinking twice about it: this technologie's maximum reach | ||
49 | * is 10 meters...unless you want to pack too much stuff in around | ||
50 | * your radio controller/WLP device, the list will probably not be | ||
51 | * too big. | ||
52 | * | ||
53 | * In any case, there is probably some data structure in the kernel | ||
54 | * than we could reused for that already. | ||
55 | * | ||
56 | * The below structure is really just good while we support one WSS per | ||
57 | * host. | ||
58 | */ | ||
59 | struct wlp_eda_node { | ||
60 | struct list_head list_node; | ||
61 | unsigned char eth_addr[ETH_ALEN]; | ||
62 | struct uwb_dev_addr dev_addr; | ||
63 | struct wlp_wss *wss; | ||
64 | unsigned char virt_addr[ETH_ALEN]; | ||
65 | u8 tag; | ||
66 | enum wlp_wss_connect state; | ||
67 | }; | ||
68 | |||
69 | typedef int (*wlp_eda_for_each_f)(struct wlp *, struct wlp_eda_node *, void *); | ||
70 | |||
71 | extern void wlp_eda_init(struct wlp_eda *); | ||
72 | extern void wlp_eda_release(struct wlp_eda *); | ||
73 | extern int wlp_eda_create_node(struct wlp_eda *, | ||
74 | const unsigned char eth_addr[ETH_ALEN], | ||
75 | const struct uwb_dev_addr *); | ||
76 | extern void wlp_eda_rm_node(struct wlp_eda *, const struct uwb_dev_addr *); | ||
77 | extern int wlp_eda_update_node(struct wlp_eda *, | ||
78 | const struct uwb_dev_addr *, | ||
79 | struct wlp_wss *, | ||
80 | const unsigned char virt_addr[ETH_ALEN], | ||
81 | const u8, const enum wlp_wss_connect); | ||
82 | extern int wlp_eda_update_node_state(struct wlp_eda *, | ||
83 | const struct uwb_dev_addr *, | ||
84 | const enum wlp_wss_connect); | ||
85 | |||
86 | extern int wlp_copy_eda_node(struct wlp_eda *, struct uwb_dev_addr *, | ||
87 | struct wlp_eda_node *); | ||
88 | extern int wlp_eda_for_each(struct wlp_eda *, wlp_eda_for_each_f , void *); | ||
89 | extern int wlp_eda_for_virtual(struct wlp_eda *, | ||
90 | const unsigned char eth_addr[ETH_ALEN], | ||
91 | struct uwb_dev_addr *, | ||
92 | wlp_eda_for_each_f , void *); | ||
93 | |||
94 | |||
95 | extern void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *); | ||
96 | |||
97 | extern size_t wlp_wss_key_print(char *, size_t, u8 *); | ||
98 | |||
99 | /* Function called when no more references to WSS exists */ | ||
100 | extern void wlp_wss_release(struct kobject *); | ||
101 | |||
102 | extern void wlp_wss_reset(struct wlp_wss *); | ||
103 | extern int wlp_wss_create_activate(struct wlp_wss *, struct wlp_uuid *, | ||
104 | char *, unsigned, unsigned); | ||
105 | extern int wlp_wss_enroll_activate(struct wlp_wss *, struct wlp_uuid *, | ||
106 | struct uwb_dev_addr *); | ||
107 | extern ssize_t wlp_discover(struct wlp *); | ||
108 | |||
109 | extern int wlp_enroll_neighbor(struct wlp *, struct wlp_neighbor_e *, | ||
110 | struct wlp_wss *, struct wlp_uuid *); | ||
111 | extern int wlp_wss_is_active(struct wlp *, struct wlp_wss *, | ||
112 | struct uwb_dev_addr *); | ||
113 | |||
114 | struct wlp_assoc_conn_ctx { | ||
115 | struct work_struct ws; | ||
116 | struct wlp *wlp; | ||
117 | struct sk_buff *skb; | ||
118 | struct wlp_eda_node eda_entry; | ||
119 | }; | ||
120 | |||
121 | |||
122 | extern int wlp_wss_connect_prep(struct wlp *, struct wlp_eda_node *, void *); | ||
123 | extern int wlp_wss_send_copy(struct wlp *, struct wlp_eda_node *, void *); | ||
124 | |||
125 | |||
126 | /* Message handling */ | ||
127 | struct wlp_assoc_frame_ctx { | ||
128 | struct work_struct ws; | ||
129 | struct wlp *wlp; | ||
130 | struct sk_buff *skb; | ||
131 | struct uwb_dev_addr src; | ||
132 | }; | ||
133 | |||
134 | extern int wlp_wss_prep_hdr(struct wlp *, struct wlp_eda_node *, void *); | ||
135 | extern void wlp_handle_d1_frame(struct work_struct *); | ||
136 | extern int wlp_parse_d2_frame_to_cache(struct wlp *, struct sk_buff *, | ||
137 | struct wlp_neighbor_e *); | ||
138 | extern int wlp_parse_d2_frame_to_enroll(struct wlp_wss *, struct sk_buff *, | ||
139 | struct wlp_neighbor_e *, | ||
140 | struct wlp_uuid *); | ||
141 | extern void wlp_handle_c1_frame(struct work_struct *); | ||
142 | extern void wlp_handle_c3_frame(struct work_struct *); | ||
143 | extern int wlp_parse_c3c4_frame(struct wlp *, struct sk_buff *, | ||
144 | struct wlp_uuid *, u8 *, | ||
145 | struct uwb_mac_addr *); | ||
146 | extern int wlp_parse_f0(struct wlp *, struct sk_buff *); | ||
147 | extern int wlp_send_assoc_frame(struct wlp *, struct wlp_wss *, | ||
148 | struct uwb_dev_addr *, enum wlp_assoc_type); | ||
149 | extern ssize_t wlp_get_version(struct wlp *, struct wlp_attr_version *, | ||
150 | u8 *, ssize_t); | ||
151 | extern ssize_t wlp_get_wssid(struct wlp *, struct wlp_attr_wssid *, | ||
152 | struct wlp_uuid *, ssize_t); | ||
153 | extern int __wlp_alloc_device_info(struct wlp *); | ||
154 | extern int __wlp_setup_device_info(struct wlp *); | ||
155 | |||
156 | extern struct wlp_wss_attribute wss_attribute_properties; | ||
157 | extern struct wlp_wss_attribute wss_attribute_members; | ||
158 | extern struct wlp_wss_attribute wss_attribute_state; | ||
159 | |||
160 | static inline | ||
161 | size_t wlp_wss_uuid_print(char *buf, size_t bufsize, struct wlp_uuid *uuid) | ||
162 | { | ||
163 | size_t result; | ||
164 | |||
165 | result = scnprintf(buf, bufsize, | ||
166 | "%02x:%02x:%02x:%02x:%02x:%02x:" | ||
167 | "%02x:%02x:%02x:%02x:%02x:%02x:" | ||
168 | "%02x:%02x:%02x:%02x", | ||
169 | uuid->data[0], uuid->data[1], | ||
170 | uuid->data[2], uuid->data[3], | ||
171 | uuid->data[4], uuid->data[5], | ||
172 | uuid->data[6], uuid->data[7], | ||
173 | uuid->data[8], uuid->data[9], | ||
174 | uuid->data[10], uuid->data[11], | ||
175 | uuid->data[12], uuid->data[13], | ||
176 | uuid->data[14], uuid->data[15]); | ||
177 | return result; | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * FIXME: How should a nonce be displayed? | ||
182 | */ | ||
183 | static inline | ||
184 | size_t wlp_wss_nonce_print(char *buf, size_t bufsize, struct wlp_nonce *nonce) | ||
185 | { | ||
186 | size_t result; | ||
187 | |||
188 | result = scnprintf(buf, bufsize, | ||
189 | "%02x %02x %02x %02x %02x %02x " | ||
190 | "%02x %02x %02x %02x %02x %02x " | ||
191 | "%02x %02x %02x %02x", | ||
192 | nonce->data[0], nonce->data[1], | ||
193 | nonce->data[2], nonce->data[3], | ||
194 | nonce->data[4], nonce->data[5], | ||
195 | nonce->data[6], nonce->data[7], | ||
196 | nonce->data[8], nonce->data[9], | ||
197 | nonce->data[10], nonce->data[11], | ||
198 | nonce->data[12], nonce->data[13], | ||
199 | nonce->data[14], nonce->data[15]); | ||
200 | return result; | ||
201 | } | ||
202 | |||
203 | |||
204 | static inline | ||
205 | void wlp_session_cb(struct wlp *wlp) | ||
206 | { | ||
207 | struct completion *completion = wlp->session->cb_priv; | ||
208 | complete(completion); | ||
209 | } | ||
210 | |||
211 | static inline | ||
212 | int wlp_uuid_is_set(struct wlp_uuid *uuid) | ||
213 | { | ||
214 | struct wlp_uuid zero_uuid = { .data = { 0x00, 0x00, 0x00, 0x00, | ||
215 | 0x00, 0x00, 0x00, 0x00, | ||
216 | 0x00, 0x00, 0x00, 0x00, | ||
217 | 0x00, 0x00, 0x00, 0x00} }; | ||
218 | |||
219 | if (!memcmp(uuid, &zero_uuid, sizeof(*uuid))) | ||
220 | return 0; | ||
221 | return 1; | ||
222 | } | ||
223 | |||
224 | #endif /* __WLP_INTERNAL_H__ */ | ||
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c deleted file mode 100644 index 7f6a630bf26c..000000000000 --- a/drivers/uwb/wlp/wlp-lc.c +++ /dev/null | |||
@@ -1,560 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * FIXME: docs | ||
23 | */ | ||
24 | #include <linux/wlp.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include "wlp-internal.h" | ||
28 | |||
29 | static | ||
30 | void wlp_neighbor_init(struct wlp_neighbor_e *neighbor) | ||
31 | { | ||
32 | INIT_LIST_HEAD(&neighbor->wssid); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * Create area for device information storage | ||
37 | * | ||
38 | * wlp->mutex must be held | ||
39 | */ | ||
40 | int __wlp_alloc_device_info(struct wlp *wlp) | ||
41 | { | ||
42 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
43 | BUG_ON(wlp->dev_info != NULL); | ||
44 | wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL); | ||
45 | if (wlp->dev_info == NULL) { | ||
46 | dev_err(dev, "WLP: Unable to allocate memory for " | ||
47 | "device information.\n"); | ||
48 | return -ENOMEM; | ||
49 | } | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Fill in device information using function provided by driver | ||
56 | * | ||
57 | * wlp->mutex must be held | ||
58 | */ | ||
59 | static | ||
60 | void __wlp_fill_device_info(struct wlp *wlp) | ||
61 | { | ||
62 | wlp->fill_device_info(wlp, wlp->dev_info); | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Setup device information | ||
67 | * | ||
68 | * Allocate area for device information and populate it. | ||
69 | * | ||
70 | * wlp->mutex must be held | ||
71 | */ | ||
72 | int __wlp_setup_device_info(struct wlp *wlp) | ||
73 | { | ||
74 | int result; | ||
75 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
76 | |||
77 | result = __wlp_alloc_device_info(wlp); | ||
78 | if (result < 0) { | ||
79 | dev_err(dev, "WLP: Unable to allocate area for " | ||
80 | "device information.\n"); | ||
81 | return result; | ||
82 | } | ||
83 | __wlp_fill_device_info(wlp); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * Remove information about neighbor stored temporarily | ||
89 | * | ||
90 | * Information learned during discovey should only be stored when the | ||
91 | * device enrolls in the neighbor's WSS. We do need to store this | ||
92 | * information temporarily in order to present it to the user. | ||
93 | * | ||
94 | * We are only interested in keeping neighbor WSS information if that | ||
95 | * neighbor is accepting enrollment. | ||
96 | * | ||
97 | * should be called with wlp->nbmutex held | ||
98 | */ | ||
99 | void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor) | ||
100 | { | ||
101 | struct wlp_wssid_e *wssid_e, *next; | ||
102 | u8 keep; | ||
103 | if (!list_empty(&neighbor->wssid)) { | ||
104 | list_for_each_entry_safe(wssid_e, next, &neighbor->wssid, | ||
105 | node) { | ||
106 | if (wssid_e->info != NULL) { | ||
107 | keep = wssid_e->info->accept_enroll; | ||
108 | kfree(wssid_e->info); | ||
109 | wssid_e->info = NULL; | ||
110 | if (!keep) { | ||
111 | list_del(&wssid_e->node); | ||
112 | kfree(wssid_e); | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | if (neighbor->info != NULL) { | ||
118 | kfree(neighbor->info); | ||
119 | neighbor->info = NULL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Populate WLP neighborhood cache with neighbor information | ||
125 | * | ||
126 | * A new neighbor is found. If it is discoverable then we add it to the | ||
127 | * neighborhood cache. | ||
128 | * | ||
129 | */ | ||
130 | static | ||
131 | int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev) | ||
132 | { | ||
133 | int result = 0; | ||
134 | int discoverable; | ||
135 | struct wlp_neighbor_e *neighbor; | ||
136 | |||
137 | /* | ||
138 | * FIXME: | ||
139 | * Use contents of WLP IE found in beacon cache to determine if | ||
140 | * neighbor is discoverable. | ||
141 | * The device does not support WLP IE yet so this still needs to be | ||
142 | * done. Until then we assume all devices are discoverable. | ||
143 | */ | ||
144 | discoverable = 1; /* will be changed when FIXME disappears */ | ||
145 | if (discoverable) { | ||
146 | /* Add neighbor to cache for discovery */ | ||
147 | neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL); | ||
148 | if (neighbor == NULL) { | ||
149 | dev_err(&dev->dev, "Unable to create memory for " | ||
150 | "new neighbor. \n"); | ||
151 | result = -ENOMEM; | ||
152 | goto error_no_mem; | ||
153 | } | ||
154 | wlp_neighbor_init(neighbor); | ||
155 | uwb_dev_get(dev); | ||
156 | neighbor->uwb_dev = dev; | ||
157 | list_add(&neighbor->node, &wlp->neighbors); | ||
158 | } | ||
159 | error_no_mem: | ||
160 | return result; | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * Remove one neighbor from cache | ||
165 | */ | ||
166 | static | ||
167 | void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor) | ||
168 | { | ||
169 | struct wlp_wssid_e *wssid_e, *next_wssid_e; | ||
170 | |||
171 | list_for_each_entry_safe(wssid_e, next_wssid_e, | ||
172 | &neighbor->wssid, node) { | ||
173 | list_del(&wssid_e->node); | ||
174 | kfree(wssid_e); | ||
175 | } | ||
176 | uwb_dev_put(neighbor->uwb_dev); | ||
177 | list_del(&neighbor->node); | ||
178 | kfree(neighbor); | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * Clear entire neighborhood cache. | ||
183 | */ | ||
184 | static | ||
185 | void __wlp_neighbors_release(struct wlp *wlp) | ||
186 | { | ||
187 | struct wlp_neighbor_e *neighbor, *next; | ||
188 | if (list_empty(&wlp->neighbors)) | ||
189 | return; | ||
190 | list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { | ||
191 | __wlp_neighbor_release(neighbor); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static | ||
196 | void wlp_neighbors_release(struct wlp *wlp) | ||
197 | { | ||
198 | mutex_lock(&wlp->nbmutex); | ||
199 | __wlp_neighbors_release(wlp); | ||
200 | mutex_unlock(&wlp->nbmutex); | ||
201 | } | ||
202 | |||
203 | |||
204 | |||
205 | /** | ||
206 | * Send D1 message to neighbor, receive D2 message | ||
207 | * | ||
208 | * @neighbor: neighbor to which D1 message will be sent | ||
209 | * @wss: if not NULL, it is an enrollment request for this WSS | ||
210 | * @wssid: if wss not NULL, this is the wssid of the WSS in which we | ||
211 | * want to enroll | ||
212 | * | ||
213 | * A D1/D2 exchange is done for one of two reasons: discovery or | ||
214 | * enrollment. If done for discovery the D1 message is sent to the neighbor | ||
215 | * and the contents of the D2 response is stored in a temporary cache. | ||
216 | * If done for enrollment the @wss and @wssid are provided also. In this | ||
217 | * case the D1 message is sent to the neighbor, the D2 response is parsed | ||
218 | * for enrollment of the WSS with wssid. | ||
219 | * | ||
220 | * &wss->mutex is held | ||
221 | */ | ||
222 | static | ||
223 | int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor, | ||
224 | struct wlp_wss *wss, struct wlp_uuid *wssid) | ||
225 | { | ||
226 | int result; | ||
227 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
228 | DECLARE_COMPLETION_ONSTACK(completion); | ||
229 | struct wlp_session session; | ||
230 | struct sk_buff *skb; | ||
231 | struct wlp_frame_assoc *resp; | ||
232 | struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; | ||
233 | |||
234 | mutex_lock(&wlp->mutex); | ||
235 | if (!wlp_uuid_is_set(&wlp->uuid)) { | ||
236 | dev_err(dev, "WLP: UUID is not set. Set via sysfs to " | ||
237 | "proceed.\n"); | ||
238 | result = -ENXIO; | ||
239 | goto out; | ||
240 | } | ||
241 | /* Send D1 association frame */ | ||
242 | result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1); | ||
243 | if (result < 0) { | ||
244 | dev_err(dev, "Unable to send D1 frame to neighbor " | ||
245 | "%02x:%02x (%d)\n", dev_addr->data[1], | ||
246 | dev_addr->data[0], result); | ||
247 | goto out; | ||
248 | } | ||
249 | /* Create session, wait for response */ | ||
250 | session.exp_message = WLP_ASSOC_D2; | ||
251 | session.cb = wlp_session_cb; | ||
252 | session.cb_priv = &completion; | ||
253 | session.neighbor_addr = *dev_addr; | ||
254 | BUG_ON(wlp->session != NULL); | ||
255 | wlp->session = &session; | ||
256 | /* Wait for D2/F0 frame */ | ||
257 | result = wait_for_completion_interruptible_timeout(&completion, | ||
258 | WLP_PER_MSG_TIMEOUT * HZ); | ||
259 | if (result == 0) { | ||
260 | result = -ETIMEDOUT; | ||
261 | dev_err(dev, "Timeout while sending D1 to neighbor " | ||
262 | "%02x:%02x.\n", dev_addr->data[1], | ||
263 | dev_addr->data[0]); | ||
264 | goto error_session; | ||
265 | } | ||
266 | if (result < 0) { | ||
267 | dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n", | ||
268 | dev_addr->data[1], dev_addr->data[0]); | ||
269 | goto error_session; | ||
270 | } | ||
271 | /* Parse message in session->data: it will be either D2 or F0 */ | ||
272 | skb = session.data; | ||
273 | resp = (void *) skb->data; | ||
274 | |||
275 | if (resp->type == WLP_ASSOC_F0) { | ||
276 | result = wlp_parse_f0(wlp, skb); | ||
277 | if (result < 0) | ||
278 | dev_err(dev, "WLP: Unable to parse F0 from neighbor " | ||
279 | "%02x:%02x.\n", dev_addr->data[1], | ||
280 | dev_addr->data[0]); | ||
281 | result = -EINVAL; | ||
282 | goto error_resp_parse; | ||
283 | } | ||
284 | if (wss == NULL) { | ||
285 | /* Discovery */ | ||
286 | result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor); | ||
287 | if (result < 0) { | ||
288 | dev_err(dev, "WLP: Unable to parse D2 message from " | ||
289 | "neighbor %02x:%02x for discovery.\n", | ||
290 | dev_addr->data[1], dev_addr->data[0]); | ||
291 | goto error_resp_parse; | ||
292 | } | ||
293 | } else { | ||
294 | /* Enrollment */ | ||
295 | result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor, | ||
296 | wssid); | ||
297 | if (result < 0) { | ||
298 | dev_err(dev, "WLP: Unable to parse D2 message from " | ||
299 | "neighbor %02x:%02x for enrollment.\n", | ||
300 | dev_addr->data[1], dev_addr->data[0]); | ||
301 | goto error_resp_parse; | ||
302 | } | ||
303 | } | ||
304 | error_resp_parse: | ||
305 | kfree_skb(skb); | ||
306 | error_session: | ||
307 | wlp->session = NULL; | ||
308 | out: | ||
309 | mutex_unlock(&wlp->mutex); | ||
310 | return result; | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * Enroll into WSS of provided WSSID by using neighbor as registrar | ||
315 | * | ||
316 | * &wss->mutex is held | ||
317 | */ | ||
318 | int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor, | ||
319 | struct wlp_wss *wss, struct wlp_uuid *wssid) | ||
320 | { | ||
321 | int result = 0; | ||
322 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
323 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
324 | struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; | ||
325 | |||
326 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
327 | |||
328 | result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid); | ||
329 | if (result < 0) { | ||
330 | dev_err(dev, "WLP: D1/D2 message exchange for enrollment " | ||
331 | "failed. result = %d \n", result); | ||
332 | goto out; | ||
333 | } | ||
334 | if (wss->state != WLP_WSS_STATE_PART_ENROLLED) { | ||
335 | dev_err(dev, "WLP: Unable to enroll into WSS %s using " | ||
336 | "neighbor %02x:%02x. \n", buf, | ||
337 | dev_addr->data[1], dev_addr->data[0]); | ||
338 | result = -EINVAL; | ||
339 | goto out; | ||
340 | } | ||
341 | if (wss->secure_status == WLP_WSS_SECURE) { | ||
342 | dev_err(dev, "FIXME: need to complete secure enrollment.\n"); | ||
343 | result = -EINVAL; | ||
344 | goto error; | ||
345 | } else { | ||
346 | wss->state = WLP_WSS_STATE_ENROLLED; | ||
347 | dev_dbg(dev, "WLP: Success Enrollment into unsecure WSS " | ||
348 | "%s using neighbor %02x:%02x. \n", | ||
349 | buf, dev_addr->data[1], dev_addr->data[0]); | ||
350 | } | ||
351 | out: | ||
352 | return result; | ||
353 | error: | ||
354 | wlp_wss_reset(wss); | ||
355 | return result; | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * Discover WSS information of neighbor's active WSS | ||
360 | */ | ||
361 | static | ||
362 | int wlp_discover_neighbor(struct wlp *wlp, | ||
363 | struct wlp_neighbor_e *neighbor) | ||
364 | { | ||
365 | return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL); | ||
366 | } | ||
367 | |||
368 | |||
369 | /** | ||
370 | * Each neighbor in the neighborhood cache is discoverable. Discover it. | ||
371 | * | ||
372 | * Discovery is done through sending of D1 association frame and parsing | ||
373 | * the D2 association frame response. Only wssid from D2 will be included | ||
374 | * in neighbor cache, rest is just displayed to user and forgotten. | ||
375 | * | ||
376 | * The discovery is not done in parallel. This is simple and enables us to | ||
377 | * maintain only one association context. | ||
378 | * | ||
379 | * The discovery of one neighbor does not affect the other, but if the | ||
380 | * discovery of a neighbor fails it is removed from the neighborhood cache. | ||
381 | */ | ||
382 | static | ||
383 | int wlp_discover_all_neighbors(struct wlp *wlp) | ||
384 | { | ||
385 | int result = 0; | ||
386 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
387 | struct wlp_neighbor_e *neighbor, *next; | ||
388 | |||
389 | list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { | ||
390 | result = wlp_discover_neighbor(wlp, neighbor); | ||
391 | if (result < 0) { | ||
392 | dev_err(dev, "WLP: Unable to discover neighbor " | ||
393 | "%02x:%02x, removing from neighborhood. \n", | ||
394 | neighbor->uwb_dev->dev_addr.data[1], | ||
395 | neighbor->uwb_dev->dev_addr.data[0]); | ||
396 | __wlp_neighbor_release(neighbor); | ||
397 | } | ||
398 | } | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | static int wlp_add_neighbor_helper(struct device *dev, void *priv) | ||
403 | { | ||
404 | struct wlp *wlp = priv; | ||
405 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
406 | |||
407 | return wlp_add_neighbor(wlp, uwb_dev); | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * Discover WLP neighborhood | ||
412 | * | ||
413 | * Will send D1 association frame to all devices in beacon group that have | ||
414 | * discoverable bit set in WLP IE. D2 frames will be received, information | ||
415 | * displayed to user in @buf. Partial information (from D2 association | ||
416 | * frame) will be cached to assist with future association | ||
417 | * requests. | ||
418 | * | ||
419 | * The discovery of the WLP neighborhood is triggered by the user. This | ||
420 | * should occur infrequently and we thus free current cache and re-allocate | ||
421 | * memory if needed. | ||
422 | * | ||
423 | * If one neighbor fails during initial discovery (determining if it is a | ||
424 | * neighbor or not), we fail all - note that interaction with neighbor has | ||
425 | * not occured at this point so if a failure occurs we know something went wrong | ||
426 | * locally. We thus undo everything. | ||
427 | */ | ||
428 | ssize_t wlp_discover(struct wlp *wlp) | ||
429 | { | ||
430 | int result = 0; | ||
431 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
432 | |||
433 | mutex_lock(&wlp->nbmutex); | ||
434 | /* Clear current neighborhood cache. */ | ||
435 | __wlp_neighbors_release(wlp); | ||
436 | /* Determine which devices in neighborhood. Repopulate cache. */ | ||
437 | result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp); | ||
438 | if (result < 0) { | ||
439 | /* May have partial neighbor information, release all. */ | ||
440 | __wlp_neighbors_release(wlp); | ||
441 | goto error_dev_for_each; | ||
442 | } | ||
443 | /* Discover the properties of devices in neighborhood. */ | ||
444 | result = wlp_discover_all_neighbors(wlp); | ||
445 | /* In case of failure we still print our partial results. */ | ||
446 | if (result < 0) { | ||
447 | dev_err(dev, "Unable to fully discover neighborhood. \n"); | ||
448 | result = 0; | ||
449 | } | ||
450 | error_dev_for_each: | ||
451 | mutex_unlock(&wlp->nbmutex); | ||
452 | return result; | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * Handle events from UWB stack | ||
457 | * | ||
458 | * We handle events conservatively. If a neighbor goes off the air we | ||
459 | * remove it from the neighborhood. If an association process is in | ||
460 | * progress this function will block waiting for the nbmutex to become | ||
461 | * free. The association process will thus be allowed to complete before it | ||
462 | * is removed. | ||
463 | */ | ||
464 | static | ||
465 | void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev, | ||
466 | enum uwb_notifs event) | ||
467 | { | ||
468 | struct wlp *wlp = _wlp; | ||
469 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
470 | struct wlp_neighbor_e *neighbor, *next; | ||
471 | int result; | ||
472 | switch (event) { | ||
473 | case UWB_NOTIF_ONAIR: | ||
474 | result = wlp_eda_create_node(&wlp->eda, | ||
475 | uwb_dev->mac_addr.data, | ||
476 | &uwb_dev->dev_addr); | ||
477 | if (result < 0) | ||
478 | dev_err(dev, "WLP: Unable to add new neighbor " | ||
479 | "%02x:%02x to EDA cache.\n", | ||
480 | uwb_dev->dev_addr.data[1], | ||
481 | uwb_dev->dev_addr.data[0]); | ||
482 | break; | ||
483 | case UWB_NOTIF_OFFAIR: | ||
484 | wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr); | ||
485 | mutex_lock(&wlp->nbmutex); | ||
486 | list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { | ||
487 | if (neighbor->uwb_dev == uwb_dev) | ||
488 | __wlp_neighbor_release(neighbor); | ||
489 | } | ||
490 | mutex_unlock(&wlp->nbmutex); | ||
491 | break; | ||
492 | default: | ||
493 | dev_err(dev, "don't know how to handle event %d from uwb\n", | ||
494 | event); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void wlp_channel_changed(struct uwb_pal *pal, int channel) | ||
499 | { | ||
500 | struct wlp *wlp = container_of(pal, struct wlp, pal); | ||
501 | |||
502 | if (channel < 0) | ||
503 | netif_carrier_off(wlp->ndev); | ||
504 | else | ||
505 | netif_carrier_on(wlp->ndev); | ||
506 | } | ||
507 | |||
508 | int wlp_setup(struct wlp *wlp, struct uwb_rc *rc, struct net_device *ndev) | ||
509 | { | ||
510 | int result; | ||
511 | |||
512 | BUG_ON(wlp->fill_device_info == NULL); | ||
513 | BUG_ON(wlp->xmit_frame == NULL); | ||
514 | BUG_ON(wlp->stop_queue == NULL); | ||
515 | BUG_ON(wlp->start_queue == NULL); | ||
516 | |||
517 | wlp->rc = rc; | ||
518 | wlp->ndev = ndev; | ||
519 | wlp_eda_init(&wlp->eda);/* Set up address cache */ | ||
520 | wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb; | ||
521 | wlp->uwb_notifs_handler.data = wlp; | ||
522 | uwb_notifs_register(rc, &wlp->uwb_notifs_handler); | ||
523 | |||
524 | uwb_pal_init(&wlp->pal); | ||
525 | wlp->pal.rc = rc; | ||
526 | wlp->pal.channel_changed = wlp_channel_changed; | ||
527 | result = uwb_pal_register(&wlp->pal); | ||
528 | if (result < 0) | ||
529 | uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); | ||
530 | |||
531 | return result; | ||
532 | } | ||
533 | EXPORT_SYMBOL_GPL(wlp_setup); | ||
534 | |||
535 | void wlp_remove(struct wlp *wlp) | ||
536 | { | ||
537 | wlp_neighbors_release(wlp); | ||
538 | uwb_pal_unregister(&wlp->pal); | ||
539 | uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); | ||
540 | wlp_eda_release(&wlp->eda); | ||
541 | mutex_lock(&wlp->mutex); | ||
542 | if (wlp->dev_info != NULL) | ||
543 | kfree(wlp->dev_info); | ||
544 | mutex_unlock(&wlp->mutex); | ||
545 | wlp->rc = NULL; | ||
546 | } | ||
547 | EXPORT_SYMBOL_GPL(wlp_remove); | ||
548 | |||
549 | /** | ||
550 | * wlp_reset_all - reset the WLP hardware | ||
551 | * @wlp: the WLP device to reset. | ||
552 | * | ||
553 | * This schedules a full hardware reset of the WLP device. The radio | ||
554 | * controller and any other PALs will also be reset. | ||
555 | */ | ||
556 | void wlp_reset_all(struct wlp *wlp) | ||
557 | { | ||
558 | uwb_rc_reset_all(wlp->rc); | ||
559 | } | ||
560 | EXPORT_SYMBOL_GPL(wlp_reset_all); | ||
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c deleted file mode 100644 index 67872c83b679..000000000000 --- a/drivers/uwb/wlp/wss-lc.c +++ /dev/null | |||
@@ -1,959 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2007 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Implementation of the WLP association protocol. | ||
23 | * | ||
24 | * FIXME: Docs | ||
25 | * | ||
26 | * A UWB network interface will configure a WSS through wlp_wss_setup() after | ||
27 | * the interface has been assigned a MAC address, typically after | ||
28 | * "ifconfig" has been called. When the interface goes down it should call | ||
29 | * wlp_wss_remove(). | ||
30 | * | ||
31 | * When the WSS is ready for use the user interacts via sysfs to create, | ||
32 | * discover, and activate WSS. | ||
33 | * | ||
34 | * wlp_wss_enroll_activate() | ||
35 | * | ||
36 | * wlp_wss_create_activate() | ||
37 | * wlp_wss_set_wssid_hash() | ||
38 | * wlp_wss_comp_wssid_hash() | ||
39 | * wlp_wss_sel_bcast_addr() | ||
40 | * wlp_wss_sysfs_add() | ||
41 | * | ||
42 | * Called when no more references to WSS exist: | ||
43 | * wlp_wss_release() | ||
44 | * wlp_wss_reset() | ||
45 | */ | ||
46 | #include <linux/etherdevice.h> /* for is_valid_ether_addr */ | ||
47 | #include <linux/skbuff.h> | ||
48 | #include <linux/slab.h> | ||
49 | #include <linux/wlp.h> | ||
50 | |||
51 | #include "wlp-internal.h" | ||
52 | |||
53 | size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key) | ||
54 | { | ||
55 | size_t result; | ||
56 | |||
57 | result = scnprintf(buf, bufsize, | ||
58 | "%02x %02x %02x %02x %02x %02x " | ||
59 | "%02x %02x %02x %02x %02x %02x " | ||
60 | "%02x %02x %02x %02x", | ||
61 | key[0], key[1], key[2], key[3], | ||
62 | key[4], key[5], key[6], key[7], | ||
63 | key[8], key[9], key[10], key[11], | ||
64 | key[12], key[13], key[14], key[15]); | ||
65 | return result; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Compute WSSID hash | ||
70 | * WLP Draft 0.99 [7.2.1] | ||
71 | * | ||
72 | * The WSSID hash for a WSSID is the result of an octet-wise exclusive-OR | ||
73 | * of all octets in the WSSID. | ||
74 | */ | ||
75 | static | ||
76 | u8 wlp_wss_comp_wssid_hash(struct wlp_uuid *wssid) | ||
77 | { | ||
78 | return wssid->data[0] ^ wssid->data[1] ^ wssid->data[2] | ||
79 | ^ wssid->data[3] ^ wssid->data[4] ^ wssid->data[5] | ||
80 | ^ wssid->data[6] ^ wssid->data[7] ^ wssid->data[8] | ||
81 | ^ wssid->data[9] ^ wssid->data[10] ^ wssid->data[11] | ||
82 | ^ wssid->data[12] ^ wssid->data[13] ^ wssid->data[14] | ||
83 | ^ wssid->data[15]; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * Select a multicast EUI-48 for the WSS broadcast address. | ||
88 | * WLP Draft 0.99 [7.2.1] | ||
89 | * | ||
90 | * Selected based on the WiMedia Alliance OUI, 00-13-88, within the WLP | ||
91 | * range, [01-13-88-00-01-00, 01-13-88-00-01-FF] inclusive. | ||
92 | * | ||
93 | * This address is currently hardcoded. | ||
94 | * FIXME? | ||
95 | */ | ||
96 | static | ||
97 | struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss) | ||
98 | { | ||
99 | struct uwb_mac_addr bcast = { | ||
100 | .data = { 0x01, 0x13, 0x88, 0x00, 0x01, 0x00 } | ||
101 | }; | ||
102 | return bcast; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Clear the contents of the WSS structure - all except kobj, mutex, virtual | ||
107 | * | ||
108 | * We do not want to reinitialize - the internal kobj should not change as | ||
109 | * it still points to the parent received during setup. The mutex should | ||
110 | * remain also. We thus just reset values individually. | ||
111 | * The virutal address assigned to WSS will remain the same for the | ||
112 | * lifetime of the WSS. We only reset the fields that can change during its | ||
113 | * lifetime. | ||
114 | */ | ||
115 | void wlp_wss_reset(struct wlp_wss *wss) | ||
116 | { | ||
117 | memset(&wss->wssid, 0, sizeof(wss->wssid)); | ||
118 | wss->hash = 0; | ||
119 | memset(&wss->name[0], 0, sizeof(wss->name)); | ||
120 | memset(&wss->bcast, 0, sizeof(wss->bcast)); | ||
121 | wss->secure_status = WLP_WSS_UNSECURE; | ||
122 | memset(&wss->master_key[0], 0, sizeof(wss->master_key)); | ||
123 | wss->tag = 0; | ||
124 | wss->state = WLP_WSS_STATE_NONE; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * Create sysfs infrastructure for WSS | ||
129 | * | ||
130 | * The WSS is configured to have the interface as parent (see wlp_wss_setup()) | ||
131 | * a new sysfs directory that includes wssid as its name is created in the | ||
132 | * interface's sysfs directory. The group of files interacting with WSS are | ||
133 | * created also. | ||
134 | */ | ||
135 | static | ||
136 | int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str) | ||
137 | { | ||
138 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
139 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
140 | int result; | ||
141 | |||
142 | result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str); | ||
143 | if (result < 0) | ||
144 | return result; | ||
145 | wss->kobj.ktype = &wss_ktype; | ||
146 | result = kobject_init_and_add(&wss->kobj, | ||
147 | &wss_ktype, wss->kobj.parent, "wlp"); | ||
148 | if (result < 0) { | ||
149 | dev_err(dev, "WLP: Cannot register WSS kobject.\n"); | ||
150 | goto error_kobject_register; | ||
151 | } | ||
152 | result = sysfs_create_group(&wss->kobj, &wss_attr_group); | ||
153 | if (result < 0) { | ||
154 | dev_err(dev, "WLP: Cannot register WSS attributes: %d\n", | ||
155 | result); | ||
156 | goto error_sysfs_create_group; | ||
157 | } | ||
158 | return 0; | ||
159 | error_sysfs_create_group: | ||
160 | |||
161 | kobject_put(&wss->kobj); /* will free name if needed */ | ||
162 | return result; | ||
163 | error_kobject_register: | ||
164 | kfree(wss->kobj.name); | ||
165 | wss->kobj.name = NULL; | ||
166 | wss->kobj.ktype = NULL; | ||
167 | return result; | ||
168 | } | ||
169 | |||
170 | |||
171 | /** | ||
172 | * Release WSS | ||
173 | * | ||
174 | * No more references exist to this WSS. We should undo everything that was | ||
175 | * done in wlp_wss_create_activate() except removing the group. The group | ||
176 | * is not removed because an object can be unregistered before the group is | ||
177 | * created. We also undo any additional operations on the WSS after this | ||
178 | * (addition of members). | ||
179 | * | ||
180 | * If memory was allocated for the kobject's name then it will | ||
181 | * be freed by the kobject system during this time. | ||
182 | * | ||
183 | * The EDA cache is removed and reinitialized when the WSS is removed. We | ||
184 | * thus loose knowledge of members of this WSS at that time and need not do | ||
185 | * it here. | ||
186 | */ | ||
187 | void wlp_wss_release(struct kobject *kobj) | ||
188 | { | ||
189 | struct wlp_wss *wss = container_of(kobj, struct wlp_wss, kobj); | ||
190 | |||
191 | wlp_wss_reset(wss); | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * Enroll into a WSS using provided neighbor as registrar | ||
196 | * | ||
197 | * First search the neighborhood information to learn which neighbor is | ||
198 | * referred to, next proceed with enrollment. | ||
199 | * | ||
200 | * &wss->mutex is held | ||
201 | */ | ||
202 | static | ||
203 | int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
204 | struct uwb_dev_addr *dest) | ||
205 | { | ||
206 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
207 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
208 | struct wlp_neighbor_e *neighbor; | ||
209 | int result = -ENXIO; | ||
210 | struct uwb_dev_addr *dev_addr; | ||
211 | |||
212 | mutex_lock(&wlp->nbmutex); | ||
213 | list_for_each_entry(neighbor, &wlp->neighbors, node) { | ||
214 | dev_addr = &neighbor->uwb_dev->dev_addr; | ||
215 | if (!memcmp(dest, dev_addr, sizeof(*dest))) { | ||
216 | result = wlp_enroll_neighbor(wlp, neighbor, wss, wssid); | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | if (result == -ENXIO) | ||
221 | dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n", | ||
222 | dest->data[1], dest->data[0]); | ||
223 | mutex_unlock(&wlp->nbmutex); | ||
224 | return result; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * Enroll into a WSS previously discovered | ||
229 | * | ||
230 | * User provides WSSID of WSS, search for neighbor that has this WSS | ||
231 | * activated and attempt to enroll. | ||
232 | * | ||
233 | * &wss->mutex is held | ||
234 | */ | ||
235 | static | ||
236 | int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid) | ||
237 | { | ||
238 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
239 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
240 | struct wlp_neighbor_e *neighbor; | ||
241 | struct wlp_wssid_e *wssid_e; | ||
242 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
243 | int result = -ENXIO; | ||
244 | |||
245 | |||
246 | mutex_lock(&wlp->nbmutex); | ||
247 | list_for_each_entry(neighbor, &wlp->neighbors, node) { | ||
248 | list_for_each_entry(wssid_e, &neighbor->wssid, node) { | ||
249 | if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) { | ||
250 | result = wlp_enroll_neighbor(wlp, neighbor, | ||
251 | wss, wssid); | ||
252 | if (result == 0) /* enrollment success */ | ||
253 | goto out; | ||
254 | break; | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | out: | ||
259 | if (result == -ENXIO) { | ||
260 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
261 | dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf); | ||
262 | } | ||
263 | mutex_unlock(&wlp->nbmutex); | ||
264 | return result; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * Enroll into WSS with provided WSSID, registrar may be provided | ||
269 | * | ||
270 | * @wss: out WSS that will be enrolled | ||
271 | * @wssid: wssid of neighboring WSS that we want to enroll in | ||
272 | * @devaddr: registrar can be specified, will be broadcast (ff:ff) if any | ||
273 | * neighbor can be used as registrar. | ||
274 | * | ||
275 | * &wss->mutex is held | ||
276 | */ | ||
277 | static | ||
278 | int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
279 | struct uwb_dev_addr *devaddr) | ||
280 | { | ||
281 | int result; | ||
282 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
283 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
284 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
285 | struct uwb_dev_addr bcast = {.data = {0xff, 0xff} }; | ||
286 | |||
287 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
288 | |||
289 | if (wss->state != WLP_WSS_STATE_NONE) { | ||
290 | dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf); | ||
291 | result = -EEXIST; | ||
292 | goto error; | ||
293 | } | ||
294 | if (!memcmp(&bcast, devaddr, sizeof(bcast))) | ||
295 | result = wlp_wss_enroll_discovered(wss, wssid); | ||
296 | else | ||
297 | result = wlp_wss_enroll_target(wss, wssid, devaddr); | ||
298 | if (result < 0) { | ||
299 | dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n", | ||
300 | buf, result); | ||
301 | goto error; | ||
302 | } | ||
303 | dev_dbg(dev, "Successfully enrolled into WSS %s \n", buf); | ||
304 | result = wlp_wss_sysfs_add(wss, buf); | ||
305 | if (result < 0) { | ||
306 | dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n"); | ||
307 | wlp_wss_reset(wss); | ||
308 | } | ||
309 | error: | ||
310 | return result; | ||
311 | |||
312 | } | ||
313 | |||
314 | /** | ||
315 | * Activate given WSS | ||
316 | * | ||
317 | * Prior to activation a WSS must be enrolled. To activate a WSS a device | ||
318 | * includes the WSS hash in the WLP IE in its beacon in each superframe. | ||
319 | * WLP 0.99 [7.2.5]. | ||
320 | * | ||
321 | * The WSS tag is also computed at this time. We only support one activated | ||
322 | * WSS so we can use the hash as a tag - there will never be a conflict. | ||
323 | * | ||
324 | * We currently only support one activated WSS so only one WSS hash is | ||
325 | * included in the WLP IE. | ||
326 | */ | ||
327 | static | ||
328 | int wlp_wss_activate(struct wlp_wss *wss) | ||
329 | { | ||
330 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
331 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
332 | struct uwb_rc *uwb_rc = wlp->rc; | ||
333 | int result; | ||
334 | struct { | ||
335 | struct wlp_ie wlp_ie; | ||
336 | u8 hash; /* only include one hash */ | ||
337 | } ie_data; | ||
338 | |||
339 | BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED); | ||
340 | wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid); | ||
341 | wss->tag = wss->hash; | ||
342 | memset(&ie_data, 0, sizeof(ie_data)); | ||
343 | ie_data.wlp_ie.hdr.element_id = UWB_IE_WLP; | ||
344 | ie_data.wlp_ie.hdr.length = sizeof(ie_data) - sizeof(struct uwb_ie_hdr); | ||
345 | wlp_ie_set_hash_length(&ie_data.wlp_ie, sizeof(ie_data.hash)); | ||
346 | ie_data.hash = wss->hash; | ||
347 | result = uwb_rc_ie_add(uwb_rc, &ie_data.wlp_ie.hdr, | ||
348 | sizeof(ie_data)); | ||
349 | if (result < 0) { | ||
350 | dev_err(dev, "WLP: Unable to add WLP IE to beacon. " | ||
351 | "result = %d.\n", result); | ||
352 | goto error_wlp_ie; | ||
353 | } | ||
354 | wss->state = WLP_WSS_STATE_ACTIVE; | ||
355 | result = 0; | ||
356 | error_wlp_ie: | ||
357 | return result; | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * Enroll in and activate WSS identified by provided WSSID | ||
362 | * | ||
363 | * The neighborhood cache should contain a list of all neighbors and the | ||
364 | * WSS they have activated. Based on that cache we search which neighbor we | ||
365 | * can perform the association process with. The user also has option to | ||
366 | * specify which neighbor it prefers as registrar. | ||
367 | * Successful enrollment is followed by activation. | ||
368 | * Successful activation will create the sysfs directory containing | ||
369 | * specific information regarding this WSS. | ||
370 | */ | ||
371 | int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
372 | struct uwb_dev_addr *devaddr) | ||
373 | { | ||
374 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
375 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
376 | int result = 0; | ||
377 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
378 | |||
379 | mutex_lock(&wss->mutex); | ||
380 | result = wlp_wss_enroll(wss, wssid, devaddr); | ||
381 | if (result < 0) { | ||
382 | wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); | ||
383 | dev_err(dev, "WLP: Enrollment into WSS %s failed.\n", buf); | ||
384 | goto error_enroll; | ||
385 | } | ||
386 | result = wlp_wss_activate(wss); | ||
387 | if (result < 0) { | ||
388 | dev_err(dev, "WLP: Unable to activate WSS. Undoing enrollment " | ||
389 | "result = %d \n", result); | ||
390 | /* Undo enrollment */ | ||
391 | wlp_wss_reset(wss); | ||
392 | goto error_activate; | ||
393 | } | ||
394 | error_activate: | ||
395 | error_enroll: | ||
396 | mutex_unlock(&wss->mutex); | ||
397 | return result; | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * Create, enroll, and activate a new WSS | ||
402 | * | ||
403 | * @wssid: new wssid provided by user | ||
404 | * @name: WSS name requested by used. | ||
405 | * @sec_status: security status requested by user | ||
406 | * | ||
407 | * A user requested the creation of a new WSS. All operations are done | ||
408 | * locally. The new WSS will be stored locally, the hash will be included | ||
409 | * in the WLP IE, and the sysfs infrastructure for this WSS will be | ||
410 | * created. | ||
411 | */ | ||
412 | int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
413 | char *name, unsigned sec_status, unsigned accept) | ||
414 | { | ||
415 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
416 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
417 | int result = 0; | ||
418 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
419 | |||
420 | result = wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
421 | |||
422 | if (!mutex_trylock(&wss->mutex)) { | ||
423 | dev_err(dev, "WLP: WLP association session in progress.\n"); | ||
424 | return -EBUSY; | ||
425 | } | ||
426 | if (wss->state != WLP_WSS_STATE_NONE) { | ||
427 | dev_err(dev, "WLP: WSS already exists. Not creating new.\n"); | ||
428 | result = -EEXIST; | ||
429 | goto out; | ||
430 | } | ||
431 | if (wss->kobj.parent == NULL) { | ||
432 | dev_err(dev, "WLP: WSS parent not ready. Is network interface " | ||
433 | "up?\n"); | ||
434 | result = -ENXIO; | ||
435 | goto out; | ||
436 | } | ||
437 | if (sec_status == WLP_WSS_SECURE) { | ||
438 | dev_err(dev, "WLP: FIXME Creation of secure WSS not " | ||
439 | "supported yet.\n"); | ||
440 | result = -EINVAL; | ||
441 | goto out; | ||
442 | } | ||
443 | wss->wssid = *wssid; | ||
444 | memcpy(wss->name, name, sizeof(wss->name)); | ||
445 | wss->bcast = wlp_wss_sel_bcast_addr(wss); | ||
446 | wss->secure_status = sec_status; | ||
447 | wss->accept_enroll = accept; | ||
448 | /*wss->virtual_addr is initialized in call to wlp_wss_setup*/ | ||
449 | /* sysfs infrastructure */ | ||
450 | result = wlp_wss_sysfs_add(wss, buf); | ||
451 | if (result < 0) { | ||
452 | dev_err(dev, "Cannot set up sysfs for WSS kobject.\n"); | ||
453 | wlp_wss_reset(wss); | ||
454 | goto out; | ||
455 | } else | ||
456 | result = 0; | ||
457 | wss->state = WLP_WSS_STATE_ENROLLED; | ||
458 | result = wlp_wss_activate(wss); | ||
459 | if (result < 0) { | ||
460 | dev_err(dev, "WLP: Unable to activate WSS. Undoing " | ||
461 | "enrollment\n"); | ||
462 | wlp_wss_reset(wss); | ||
463 | goto out; | ||
464 | } | ||
465 | result = 0; | ||
466 | out: | ||
467 | mutex_unlock(&wss->mutex); | ||
468 | return result; | ||
469 | } | ||
470 | |||
471 | /** | ||
472 | * Determine if neighbor has WSS activated | ||
473 | * | ||
474 | * @returns: 1 if neighbor has WSS activated, zero otherwise | ||
475 | * | ||
476 | * This can be done in two ways: | ||
477 | * - send a C1 frame, parse C2/F0 response | ||
478 | * - examine the WLP IE sent by the neighbor | ||
479 | * | ||
480 | * The WLP IE is not fully supported in hardware so we use the C1/C2 frame | ||
481 | * exchange to determine if a WSS is activated. Using the WLP IE should be | ||
482 | * faster and should be used when it becomes possible. | ||
483 | */ | ||
484 | int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss, | ||
485 | struct uwb_dev_addr *dev_addr) | ||
486 | { | ||
487 | int result = 0; | ||
488 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
489 | DECLARE_COMPLETION_ONSTACK(completion); | ||
490 | struct wlp_session session; | ||
491 | struct sk_buff *skb; | ||
492 | struct wlp_frame_assoc *resp; | ||
493 | struct wlp_uuid wssid; | ||
494 | |||
495 | mutex_lock(&wlp->mutex); | ||
496 | /* Send C1 association frame */ | ||
497 | result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1); | ||
498 | if (result < 0) { | ||
499 | dev_err(dev, "Unable to send C1 frame to neighbor " | ||
500 | "%02x:%02x (%d)\n", dev_addr->data[1], | ||
501 | dev_addr->data[0], result); | ||
502 | result = 0; | ||
503 | goto out; | ||
504 | } | ||
505 | /* Create session, wait for response */ | ||
506 | session.exp_message = WLP_ASSOC_C2; | ||
507 | session.cb = wlp_session_cb; | ||
508 | session.cb_priv = &completion; | ||
509 | session.neighbor_addr = *dev_addr; | ||
510 | BUG_ON(wlp->session != NULL); | ||
511 | wlp->session = &session; | ||
512 | /* Wait for C2/F0 frame */ | ||
513 | result = wait_for_completion_interruptible_timeout(&completion, | ||
514 | WLP_PER_MSG_TIMEOUT * HZ); | ||
515 | if (result == 0) { | ||
516 | dev_err(dev, "Timeout while sending C1 to neighbor " | ||
517 | "%02x:%02x.\n", dev_addr->data[1], | ||
518 | dev_addr->data[0]); | ||
519 | goto out; | ||
520 | } | ||
521 | if (result < 0) { | ||
522 | dev_err(dev, "Unable to send C1 to neighbor %02x:%02x.\n", | ||
523 | dev_addr->data[1], dev_addr->data[0]); | ||
524 | result = 0; | ||
525 | goto out; | ||
526 | } | ||
527 | /* Parse message in session->data: it will be either C2 or F0 */ | ||
528 | skb = session.data; | ||
529 | resp = (void *) skb->data; | ||
530 | if (resp->type == WLP_ASSOC_F0) { | ||
531 | result = wlp_parse_f0(wlp, skb); | ||
532 | if (result < 0) | ||
533 | dev_err(dev, "WLP: unable to parse incoming F0 " | ||
534 | "frame from neighbor %02x:%02x.\n", | ||
535 | dev_addr->data[1], dev_addr->data[0]); | ||
536 | result = 0; | ||
537 | goto error_resp_parse; | ||
538 | } | ||
539 | /* WLP version and message type fields have already been parsed */ | ||
540 | result = wlp_get_wssid(wlp, (void *)resp + sizeof(*resp), &wssid, | ||
541 | skb->len - sizeof(*resp)); | ||
542 | if (result < 0) { | ||
543 | dev_err(dev, "WLP: unable to obtain WSSID from C2 frame.\n"); | ||
544 | result = 0; | ||
545 | goto error_resp_parse; | ||
546 | } | ||
547 | if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))) | ||
548 | result = 1; | ||
549 | else { | ||
550 | dev_err(dev, "WLP: Received a C2 frame without matching " | ||
551 | "WSSID.\n"); | ||
552 | result = 0; | ||
553 | } | ||
554 | error_resp_parse: | ||
555 | kfree_skb(skb); | ||
556 | out: | ||
557 | wlp->session = NULL; | ||
558 | mutex_unlock(&wlp->mutex); | ||
559 | return result; | ||
560 | } | ||
561 | |||
562 | /** | ||
563 | * Activate connection with neighbor by updating EDA cache | ||
564 | * | ||
565 | * @wss: local WSS to which neighbor wants to connect | ||
566 | * @dev_addr: neighbor's address | ||
567 | * @wssid: neighbor's WSSID - must be same as our WSS's WSSID | ||
568 | * @tag: neighbor's WSS tag used to identify frames transmitted by it | ||
569 | * @virt_addr: neighbor's virtual EUI-48 | ||
570 | */ | ||
571 | static | ||
572 | int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss, | ||
573 | struct uwb_dev_addr *dev_addr, | ||
574 | struct wlp_uuid *wssid, u8 *tag, | ||
575 | struct uwb_mac_addr *virt_addr) | ||
576 | { | ||
577 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
578 | int result = 0; | ||
579 | |||
580 | if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) { | ||
581 | /* Update EDA cache */ | ||
582 | result = wlp_eda_update_node(&wlp->eda, dev_addr, wss, | ||
583 | (void *) virt_addr->data, *tag, | ||
584 | WLP_WSS_CONNECTED); | ||
585 | if (result < 0) | ||
586 | dev_err(dev, "WLP: Unable to update EDA cache " | ||
587 | "with new connected neighbor information.\n"); | ||
588 | } else { | ||
589 | dev_err(dev, "WLP: Neighbor does not have matching WSSID.\n"); | ||
590 | result = -EINVAL; | ||
591 | } | ||
592 | return result; | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * Connect to WSS neighbor | ||
597 | * | ||
598 | * Use C3/C4 exchange to determine if neighbor has WSS activated and | ||
599 | * retrieve the WSS tag and virtual EUI-48 of the neighbor. | ||
600 | */ | ||
601 | static | ||
602 | int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss, | ||
603 | struct uwb_dev_addr *dev_addr) | ||
604 | { | ||
605 | int result; | ||
606 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
607 | struct wlp_uuid wssid; | ||
608 | u8 tag; | ||
609 | struct uwb_mac_addr virt_addr; | ||
610 | DECLARE_COMPLETION_ONSTACK(completion); | ||
611 | struct wlp_session session; | ||
612 | struct wlp_frame_assoc *resp; | ||
613 | struct sk_buff *skb; | ||
614 | |||
615 | mutex_lock(&wlp->mutex); | ||
616 | /* Send C3 association frame */ | ||
617 | result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3); | ||
618 | if (result < 0) { | ||
619 | dev_err(dev, "Unable to send C3 frame to neighbor " | ||
620 | "%02x:%02x (%d)\n", dev_addr->data[1], | ||
621 | dev_addr->data[0], result); | ||
622 | goto out; | ||
623 | } | ||
624 | /* Create session, wait for response */ | ||
625 | session.exp_message = WLP_ASSOC_C4; | ||
626 | session.cb = wlp_session_cb; | ||
627 | session.cb_priv = &completion; | ||
628 | session.neighbor_addr = *dev_addr; | ||
629 | BUG_ON(wlp->session != NULL); | ||
630 | wlp->session = &session; | ||
631 | /* Wait for C4/F0 frame */ | ||
632 | result = wait_for_completion_interruptible_timeout(&completion, | ||
633 | WLP_PER_MSG_TIMEOUT * HZ); | ||
634 | if (result == 0) { | ||
635 | dev_err(dev, "Timeout while sending C3 to neighbor " | ||
636 | "%02x:%02x.\n", dev_addr->data[1], | ||
637 | dev_addr->data[0]); | ||
638 | result = -ETIMEDOUT; | ||
639 | goto out; | ||
640 | } | ||
641 | if (result < 0) { | ||
642 | dev_err(dev, "Unable to send C3 to neighbor %02x:%02x.\n", | ||
643 | dev_addr->data[1], dev_addr->data[0]); | ||
644 | goto out; | ||
645 | } | ||
646 | /* Parse message in session->data: it will be either C4 or F0 */ | ||
647 | skb = session.data; | ||
648 | resp = (void *) skb->data; | ||
649 | if (resp->type == WLP_ASSOC_F0) { | ||
650 | result = wlp_parse_f0(wlp, skb); | ||
651 | if (result < 0) | ||
652 | dev_err(dev, "WLP: unable to parse incoming F0 " | ||
653 | "frame from neighbor %02x:%02x.\n", | ||
654 | dev_addr->data[1], dev_addr->data[0]); | ||
655 | result = -EINVAL; | ||
656 | goto error_resp_parse; | ||
657 | } | ||
658 | result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr); | ||
659 | if (result < 0) { | ||
660 | dev_err(dev, "WLP: Unable to parse C4 frame from neighbor.\n"); | ||
661 | goto error_resp_parse; | ||
662 | } | ||
663 | result = wlp_wss_activate_connection(wlp, wss, dev_addr, &wssid, &tag, | ||
664 | &virt_addr); | ||
665 | if (result < 0) { | ||
666 | dev_err(dev, "WLP: Unable to activate connection to " | ||
667 | "neighbor %02x:%02x.\n", dev_addr->data[1], | ||
668 | dev_addr->data[0]); | ||
669 | goto error_resp_parse; | ||
670 | } | ||
671 | error_resp_parse: | ||
672 | kfree_skb(skb); | ||
673 | out: | ||
674 | /* Record that we unsuccessfully tried to connect to this neighbor */ | ||
675 | if (result < 0) | ||
676 | wlp_eda_update_node_state(&wlp->eda, dev_addr, | ||
677 | WLP_WSS_CONNECT_FAILED); | ||
678 | wlp->session = NULL; | ||
679 | mutex_unlock(&wlp->mutex); | ||
680 | return result; | ||
681 | } | ||
682 | |||
683 | /** | ||
684 | * Connect to neighbor with common WSS, send pending frame | ||
685 | * | ||
686 | * This function is scheduled when a frame is destined to a neighbor with | ||
687 | * which we do not have a connection. A copy of the EDA cache entry is | ||
688 | * provided - not the actual cache entry (because it is protected by a | ||
689 | * spinlock). | ||
690 | * | ||
691 | * First determine if neighbor has the same WSS activated, connect if it | ||
692 | * does. The C3/C4 exchange is dual purpose to determine if neighbor has | ||
693 | * WSS activated and proceed with the connection. | ||
694 | * | ||
695 | * The frame that triggered the connection setup is sent after connection | ||
696 | * setup. | ||
697 | * | ||
698 | * network queue is stopped - we need to restart when done | ||
699 | * | ||
700 | */ | ||
701 | static | ||
702 | void wlp_wss_connect_send(struct work_struct *ws) | ||
703 | { | ||
704 | struct wlp_assoc_conn_ctx *conn_ctx = container_of(ws, | ||
705 | struct wlp_assoc_conn_ctx, | ||
706 | ws); | ||
707 | struct wlp *wlp = conn_ctx->wlp; | ||
708 | struct sk_buff *skb = conn_ctx->skb; | ||
709 | struct wlp_eda_node *eda_entry = &conn_ctx->eda_entry; | ||
710 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
711 | struct wlp_wss *wss = &wlp->wss; | ||
712 | int result; | ||
713 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
714 | |||
715 | mutex_lock(&wss->mutex); | ||
716 | if (wss->state < WLP_WSS_STATE_ACTIVE) { | ||
717 | if (printk_ratelimit()) | ||
718 | dev_err(dev, "WLP: Attempting to connect with " | ||
719 | "WSS that is not active or connected.\n"); | ||
720 | dev_kfree_skb(skb); | ||
721 | goto out; | ||
722 | } | ||
723 | /* Establish connection - send C3 rcv C4 */ | ||
724 | result = wlp_wss_connect_neighbor(wlp, wss, dev_addr); | ||
725 | if (result < 0) { | ||
726 | if (printk_ratelimit()) | ||
727 | dev_err(dev, "WLP: Unable to establish connection " | ||
728 | "with neighbor %02x:%02x.\n", | ||
729 | dev_addr->data[1], dev_addr->data[0]); | ||
730 | dev_kfree_skb(skb); | ||
731 | goto out; | ||
732 | } | ||
733 | /* EDA entry changed, update the local copy being used */ | ||
734 | result = wlp_copy_eda_node(&wlp->eda, dev_addr, eda_entry); | ||
735 | if (result < 0) { | ||
736 | if (printk_ratelimit()) | ||
737 | dev_err(dev, "WLP: Cannot find EDA entry for " | ||
738 | "neighbor %02x:%02x \n", | ||
739 | dev_addr->data[1], dev_addr->data[0]); | ||
740 | } | ||
741 | result = wlp_wss_prep_hdr(wlp, eda_entry, skb); | ||
742 | if (result < 0) { | ||
743 | if (printk_ratelimit()) | ||
744 | dev_err(dev, "WLP: Unable to prepare frame header for " | ||
745 | "transmission (neighbor %02x:%02x). \n", | ||
746 | dev_addr->data[1], dev_addr->data[0]); | ||
747 | dev_kfree_skb(skb); | ||
748 | goto out; | ||
749 | } | ||
750 | BUG_ON(wlp->xmit_frame == NULL); | ||
751 | result = wlp->xmit_frame(wlp, skb, dev_addr); | ||
752 | if (result < 0) { | ||
753 | if (printk_ratelimit()) | ||
754 | dev_err(dev, "WLP: Unable to transmit frame: %d\n", | ||
755 | result); | ||
756 | if (result == -ENXIO) | ||
757 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
758 | /* We could try again ... */ | ||
759 | dev_kfree_skb(skb);/*we need to free if tx fails */ | ||
760 | } | ||
761 | out: | ||
762 | kfree(conn_ctx); | ||
763 | BUG_ON(wlp->start_queue == NULL); | ||
764 | wlp->start_queue(wlp); | ||
765 | mutex_unlock(&wss->mutex); | ||
766 | } | ||
767 | |||
768 | /** | ||
769 | * Add WLP header to outgoing skb | ||
770 | * | ||
771 | * @eda_entry: pointer to neighbor's entry in the EDA cache | ||
772 | * @_skb: skb containing data destined to the neighbor | ||
773 | */ | ||
774 | int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry, | ||
775 | void *_skb) | ||
776 | { | ||
777 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
778 | int result = 0; | ||
779 | unsigned char *eth_addr = eda_entry->eth_addr; | ||
780 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
781 | struct sk_buff *skb = _skb; | ||
782 | struct wlp_frame_std_abbrv_hdr *std_hdr; | ||
783 | |||
784 | if (eda_entry->state == WLP_WSS_CONNECTED) { | ||
785 | /* Add WLP header */ | ||
786 | BUG_ON(skb_headroom(skb) < sizeof(*std_hdr)); | ||
787 | std_hdr = (void *) __skb_push(skb, sizeof(*std_hdr)); | ||
788 | std_hdr->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
789 | std_hdr->hdr.type = WLP_FRAME_STANDARD; | ||
790 | std_hdr->tag = eda_entry->wss->tag; | ||
791 | } else { | ||
792 | if (printk_ratelimit()) | ||
793 | dev_err(dev, "WLP: Destination neighbor (Ethernet: " | ||
794 | "%pM, Dev: %02x:%02x) is not connected.\n", | ||
795 | eth_addr, dev_addr->data[1], dev_addr->data[0]); | ||
796 | result = -EINVAL; | ||
797 | } | ||
798 | return result; | ||
799 | } | ||
800 | |||
801 | |||
802 | /** | ||
803 | * Prepare skb for neighbor: connect if not already and prep WLP header | ||
804 | * | ||
805 | * This function is called in interrupt context, but it needs to sleep. We | ||
806 | * temporarily stop the net queue to establish the WLP connection. | ||
807 | * Setup of the WLP connection and restart of queue is scheduled | ||
808 | * on the default work queue. | ||
809 | * | ||
810 | * run with eda->lock held (spinlock) | ||
811 | */ | ||
812 | int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry, | ||
813 | void *_skb) | ||
814 | { | ||
815 | int result = 0; | ||
816 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
817 | struct sk_buff *skb = _skb; | ||
818 | struct wlp_assoc_conn_ctx *conn_ctx; | ||
819 | |||
820 | if (eda_entry->state == WLP_WSS_UNCONNECTED) { | ||
821 | /* We don't want any more packets while we set up connection */ | ||
822 | BUG_ON(wlp->stop_queue == NULL); | ||
823 | wlp->stop_queue(wlp); | ||
824 | conn_ctx = kmalloc(sizeof(*conn_ctx), GFP_ATOMIC); | ||
825 | if (conn_ctx == NULL) { | ||
826 | if (printk_ratelimit()) | ||
827 | dev_err(dev, "WLP: Unable to allocate memory " | ||
828 | "for connection handling.\n"); | ||
829 | result = -ENOMEM; | ||
830 | goto out; | ||
831 | } | ||
832 | conn_ctx->wlp = wlp; | ||
833 | conn_ctx->skb = skb; | ||
834 | conn_ctx->eda_entry = *eda_entry; | ||
835 | INIT_WORK(&conn_ctx->ws, wlp_wss_connect_send); | ||
836 | schedule_work(&conn_ctx->ws); | ||
837 | result = 1; | ||
838 | } else if (eda_entry->state == WLP_WSS_CONNECT_FAILED) { | ||
839 | /* Previous connection attempts failed, don't retry - see | ||
840 | * conditions for connection in WLP 0.99 [7.6.2] */ | ||
841 | if (printk_ratelimit()) | ||
842 | dev_err(dev, "Could not connect to neighbor " | ||
843 | "previously. Not retrying. \n"); | ||
844 | result = -ENONET; | ||
845 | goto out; | ||
846 | } else /* eda_entry->state == WLP_WSS_CONNECTED */ | ||
847 | result = wlp_wss_prep_hdr(wlp, eda_entry, skb); | ||
848 | out: | ||
849 | return result; | ||
850 | } | ||
851 | |||
852 | /** | ||
853 | * Emulate broadcast: copy skb, send copy to neighbor (connect if not already) | ||
854 | * | ||
855 | * We need to copy skbs in the case where we emulate broadcast through | ||
856 | * unicast. We copy instead of clone because we are modifying the data of | ||
857 | * the frame after copying ... clones share data so we cannot emulate | ||
858 | * broadcast using clones. | ||
859 | * | ||
860 | * run with eda->lock held (spinlock) | ||
861 | */ | ||
862 | int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry, | ||
863 | void *_skb) | ||
864 | { | ||
865 | int result = -ENOMEM; | ||
866 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
867 | struct sk_buff *skb = _skb; | ||
868 | struct sk_buff *copy; | ||
869 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
870 | |||
871 | copy = skb_copy(skb, GFP_ATOMIC); | ||
872 | if (copy == NULL) { | ||
873 | if (printk_ratelimit()) | ||
874 | dev_err(dev, "WLP: Unable to copy skb for " | ||
875 | "transmission.\n"); | ||
876 | goto out; | ||
877 | } | ||
878 | result = wlp_wss_connect_prep(wlp, eda_entry, copy); | ||
879 | if (result < 0) { | ||
880 | if (printk_ratelimit()) | ||
881 | dev_err(dev, "WLP: Unable to connect/send skb " | ||
882 | "to neighbor.\n"); | ||
883 | dev_kfree_skb_irq(copy); | ||
884 | goto out; | ||
885 | } else if (result == 1) | ||
886 | /* Frame will be transmitted separately */ | ||
887 | goto out; | ||
888 | BUG_ON(wlp->xmit_frame == NULL); | ||
889 | result = wlp->xmit_frame(wlp, copy, dev_addr); | ||
890 | if (result < 0) { | ||
891 | if (printk_ratelimit()) | ||
892 | dev_err(dev, "WLP: Unable to transmit frame: %d\n", | ||
893 | result); | ||
894 | if ((result == -ENXIO) && printk_ratelimit()) | ||
895 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
896 | /* We could try again ... */ | ||
897 | dev_kfree_skb_irq(copy);/*we need to free if tx fails */ | ||
898 | } | ||
899 | out: | ||
900 | return result; | ||
901 | } | ||
902 | |||
903 | |||
904 | /** | ||
905 | * Setup WSS | ||
906 | * | ||
907 | * Should be called by network driver after the interface has been given a | ||
908 | * MAC address. | ||
909 | */ | ||
910 | int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss) | ||
911 | { | ||
912 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
913 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
914 | int result = 0; | ||
915 | |||
916 | mutex_lock(&wss->mutex); | ||
917 | wss->kobj.parent = &net_dev->dev.kobj; | ||
918 | if (!is_valid_ether_addr(net_dev->dev_addr)) { | ||
919 | dev_err(dev, "WLP: Invalid MAC address. Cannot use for" | ||
920 | "virtual.\n"); | ||
921 | result = -EINVAL; | ||
922 | goto out; | ||
923 | } | ||
924 | memcpy(wss->virtual_addr.data, net_dev->dev_addr, | ||
925 | sizeof(wss->virtual_addr.data)); | ||
926 | out: | ||
927 | mutex_unlock(&wss->mutex); | ||
928 | return result; | ||
929 | } | ||
930 | EXPORT_SYMBOL_GPL(wlp_wss_setup); | ||
931 | |||
932 | /** | ||
933 | * Remove WSS | ||
934 | * | ||
935 | * Called by client that configured WSS through wlp_wss_setup(). This | ||
936 | * function is called when client no longer needs WSS, eg. client shuts | ||
937 | * down. | ||
938 | * | ||
939 | * We remove the WLP IE from the beacon before initiating local cleanup. | ||
940 | */ | ||
941 | void wlp_wss_remove(struct wlp_wss *wss) | ||
942 | { | ||
943 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
944 | |||
945 | mutex_lock(&wss->mutex); | ||
946 | if (wss->state == WLP_WSS_STATE_ACTIVE) | ||
947 | uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP); | ||
948 | if (wss->state != WLP_WSS_STATE_NONE) { | ||
949 | sysfs_remove_group(&wss->kobj, &wss_attr_group); | ||
950 | kobject_put(&wss->kobj); | ||
951 | } | ||
952 | wss->kobj.parent = NULL; | ||
953 | memset(&wss->virtual_addr, 0, sizeof(wss->virtual_addr)); | ||
954 | /* Cleanup EDA cache */ | ||
955 | wlp_eda_release(&wlp->eda); | ||
956 | wlp_eda_init(&wlp->eda); | ||
957 | mutex_unlock(&wss->mutex); | ||
958 | } | ||
959 | EXPORT_SYMBOL_GPL(wlp_wss_remove); | ||
diff --git a/include/linux/wlp.h b/include/linux/wlp.h deleted file mode 100644 index c76fe2392506..000000000000 --- a/include/linux/wlp.h +++ /dev/null | |||
@@ -1,736 +0,0 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * FIXME: docs | ||
23 | * | ||
24 | * - Does not (yet) include support for WLP control frames | ||
25 | * WLP Draft 0.99 [6.5]. | ||
26 | * | ||
27 | * A visual representation of the data structures. | ||
28 | * | ||
29 | * wssidB wssidB | ||
30 | * ^ ^ | ||
31 | * | | | ||
32 | * wssidA wssidA | ||
33 | * wlp interface { ^ ^ | ||
34 | * ... | | | ||
35 | * ... ... wssid wssid ... | ||
36 | * wlp --- ... | | | ||
37 | * }; neighbors --> neighbA --> neighbB | ||
38 | * ... | ||
39 | * wss | ||
40 | * ... | ||
41 | * eda cache --> neighborA --> neighborB --> neighborC ... | ||
42 | */ | ||
43 | |||
44 | #ifndef __LINUX__WLP_H_ | ||
45 | #define __LINUX__WLP_H_ | ||
46 | |||
47 | #include <linux/netdevice.h> | ||
48 | #include <linux/skbuff.h> | ||
49 | #include <linux/list.h> | ||
50 | #include <linux/uwb.h> | ||
51 | |||
52 | /** | ||
53 | * WLP Protocol ID | ||
54 | * WLP Draft 0.99 [6.2] | ||
55 | * | ||
56 | * The MUX header for all WLP frames | ||
57 | */ | ||
58 | #define WLP_PROTOCOL_ID 0x0100 | ||
59 | |||
60 | /** | ||
61 | * WLP Version | ||
62 | * WLP version placed in the association frames (WLP 0.99 [6.6]) | ||
63 | */ | ||
64 | #define WLP_VERSION 0x10 | ||
65 | |||
66 | /** | ||
67 | * Bytes needed to print UUID as string | ||
68 | */ | ||
69 | #define WLP_WSS_UUID_STRSIZE 48 | ||
70 | |||
71 | /** | ||
72 | * Bytes needed to print nonce as string | ||
73 | */ | ||
74 | #define WLP_WSS_NONCE_STRSIZE 48 | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Size used for WLP name size | ||
79 | * | ||
80 | * The WSS name is set to 65 bytes, 1 byte larger than the maximum | ||
81 | * allowed by the WLP spec. This is to have a null terminated string | ||
82 | * for display to the user. A maximum of 64 bytes will still be used | ||
83 | * when placing the WSS name field in association frames. | ||
84 | */ | ||
85 | #define WLP_WSS_NAME_SIZE 65 | ||
86 | |||
87 | /** | ||
88 | * Number of bytes added by WLP to data frame | ||
89 | * | ||
90 | * A data frame transmitted from a host will be placed in a Standard or | ||
91 | * Abbreviated WLP frame. These have an extra 4 bytes of header (struct | ||
92 | * wlp_frame_std_abbrv_hdr). | ||
93 | * When the stack sends this data frame for transmission it needs to ensure | ||
94 | * there is enough headroom for this header. | ||
95 | */ | ||
96 | #define WLP_DATA_HLEN 4 | ||
97 | |||
98 | /** | ||
99 | * State of device regarding WLP Service Set | ||
100 | * | ||
101 | * WLP_WSS_STATE_NONE: the host does not participate in any WSS | ||
102 | * WLP_WSS_STATE_PART_ENROLLED: used as part of the enrollment sequence | ||
103 | * ("Partial Enroll"). This state is used to | ||
104 | * indicate the first part of enrollment that is | ||
105 | * unsecure. If the WSS is unsecure then the | ||
106 | * state will promptly go to WLP_WSS_STATE_ENROLLED, | ||
107 | * if the WSS is not secure then the enrollment | ||
108 | * procedure is a few more steps before we are | ||
109 | * enrolled. | ||
110 | * WLP_WSS_STATE_ENROLLED: the host is enrolled in a WSS | ||
111 | * WLP_WSS_STATE_ACTIVE: WSS is activated | ||
112 | * WLP_WSS_STATE_CONNECTED: host is connected to neighbor in WSS | ||
113 | * | ||
114 | */ | ||
115 | enum wlp_wss_state { | ||
116 | WLP_WSS_STATE_NONE = 0, | ||
117 | WLP_WSS_STATE_PART_ENROLLED, | ||
118 | WLP_WSS_STATE_ENROLLED, | ||
119 | WLP_WSS_STATE_ACTIVE, | ||
120 | WLP_WSS_STATE_CONNECTED, | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * WSS Secure status | ||
125 | * WLP 0.99 Table 6 | ||
126 | * | ||
127 | * Set to one if the WSS is secure, zero if it is not secure | ||
128 | */ | ||
129 | enum wlp_wss_sec_status { | ||
130 | WLP_WSS_UNSECURE = 0, | ||
131 | WLP_WSS_SECURE, | ||
132 | }; | ||
133 | |||
134 | /** | ||
135 | * WLP frame type | ||
136 | * WLP Draft 0.99 [6.2 Table 1] | ||
137 | */ | ||
138 | enum wlp_frame_type { | ||
139 | WLP_FRAME_STANDARD = 0, | ||
140 | WLP_FRAME_ABBREVIATED, | ||
141 | WLP_FRAME_CONTROL, | ||
142 | WLP_FRAME_ASSOCIATION, | ||
143 | }; | ||
144 | |||
145 | /** | ||
146 | * WLP Association Message Type | ||
147 | * WLP Draft 0.99 [6.6.1.2 Table 8] | ||
148 | */ | ||
149 | enum wlp_assoc_type { | ||
150 | WLP_ASSOC_D1 = 2, | ||
151 | WLP_ASSOC_D2 = 3, | ||
152 | WLP_ASSOC_M1 = 4, | ||
153 | WLP_ASSOC_M2 = 5, | ||
154 | WLP_ASSOC_M3 = 7, | ||
155 | WLP_ASSOC_M4 = 8, | ||
156 | WLP_ASSOC_M5 = 9, | ||
157 | WLP_ASSOC_M6 = 10, | ||
158 | WLP_ASSOC_M7 = 11, | ||
159 | WLP_ASSOC_M8 = 12, | ||
160 | WLP_ASSOC_F0 = 14, | ||
161 | WLP_ASSOC_E1 = 32, | ||
162 | WLP_ASSOC_E2 = 33, | ||
163 | WLP_ASSOC_C1 = 34, | ||
164 | WLP_ASSOC_C2 = 35, | ||
165 | WLP_ASSOC_C3 = 36, | ||
166 | WLP_ASSOC_C4 = 37, | ||
167 | }; | ||
168 | |||
169 | /** | ||
170 | * WLP Attribute Type | ||
171 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
172 | */ | ||
173 | enum wlp_attr_type { | ||
174 | WLP_ATTR_AUTH = 0x1005, /* Authenticator */ | ||
175 | WLP_ATTR_DEV_NAME = 0x1011, /* Device Name */ | ||
176 | WLP_ATTR_DEV_PWD_ID = 0x1012, /* Device Password ID */ | ||
177 | WLP_ATTR_E_HASH1 = 0x1014, /* E-Hash1 */ | ||
178 | WLP_ATTR_E_HASH2 = 0x1015, /* E-Hash2 */ | ||
179 | WLP_ATTR_E_SNONCE1 = 0x1016, /* E-SNonce1 */ | ||
180 | WLP_ATTR_E_SNONCE2 = 0x1017, /* E-SNonce2 */ | ||
181 | WLP_ATTR_ENCR_SET = 0x1018, /* Encrypted Settings */ | ||
182 | WLP_ATTR_ENRL_NONCE = 0x101A, /* Enrollee Nonce */ | ||
183 | WLP_ATTR_KEYWRAP_AUTH = 0x101E, /* Key Wrap Authenticator */ | ||
184 | WLP_ATTR_MANUF = 0x1021, /* Manufacturer */ | ||
185 | WLP_ATTR_MSG_TYPE = 0x1022, /* Message Type */ | ||
186 | WLP_ATTR_MODEL_NAME = 0x1023, /* Model Name */ | ||
187 | WLP_ATTR_MODEL_NR = 0x1024, /* Model Number */ | ||
188 | WLP_ATTR_PUB_KEY = 0x1032, /* Public Key */ | ||
189 | WLP_ATTR_REG_NONCE = 0x1039, /* Registrar Nonce */ | ||
190 | WLP_ATTR_R_HASH1 = 0x103D, /* R-Hash1 */ | ||
191 | WLP_ATTR_R_HASH2 = 0x103E, /* R-Hash2 */ | ||
192 | WLP_ATTR_R_SNONCE1 = 0x103F, /* R-SNonce1 */ | ||
193 | WLP_ATTR_R_SNONCE2 = 0x1040, /* R-SNonce2 */ | ||
194 | WLP_ATTR_SERIAL = 0x1042, /* Serial number */ | ||
195 | WLP_ATTR_UUID_E = 0x1047, /* UUID-E */ | ||
196 | WLP_ATTR_UUID_R = 0x1048, /* UUID-R */ | ||
197 | WLP_ATTR_PRI_DEV_TYPE = 0x1054, /* Primary Device Type */ | ||
198 | WLP_ATTR_SEC_DEV_TYPE = 0x1055, /* Secondary Device Type */ | ||
199 | WLP_ATTR_PORT_DEV = 0x1056, /* Portable Device */ | ||
200 | WLP_ATTR_APP_EXT = 0x1058, /* Application Extension */ | ||
201 | WLP_ATTR_WLP_VER = 0x2000, /* WLP Version */ | ||
202 | WLP_ATTR_WSSID = 0x2001, /* WSSID */ | ||
203 | WLP_ATTR_WSS_NAME = 0x2002, /* WSS Name */ | ||
204 | WLP_ATTR_WSS_SEC_STAT = 0x2003, /* WSS Secure Status */ | ||
205 | WLP_ATTR_WSS_BCAST = 0x2004, /* WSS Broadcast Address */ | ||
206 | WLP_ATTR_WSS_M_KEY = 0x2005, /* WSS Master Key */ | ||
207 | WLP_ATTR_ACC_ENRL = 0x2006, /* Accepting Enrollment */ | ||
208 | WLP_ATTR_WSS_INFO = 0x2007, /* WSS Information */ | ||
209 | WLP_ATTR_WSS_SEL_MTHD = 0x2008, /* WSS Selection Method */ | ||
210 | WLP_ATTR_ASSC_MTHD_LIST = 0x2009, /* Association Methods List */ | ||
211 | WLP_ATTR_SEL_ASSC_MTHD = 0x200A, /* Selected Association Method */ | ||
212 | WLP_ATTR_ENRL_HASH_COMM = 0x200B, /* Enrollee Hash Commitment */ | ||
213 | WLP_ATTR_WSS_TAG = 0x200C, /* WSS Tag */ | ||
214 | WLP_ATTR_WSS_VIRT = 0x200D, /* WSS Virtual EUI-48 */ | ||
215 | WLP_ATTR_WLP_ASSC_ERR = 0x200E, /* WLP Association Error */ | ||
216 | WLP_ATTR_VNDR_EXT = 0x200F, /* Vendor Extension */ | ||
217 | }; | ||
218 | |||
219 | /** | ||
220 | * WLP Category ID of primary/secondary device | ||
221 | * WLP Draft 0.99 [6.6.1.8 Table 12] | ||
222 | */ | ||
223 | enum wlp_dev_category_id { | ||
224 | WLP_DEV_CAT_COMPUTER = 1, | ||
225 | WLP_DEV_CAT_INPUT, | ||
226 | WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER, | ||
227 | WLP_DEV_CAT_CAMERA, | ||
228 | WLP_DEV_CAT_STORAGE, | ||
229 | WLP_DEV_CAT_INFRASTRUCTURE, | ||
230 | WLP_DEV_CAT_DISPLAY, | ||
231 | WLP_DEV_CAT_MULTIM, | ||
232 | WLP_DEV_CAT_GAMING, | ||
233 | WLP_DEV_CAT_TELEPHONE, | ||
234 | WLP_DEV_CAT_OTHER = 65535, | ||
235 | }; | ||
236 | |||
237 | /** | ||
238 | * WLP WSS selection method | ||
239 | * WLP Draft 0.99 [6.6.1.6 Table 10] | ||
240 | */ | ||
241 | enum wlp_wss_sel_mthd { | ||
242 | WLP_WSS_ENRL_SELECT = 1, /* Enrollee selects */ | ||
243 | WLP_WSS_REG_SELECT, /* Registrar selects */ | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * WLP association error values | ||
248 | * WLP Draft 0.99 [6.6.1.5 Table 9] | ||
249 | */ | ||
250 | enum wlp_assc_error { | ||
251 | WLP_ASSOC_ERROR_NONE, | ||
252 | WLP_ASSOC_ERROR_AUTH, /* Authenticator Failure */ | ||
253 | WLP_ASSOC_ERROR_ROGUE, /* Rogue activity suspected */ | ||
254 | WLP_ASSOC_ERROR_BUSY, /* Device busy */ | ||
255 | WLP_ASSOC_ERROR_LOCK, /* Setup Locked */ | ||
256 | WLP_ASSOC_ERROR_NOT_READY, /* Registrar not ready */ | ||
257 | WLP_ASSOC_ERROR_INV, /* Invalid WSS selection */ | ||
258 | WLP_ASSOC_ERROR_MSG_TIME, /* Message timeout */ | ||
259 | WLP_ASSOC_ERROR_ENR_TIME, /* Enrollment session timeout */ | ||
260 | WLP_ASSOC_ERROR_PW, /* Device password invalid */ | ||
261 | WLP_ASSOC_ERROR_VER, /* Unsupported version */ | ||
262 | WLP_ASSOC_ERROR_INT, /* Internal error */ | ||
263 | WLP_ASSOC_ERROR_UNDEF, /* Undefined error */ | ||
264 | WLP_ASSOC_ERROR_NUM, /* Numeric comparison failure */ | ||
265 | WLP_ASSOC_ERROR_WAIT, /* Waiting for user input */ | ||
266 | }; | ||
267 | |||
268 | /** | ||
269 | * WLP Parameters | ||
270 | * WLP 0.99 [7.7] | ||
271 | */ | ||
272 | enum wlp_parameters { | ||
273 | WLP_PER_MSG_TIMEOUT = 15, /* Seconds to wait for response to | ||
274 | association message. */ | ||
275 | }; | ||
276 | |||
277 | /** | ||
278 | * WLP IE | ||
279 | * | ||
280 | * The WLP IE should be included in beacons by all devices. | ||
281 | * | ||
282 | * The driver can set only a few of the fields in this information element, | ||
283 | * most fields are managed by the device self. When the driver needs to set | ||
284 | * a field it will only provide values for the fields of interest, the rest | ||
285 | * will be filled with zeroes. The fields of interest are: | ||
286 | * | ||
287 | * Element ID | ||
288 | * Length | ||
289 | * Capabilities (only to include WSSID Hash list length) | ||
290 | * WSSID Hash List fields | ||
291 | * | ||
292 | * WLP 0.99 [6.7] | ||
293 | * | ||
294 | * Only the fields that will be used are detailed in this structure, rest | ||
295 | * are not detailed or marked as "notused". | ||
296 | */ | ||
297 | struct wlp_ie { | ||
298 | struct uwb_ie_hdr hdr; | ||
299 | __le16 capabilities; | ||
300 | __le16 cycle_param; | ||
301 | __le16 acw_anchor_addr; | ||
302 | u8 wssid_hash_list[]; | ||
303 | } __packed; | ||
304 | |||
305 | static inline int wlp_ie_hash_length(struct wlp_ie *ie) | ||
306 | { | ||
307 | return (le16_to_cpu(ie->capabilities) >> 12) & 0xf; | ||
308 | } | ||
309 | |||
310 | static inline void wlp_ie_set_hash_length(struct wlp_ie *ie, int hash_length) | ||
311 | { | ||
312 | u16 caps = le16_to_cpu(ie->capabilities); | ||
313 | caps = (caps & ~(0xf << 12)) | (hash_length << 12); | ||
314 | ie->capabilities = cpu_to_le16(caps); | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * WLP nonce | ||
319 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
320 | * | ||
321 | * A 128-bit random number often used (E-SNonce1, E-SNonce2, Enrollee | ||
322 | * Nonce, Registrar Nonce, R-SNonce1, R-SNonce2). It is passed to HW so | ||
323 | * it is packed. | ||
324 | */ | ||
325 | struct wlp_nonce { | ||
326 | u8 data[16]; | ||
327 | } __packed; | ||
328 | |||
329 | /** | ||
330 | * WLP UUID | ||
331 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
332 | * | ||
333 | * Universally Unique Identifier (UUID) encoded as an octet string in the | ||
334 | * order the octets are shown in string representation in RFC4122. A UUID | ||
335 | * is often used (UUID-E, UUID-R, WSSID). It is passed to HW so it is packed. | ||
336 | */ | ||
337 | struct wlp_uuid { | ||
338 | u8 data[16]; | ||
339 | } __packed; | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Primary and secondary device type attributes | ||
344 | * WLP Draft 0.99 [6.6.1.8] | ||
345 | */ | ||
346 | struct wlp_dev_type { | ||
347 | enum wlp_dev_category_id category:16; | ||
348 | u8 OUI[3]; | ||
349 | u8 OUIsubdiv; | ||
350 | __le16 subID; | ||
351 | } __packed; | ||
352 | |||
353 | /** | ||
354 | * WLP frame header | ||
355 | * WLP Draft 0.99 [6.2] | ||
356 | */ | ||
357 | struct wlp_frame_hdr { | ||
358 | __le16 mux_hdr; /* WLP_PROTOCOL_ID */ | ||
359 | enum wlp_frame_type type:8; | ||
360 | } __packed; | ||
361 | |||
362 | /** | ||
363 | * WLP attribute field header | ||
364 | * WLP Draft 0.99 [6.6.1] | ||
365 | * | ||
366 | * Header of each attribute found in an association frame | ||
367 | */ | ||
368 | struct wlp_attr_hdr { | ||
369 | __le16 type; | ||
370 | __le16 length; | ||
371 | } __packed; | ||
372 | |||
373 | /** | ||
374 | * Device information commonly used together | ||
375 | * | ||
376 | * Each of these device information elements has a specified range in which it | ||
377 | * should fit (WLP 0.99 [Table 6]). This range provided in the spec does not | ||
378 | * include the termination null '\0' character (when used in the | ||
379 | * association protocol the attribute fields are accompanied | ||
380 | * with a "length" field so the full range from the spec can be used for | ||
381 | * the value). We thus allocate an extra byte to be able to store a string | ||
382 | * of max length with a terminating '\0'. | ||
383 | */ | ||
384 | struct wlp_device_info { | ||
385 | char name[33]; | ||
386 | char model_name[33]; | ||
387 | char manufacturer[65]; | ||
388 | char model_nr[33]; | ||
389 | char serial[33]; | ||
390 | struct wlp_dev_type prim_dev_type; | ||
391 | }; | ||
392 | |||
393 | /** | ||
394 | * Macros for the WLP attributes | ||
395 | * | ||
396 | * There are quite a few attributes (total is 43). The attribute layout can be | ||
397 | * in one of three categories: one value, an array, an enum forced to 8 bits. | ||
398 | * These macros help with their definitions. | ||
399 | */ | ||
400 | #define wlp_attr(type, name) \ | ||
401 | struct wlp_attr_##name { \ | ||
402 | struct wlp_attr_hdr hdr; \ | ||
403 | type name; \ | ||
404 | } __packed; | ||
405 | |||
406 | #define wlp_attr_array(type, name) \ | ||
407 | struct wlp_attr_##name { \ | ||
408 | struct wlp_attr_hdr hdr; \ | ||
409 | type name[]; \ | ||
410 | } __packed; | ||
411 | |||
412 | /** | ||
413 | * WLP association attribute fields | ||
414 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
415 | * | ||
416 | * Attributes appear in same order as the Table in the spec | ||
417 | * FIXME Does not define all attributes yet | ||
418 | */ | ||
419 | |||
420 | /* Device name: Friendly name of sending device */ | ||
421 | wlp_attr_array(u8, dev_name) | ||
422 | |||
423 | /* Enrollee Nonce: Random number generated by enrollee for an enrollment | ||
424 | * session */ | ||
425 | wlp_attr(struct wlp_nonce, enonce) | ||
426 | |||
427 | /* Manufacturer name: Name of manufacturer of the sending device */ | ||
428 | wlp_attr_array(u8, manufacturer) | ||
429 | |||
430 | /* WLP Message Type */ | ||
431 | wlp_attr(u8, msg_type) | ||
432 | |||
433 | /* WLP Model name: Model name of sending device */ | ||
434 | wlp_attr_array(u8, model_name) | ||
435 | |||
436 | /* WLP Model number: Model number of sending device */ | ||
437 | wlp_attr_array(u8, model_nr) | ||
438 | |||
439 | /* Registrar Nonce: Random number generated by registrar for an enrollment | ||
440 | * session */ | ||
441 | wlp_attr(struct wlp_nonce, rnonce) | ||
442 | |||
443 | /* Serial number of device */ | ||
444 | wlp_attr_array(u8, serial) | ||
445 | |||
446 | /* UUID of enrollee */ | ||
447 | wlp_attr(struct wlp_uuid, uuid_e) | ||
448 | |||
449 | /* UUID of registrar */ | ||
450 | wlp_attr(struct wlp_uuid, uuid_r) | ||
451 | |||
452 | /* WLP Primary device type */ | ||
453 | wlp_attr(struct wlp_dev_type, prim_dev_type) | ||
454 | |||
455 | /* WLP Secondary device type */ | ||
456 | wlp_attr(struct wlp_dev_type, sec_dev_type) | ||
457 | |||
458 | /* WLP protocol version */ | ||
459 | wlp_attr(u8, version) | ||
460 | |||
461 | /* WLP service set identifier */ | ||
462 | wlp_attr(struct wlp_uuid, wssid) | ||
463 | |||
464 | /* WLP WSS name */ | ||
465 | wlp_attr_array(u8, wss_name) | ||
466 | |||
467 | /* WLP WSS Secure Status */ | ||
468 | wlp_attr(u8, wss_sec_status) | ||
469 | |||
470 | /* WSS Broadcast Address */ | ||
471 | wlp_attr(struct uwb_mac_addr, wss_bcast) | ||
472 | |||
473 | /* WLP Accepting Enrollment */ | ||
474 | wlp_attr(u8, accept_enrl) | ||
475 | |||
476 | /** | ||
477 | * WSS information attributes | ||
478 | * WLP Draft 0.99 [6.6.3 Table 15] | ||
479 | */ | ||
480 | struct wlp_wss_info { | ||
481 | struct wlp_attr_wssid wssid; | ||
482 | struct wlp_attr_wss_name name; | ||
483 | struct wlp_attr_accept_enrl accept; | ||
484 | struct wlp_attr_wss_sec_status sec_stat; | ||
485 | struct wlp_attr_wss_bcast bcast; | ||
486 | } __packed; | ||
487 | |||
488 | /* WLP WSS Information */ | ||
489 | wlp_attr_array(struct wlp_wss_info, wss_info) | ||
490 | |||
491 | /* WLP WSS Selection method */ | ||
492 | wlp_attr(u8, wss_sel_mthd) | ||
493 | |||
494 | /* WLP WSS tag */ | ||
495 | wlp_attr(u8, wss_tag) | ||
496 | |||
497 | /* WSS Virtual Address */ | ||
498 | wlp_attr(struct uwb_mac_addr, wss_virt) | ||
499 | |||
500 | /* WLP association error */ | ||
501 | wlp_attr(u8, wlp_assc_err) | ||
502 | |||
503 | /** | ||
504 | * WLP standard and abbreviated frames | ||
505 | * | ||
506 | * WLP Draft 0.99 [6.3] and [6.4] | ||
507 | * | ||
508 | * The difference between the WLP standard frame and the WLP | ||
509 | * abbreviated frame is that the standard frame includes the src | ||
510 | * and dest addresses from the Ethernet header, the abbreviated frame does | ||
511 | * not. | ||
512 | * The src/dest (as well as the type/length and client data) are already | ||
513 | * defined as part of the Ethernet header, we do not do this here. | ||
514 | * From this perspective the standard and abbreviated frames appear the | ||
515 | * same - they will be treated differently though. | ||
516 | * | ||
517 | * The size of this header is also captured in WLP_DATA_HLEN to enable | ||
518 | * interfaces to prepare their headroom. | ||
519 | */ | ||
520 | struct wlp_frame_std_abbrv_hdr { | ||
521 | struct wlp_frame_hdr hdr; | ||
522 | u8 tag; | ||
523 | } __packed; | ||
524 | |||
525 | /** | ||
526 | * WLP association frames | ||
527 | * | ||
528 | * WLP Draft 0.99 [6.6] | ||
529 | */ | ||
530 | struct wlp_frame_assoc { | ||
531 | struct wlp_frame_hdr hdr; | ||
532 | enum wlp_assoc_type type:8; | ||
533 | struct wlp_attr_version version; | ||
534 | struct wlp_attr_msg_type msg_type; | ||
535 | u8 attr[]; | ||
536 | } __packed; | ||
537 | |||
538 | /* Ethernet to dev address mapping */ | ||
539 | struct wlp_eda { | ||
540 | spinlock_t lock; | ||
541 | struct list_head cache; /* Eth<->Dev Addr cache */ | ||
542 | }; | ||
543 | |||
544 | /** | ||
545 | * WSS information temporary storage | ||
546 | * | ||
547 | * This information is only stored temporarily during discovery. It should | ||
548 | * not be stored unless the device is enrolled in the advertised WSS. This | ||
549 | * is done mainly because we follow the letter of the spec in this regard. | ||
550 | * See WLP 0.99 [7.2.3]. | ||
551 | * When the device does become enrolled in a WSS the WSS information will | ||
552 | * be stored as part of the more comprehensive struct wlp_wss. | ||
553 | */ | ||
554 | struct wlp_wss_tmp_info { | ||
555 | char name[WLP_WSS_NAME_SIZE]; | ||
556 | u8 accept_enroll; | ||
557 | u8 sec_status; | ||
558 | struct uwb_mac_addr bcast; | ||
559 | }; | ||
560 | |||
561 | struct wlp_wssid_e { | ||
562 | struct list_head node; | ||
563 | struct wlp_uuid wssid; | ||
564 | struct wlp_wss_tmp_info *info; | ||
565 | }; | ||
566 | |||
567 | /** | ||
568 | * A cache entry of WLP neighborhood | ||
569 | * | ||
570 | * @node: head of list is wlp->neighbors | ||
571 | * @wssid: list of wssids of this neighbor, element is wlp_wssid_e | ||
572 | * @info: temporary storage for information learned during discovery. This | ||
573 | * storage is used together with the wssid_e temporary storage | ||
574 | * during discovery. | ||
575 | */ | ||
576 | struct wlp_neighbor_e { | ||
577 | struct list_head node; | ||
578 | struct wlp_uuid uuid; | ||
579 | struct uwb_dev *uwb_dev; | ||
580 | struct list_head wssid; /* Elements are wlp_wssid_e */ | ||
581 | struct wlp_device_info *info; | ||
582 | }; | ||
583 | |||
584 | struct wlp; | ||
585 | /** | ||
586 | * Information for an association session in progress. | ||
587 | * | ||
588 | * @exp_message: The type of the expected message. Both this message and a | ||
589 | * F0 message (which can be sent in response to any | ||
590 | * association frame) will be accepted as a valid message for | ||
591 | * this session. | ||
592 | * @cb: The function that will be called upon receipt of this | ||
593 | * message. | ||
594 | * @cb_priv: Private data of callback | ||
595 | * @data: Data used in association process (always a sk_buff?) | ||
596 | * @neighbor: Address of neighbor with which association session is in | ||
597 | * progress. | ||
598 | */ | ||
599 | struct wlp_session { | ||
600 | enum wlp_assoc_type exp_message; | ||
601 | void (*cb)(struct wlp *); | ||
602 | void *cb_priv; | ||
603 | void *data; | ||
604 | struct uwb_dev_addr neighbor_addr; | ||
605 | }; | ||
606 | |||
607 | /** | ||
608 | * WLP Service Set | ||
609 | * | ||
610 | * @mutex: used to protect entire WSS structure. | ||
611 | * | ||
612 | * @name: The WSS name is set to 65 bytes, 1 byte larger than the maximum | ||
613 | * allowed by the WLP spec. This is to have a null terminated string | ||
614 | * for display to the user. A maximum of 64 bytes will still be used | ||
615 | * when placing the WSS name field in association frames. | ||
616 | * | ||
617 | * @accept_enroll: Accepting enrollment: Set to one if registrar is | ||
618 | * accepting enrollment in WSS, or zero otherwise. | ||
619 | * | ||
620 | * Global and local information for each WSS in which we are enrolled. | ||
621 | * WLP 0.99 Section 7.2.1 and Section 7.2.2 | ||
622 | */ | ||
623 | struct wlp_wss { | ||
624 | struct mutex mutex; | ||
625 | struct kobject kobj; | ||
626 | /* Global properties. */ | ||
627 | struct wlp_uuid wssid; | ||
628 | u8 hash; | ||
629 | char name[WLP_WSS_NAME_SIZE]; | ||
630 | struct uwb_mac_addr bcast; | ||
631 | u8 secure_status:1; | ||
632 | u8 master_key[16]; | ||
633 | /* Local properties. */ | ||
634 | u8 tag; | ||
635 | struct uwb_mac_addr virtual_addr; | ||
636 | /* Extra */ | ||
637 | u8 accept_enroll:1; | ||
638 | enum wlp_wss_state state; | ||
639 | }; | ||
640 | |||
641 | /** | ||
642 | * WLP main structure | ||
643 | * @mutex: protect changes to WLP structure. We only allow changes to the | ||
644 | * uuid, so currently this mutex only protects this field. | ||
645 | */ | ||
646 | struct wlp { | ||
647 | struct mutex mutex; | ||
648 | struct uwb_rc *rc; /* UWB radio controller */ | ||
649 | struct net_device *ndev; | ||
650 | struct uwb_pal pal; | ||
651 | struct wlp_eda eda; | ||
652 | struct wlp_uuid uuid; | ||
653 | struct wlp_session *session; | ||
654 | struct wlp_wss wss; | ||
655 | struct mutex nbmutex; /* Neighbor mutex protects neighbors list */ | ||
656 | struct list_head neighbors; /* Elements are wlp_neighbor_e */ | ||
657 | struct uwb_notifs_handler uwb_notifs_handler; | ||
658 | struct wlp_device_info *dev_info; | ||
659 | void (*fill_device_info)(struct wlp *wlp, struct wlp_device_info *info); | ||
660 | int (*xmit_frame)(struct wlp *, struct sk_buff *, | ||
661 | struct uwb_dev_addr *); | ||
662 | void (*stop_queue)(struct wlp *); | ||
663 | void (*start_queue)(struct wlp *); | ||
664 | }; | ||
665 | |||
666 | /* sysfs */ | ||
667 | |||
668 | |||
669 | struct wlp_wss_attribute { | ||
670 | struct attribute attr; | ||
671 | ssize_t (*show)(struct wlp_wss *wss, char *buf); | ||
672 | ssize_t (*store)(struct wlp_wss *wss, const char *buf, size_t count); | ||
673 | }; | ||
674 | |||
675 | #define WSS_ATTR(_name, _mode, _show, _store) \ | ||
676 | static struct wlp_wss_attribute wss_attr_##_name = __ATTR(_name, _mode, \ | ||
677 | _show, _store) | ||
678 | |||
679 | extern int wlp_setup(struct wlp *, struct uwb_rc *, struct net_device *ndev); | ||
680 | extern void wlp_remove(struct wlp *); | ||
681 | extern ssize_t wlp_neighborhood_show(struct wlp *, char *); | ||
682 | extern int wlp_wss_setup(struct net_device *, struct wlp_wss *); | ||
683 | extern void wlp_wss_remove(struct wlp_wss *); | ||
684 | extern ssize_t wlp_wss_activate_show(struct wlp_wss *, char *); | ||
685 | extern ssize_t wlp_wss_activate_store(struct wlp_wss *, const char *, size_t); | ||
686 | extern ssize_t wlp_eda_show(struct wlp *, char *); | ||
687 | extern ssize_t wlp_eda_store(struct wlp *, const char *, size_t); | ||
688 | extern ssize_t wlp_uuid_show(struct wlp *, char *); | ||
689 | extern ssize_t wlp_uuid_store(struct wlp *, const char *, size_t); | ||
690 | extern ssize_t wlp_dev_name_show(struct wlp *, char *); | ||
691 | extern ssize_t wlp_dev_name_store(struct wlp *, const char *, size_t); | ||
692 | extern ssize_t wlp_dev_manufacturer_show(struct wlp *, char *); | ||
693 | extern ssize_t wlp_dev_manufacturer_store(struct wlp *, const char *, size_t); | ||
694 | extern ssize_t wlp_dev_model_name_show(struct wlp *, char *); | ||
695 | extern ssize_t wlp_dev_model_name_store(struct wlp *, const char *, size_t); | ||
696 | extern ssize_t wlp_dev_model_nr_show(struct wlp *, char *); | ||
697 | extern ssize_t wlp_dev_model_nr_store(struct wlp *, const char *, size_t); | ||
698 | extern ssize_t wlp_dev_serial_show(struct wlp *, char *); | ||
699 | extern ssize_t wlp_dev_serial_store(struct wlp *, const char *, size_t); | ||
700 | extern ssize_t wlp_dev_prim_category_show(struct wlp *, char *); | ||
701 | extern ssize_t wlp_dev_prim_category_store(struct wlp *, const char *, | ||
702 | size_t); | ||
703 | extern ssize_t wlp_dev_prim_OUI_show(struct wlp *, char *); | ||
704 | extern ssize_t wlp_dev_prim_OUI_store(struct wlp *, const char *, size_t); | ||
705 | extern ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *, char *); | ||
706 | extern ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *, const char *, | ||
707 | size_t); | ||
708 | extern ssize_t wlp_dev_prim_subcat_show(struct wlp *, char *); | ||
709 | extern ssize_t wlp_dev_prim_subcat_store(struct wlp *, const char *, | ||
710 | size_t); | ||
711 | extern int wlp_receive_frame(struct device *, struct wlp *, struct sk_buff *, | ||
712 | struct uwb_dev_addr *); | ||
713 | extern int wlp_prepare_tx_frame(struct device *, struct wlp *, | ||
714 | struct sk_buff *, struct uwb_dev_addr *); | ||
715 | void wlp_reset_all(struct wlp *wlp); | ||
716 | |||
717 | /** | ||
718 | * Initialize WSS | ||
719 | */ | ||
720 | static inline | ||
721 | void wlp_wss_init(struct wlp_wss *wss) | ||
722 | { | ||
723 | mutex_init(&wss->mutex); | ||
724 | } | ||
725 | |||
726 | static inline | ||
727 | void wlp_init(struct wlp *wlp) | ||
728 | { | ||
729 | INIT_LIST_HEAD(&wlp->neighbors); | ||
730 | mutex_init(&wlp->mutex); | ||
731 | mutex_init(&wlp->nbmutex); | ||
732 | wlp_wss_init(&wlp->wss); | ||
733 | } | ||
734 | |||
735 | |||
736 | #endif /* #ifndef __LINUX__WLP_H_ */ | ||