1 |
|
|
/* $OpenBSD: iapp.c,v 1.19 2015/01/16 06:40:17 deraadt Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/ioctl.h> |
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
#include <sys/time.h> |
23 |
|
|
#include <sys/uio.h> |
24 |
|
|
|
25 |
|
|
#include <net/if.h> |
26 |
|
|
#include <net/if_dl.h> |
27 |
|
|
#include <net/if_media.h> |
28 |
|
|
#include <net/if_arp.h> |
29 |
|
|
#include <net/if_llc.h> |
30 |
|
|
#include <net/bpf.h> |
31 |
|
|
|
32 |
|
|
#include <netinet/in.h> |
33 |
|
|
#include <netinet/if_ether.h> |
34 |
|
|
#include <arpa/inet.h> |
35 |
|
|
|
36 |
|
|
#include <fcntl.h> |
37 |
|
|
#include <stdlib.h> |
38 |
|
|
#include <string.h> |
39 |
|
|
#include <unistd.h> |
40 |
|
|
#include <limits.h> |
41 |
|
|
|
42 |
|
|
#include "hostapd.h" |
43 |
|
|
#include "iapp.h" |
44 |
|
|
|
45 |
|
|
void |
46 |
|
|
hostapd_iapp_init(struct hostapd_config *cfg) |
47 |
|
|
{ |
48 |
|
|
struct hostapd_apme *apme; |
49 |
|
|
struct hostapd_iapp *iapp = &cfg->c_iapp; |
50 |
|
|
|
51 |
|
|
if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) |
52 |
|
|
return; |
53 |
|
|
|
54 |
|
|
TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { |
55 |
|
|
/* Get Host AP's BSSID */ |
56 |
|
|
hostapd_priv_apme_bssid(apme); |
57 |
|
|
hostapd_log(HOSTAPD_LOG, |
58 |
|
|
"%s/%s: attached Host AP interface with BSSID %s", |
59 |
|
|
apme->a_iface, iapp->i_iface, |
60 |
|
|
etheraddr_string(apme->a_bssid)); |
61 |
|
|
|
62 |
|
|
/* Deauthenticate all stations on startup */ |
63 |
|
|
(void)hostapd_apme_deauth(apme); |
64 |
|
|
} |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
void |
68 |
|
|
hostapd_iapp_term(struct hostapd_config *cfg) |
69 |
|
|
{ |
70 |
|
|
struct hostapd_apme *apme; |
71 |
|
|
struct hostapd_iapp *iapp = &cfg->c_iapp; |
72 |
|
|
|
73 |
|
|
if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) |
74 |
|
|
return; |
75 |
|
|
|
76 |
|
|
TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { |
77 |
|
|
hostapd_log(HOSTAPD_LOG_VERBOSE, |
78 |
|
|
"%s/%s: detaching from Host AP", |
79 |
|
|
apme->a_iface, iapp->i_iface); |
80 |
|
|
} |
81 |
|
|
} |
82 |
|
|
|
83 |
|
|
int |
84 |
|
|
hostapd_iapp_add_notify(struct hostapd_apme *apme, struct hostapd_node *node) |
85 |
|
|
{ |
86 |
|
|
struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; |
87 |
|
|
struct hostapd_iapp *iapp = &cfg->c_iapp; |
88 |
|
|
struct sockaddr_in *addr; |
89 |
|
|
struct { |
90 |
|
|
struct ieee80211_iapp_frame hdr; |
91 |
|
|
struct ieee80211_iapp_add_notify add; |
92 |
|
|
} __packed frame; |
93 |
|
|
|
94 |
|
|
if ((iapp->i_flags & HOSTAPD_IAPP_F_ADD_NOTIFY) == 0) |
95 |
|
|
return (0); |
96 |
|
|
|
97 |
|
|
/* |
98 |
|
|
* Send an ADD.notify message to other access points to notify |
99 |
|
|
* about a new association on our Host AP. |
100 |
|
|
*/ |
101 |
|
|
bzero(&frame, sizeof(frame)); |
102 |
|
|
|
103 |
|
|
frame.hdr.i_version = IEEE80211_IAPP_VERSION; |
104 |
|
|
frame.hdr.i_command = IEEE80211_IAPP_FRAME_ADD_NOTIFY; |
105 |
|
|
frame.hdr.i_identifier = htons(iapp->i_cnt++); |
106 |
|
|
frame.hdr.i_length = sizeof(struct ieee80211_iapp_add_notify); |
107 |
|
|
|
108 |
|
|
frame.add.a_length = IEEE80211_ADDR_LEN; |
109 |
|
|
frame.add.a_seqnum = htons(node->ni_rxseq); |
110 |
|
|
bcopy(node->ni_macaddr, frame.add.a_macaddr, IEEE80211_ADDR_LEN); |
111 |
|
|
|
112 |
|
|
if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) |
113 |
|
|
addr = &iapp->i_broadcast; |
114 |
|
|
else |
115 |
|
|
addr = &iapp->i_multicast; |
116 |
|
|
|
117 |
|
|
if (sendto(iapp->i_udp, &frame, sizeof(frame), |
118 |
|
|
0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) { |
119 |
|
|
hostapd_log(HOSTAPD_LOG, |
120 |
|
|
"%s: failed to send ADD notification: %s", |
121 |
|
|
iapp->i_iface, strerror(errno)); |
122 |
|
|
return (errno); |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
hostapd_log(HOSTAPD_LOG, "%s/%s: sent ADD notification for %s", |
126 |
|
|
apme->a_iface, iapp->i_iface, |
127 |
|
|
etheraddr_string(frame.add.a_macaddr)); |
128 |
|
|
|
129 |
|
|
/* Send a LLC XID frame, see llc.c for details */ |
130 |
|
|
return (hostapd_priv_llc_xid(cfg, node)); |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
int |
134 |
|
|
hostapd_iapp_radiotap(struct hostapd_apme *apme, u_int8_t *buf, |
135 |
|
|
const u_int len) |
136 |
|
|
{ |
137 |
|
|
struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; |
138 |
|
|
struct hostapd_iapp *iapp = &cfg->c_iapp; |
139 |
|
|
struct sockaddr_in *addr; |
140 |
|
|
struct ieee80211_iapp_frame hdr; |
141 |
|
|
struct msghdr msg; |
142 |
|
|
struct iovec iov[2]; |
143 |
|
|
|
144 |
|
|
/* |
145 |
|
|
* Send an HOSTAPD.pcap/radiotap message to other access points |
146 |
|
|
* with an appended network dump. This is an hostapd extension to |
147 |
|
|
* IAPP. |
148 |
|
|
*/ |
149 |
|
|
bzero(&hdr, sizeof(hdr)); |
150 |
|
|
|
151 |
|
|
hdr.i_version = IEEE80211_IAPP_VERSION; |
152 |
|
|
if (cfg->c_apme_dlt == DLT_IEEE802_11_RADIO) |
153 |
|
|
hdr.i_command = IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP; |
154 |
|
|
else if (cfg->c_apme_dlt == DLT_IEEE802_11) |
155 |
|
|
hdr.i_command = IEEE80211_IAPP_FRAME_HOSTAPD_PCAP; |
156 |
|
|
else |
157 |
|
|
return (EINVAL); |
158 |
|
|
hdr.i_identifier = htons(iapp->i_cnt++); |
159 |
|
|
hdr.i_length = len; |
160 |
|
|
|
161 |
|
|
if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) |
162 |
|
|
addr = &iapp->i_broadcast; |
163 |
|
|
else |
164 |
|
|
addr = &iapp->i_multicast; |
165 |
|
|
|
166 |
|
|
iov[0].iov_base = &hdr; |
167 |
|
|
iov[0].iov_len = sizeof(hdr); |
168 |
|
|
iov[1].iov_base = buf; |
169 |
|
|
iov[1].iov_len = len; |
170 |
|
|
msg.msg_name = (caddr_t)addr; |
171 |
|
|
msg.msg_namelen = sizeof(struct sockaddr_in); |
172 |
|
|
msg.msg_iov = iov; |
173 |
|
|
msg.msg_iovlen = 2; |
174 |
|
|
msg.msg_control = 0; |
175 |
|
|
msg.msg_controllen = 0; |
176 |
|
|
msg.msg_flags = 0; |
177 |
|
|
|
178 |
|
|
if (sendmsg(iapp->i_udp, &msg, 0) == -1) { |
179 |
|
|
hostapd_log(HOSTAPD_LOG, |
180 |
|
|
"%s: failed to send HOSTAPD %s: %s", |
181 |
|
|
iapp->i_iface, cfg->c_apme_dlt == |
182 |
|
|
DLT_IEEE802_11_RADIO ? "radiotap" : "pcap", |
183 |
|
|
strerror(errno)); |
184 |
|
|
return (errno); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
return (0); |
188 |
|
|
} |
189 |
|
|
|
190 |
|
|
void |
191 |
|
|
hostapd_iapp_input(int fd, short sig, void *arg) |
192 |
|
|
{ |
193 |
|
|
struct hostapd_config *cfg = (struct hostapd_config *)arg; |
194 |
|
|
struct hostapd_iapp *iapp = &cfg->c_iapp; |
195 |
|
|
struct hostapd_apme *apme; |
196 |
|
|
struct sockaddr_in addr; |
197 |
|
|
socklen_t addr_len; |
198 |
|
|
ssize_t len; |
199 |
|
|
u_int8_t buf[IAPP_MAXSIZE]; |
200 |
|
|
struct hostapd_node node; |
201 |
|
|
struct ieee80211_iapp_recv { |
202 |
|
|
struct ieee80211_iapp_frame hdr; |
203 |
|
|
union { |
204 |
|
|
struct ieee80211_iapp_add_notify add; |
205 |
|
|
u_int8_t buf[1]; |
206 |
|
|
} u; |
207 |
|
|
} __packed *frame; |
208 |
|
|
u_int dlt; |
209 |
|
|
int ret = 0; |
210 |
|
|
|
211 |
|
|
/* Ignore invalid signals */ |
212 |
|
|
if (sig != EV_READ) |
213 |
|
|
return; |
214 |
|
|
|
215 |
|
|
/* |
216 |
|
|
* Listen to possible messages from other IAPP |
217 |
|
|
*/ |
218 |
|
|
bzero(buf, sizeof(buf)); |
219 |
|
|
|
220 |
|
|
if ((len = recvfrom(fd, buf, sizeof(buf), 0, |
221 |
|
|
(struct sockaddr*)&addr, &addr_len)) < 1) |
222 |
|
|
return; |
223 |
|
|
|
224 |
|
|
if (bcmp(&iapp->i_addr.sin_addr, &addr.sin_addr, |
225 |
|
|
sizeof(addr.sin_addr)) == 0) |
226 |
|
|
return; |
227 |
|
|
|
228 |
|
|
frame = (struct ieee80211_iapp_recv*)buf; |
229 |
|
|
|
230 |
|
|
/* Validate the IAPP version */ |
231 |
|
|
if (len < (ssize_t)sizeof(struct ieee80211_iapp_frame) || |
232 |
|
|
frame->hdr.i_version != IEEE80211_IAPP_VERSION || |
233 |
|
|
addr_len < sizeof(struct sockaddr_in)) |
234 |
|
|
return; |
235 |
|
|
|
236 |
|
|
cfg->c_stats.cn_rx_iapp++; |
237 |
|
|
|
238 |
|
|
/* |
239 |
|
|
* Process the IAPP frame |
240 |
|
|
*/ |
241 |
|
|
switch (frame->hdr.i_command) { |
242 |
|
|
case IEEE80211_IAPP_FRAME_ADD_NOTIFY: |
243 |
|
|
/* Short frame */ |
244 |
|
|
if (len < (ssize_t)(sizeof(struct ieee80211_iapp_frame) + |
245 |
|
|
sizeof(struct ieee80211_iapp_add_notify))) |
246 |
|
|
return; |
247 |
|
|
|
248 |
|
|
/* Don't support non-48bit MAC addresses, yet */ |
249 |
|
|
if (frame->u.add.a_length != IEEE80211_ADDR_LEN) |
250 |
|
|
return; |
251 |
|
|
|
252 |
|
|
node.ni_rxseq = frame->u.add.a_seqnum; |
253 |
|
|
bcopy(frame->u.add.a_macaddr, node.ni_macaddr, |
254 |
|
|
IEEE80211_ADDR_LEN); |
255 |
|
|
|
256 |
|
|
/* |
257 |
|
|
* Try to remove a node from our Host AP and to free |
258 |
|
|
* any allocated resources. Otherwise the received |
259 |
|
|
* ADD.notify message will be ignored. |
260 |
|
|
*/ |
261 |
|
|
if (iapp->i_flags & HOSTAPD_IAPP_F_ADD && |
262 |
|
|
cfg->c_flags & HOSTAPD_CFG_F_APME) { |
263 |
|
|
TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { |
264 |
|
|
if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) |
265 |
|
|
(void)hostapd_roaming_del(apme, &node); |
266 |
|
|
if (iapp->i_flags & HOSTAPD_IAPP_F_ADD_NOTIFY && |
267 |
|
|
(ret = hostapd_apme_delnode(apme, |
268 |
|
|
&node)) == 0) |
269 |
|
|
cfg->c_stats.cn_tx_apme++; |
270 |
|
|
} |
271 |
|
|
} else |
272 |
|
|
ret = 0; |
273 |
|
|
|
274 |
|
|
hostapd_log(iapp->i_flags & HOSTAPD_IAPP_F_ADD ? |
275 |
|
|
HOSTAPD_LOG : HOSTAPD_LOG_VERBOSE, |
276 |
|
|
"%s: %s ADD notification for %s at %s", |
277 |
|
|
iapp->i_iface, ret == 0 ? |
278 |
|
|
"received" : "ignored", |
279 |
|
|
etheraddr_string(node.ni_macaddr), |
280 |
|
|
inet_ntoa(addr.sin_addr)); |
281 |
|
|
break; |
282 |
|
|
|
283 |
|
|
case IEEE80211_IAPP_FRAME_HOSTAPD_PCAP: |
284 |
|
|
case IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP: |
285 |
|
|
if ((iapp->i_flags & HOSTAPD_IAPP_F_RADIOTAP) == 0) |
286 |
|
|
return; |
287 |
|
|
|
288 |
|
|
/* Short frame */ |
289 |
|
|
if (len <= (ssize_t)sizeof(struct ieee80211_iapp_frame) || |
290 |
|
|
frame->hdr.i_length < sizeof(struct ieee80211_frame)) |
291 |
|
|
return; |
292 |
|
|
|
293 |
|
|
dlt = frame->hdr.i_command == |
294 |
|
|
IEEE80211_IAPP_FRAME_HOSTAPD_PCAP ? |
295 |
|
|
DLT_IEEE802_11 : DLT_IEEE802_11_RADIO; |
296 |
|
|
|
297 |
|
|
hostapd_print_ieee80211(dlt, 1, (u_int8_t *)frame->u.buf, |
298 |
|
|
len - sizeof(struct ieee80211_iapp_frame)); |
299 |
|
|
return; |
300 |
|
|
|
301 |
|
|
case IEEE80211_IAPP_FRAME_MOVE_NOTIFY: |
302 |
|
|
case IEEE80211_IAPP_FRAME_MOVE_RESPONSE: |
303 |
|
|
case IEEE80211_IAPP_FRAME_SEND_SECURITY_BLOCK: |
304 |
|
|
case IEEE80211_IAPP_FRAME_ACK_SECURITY_BLOCK: |
305 |
|
|
case IEEE80211_IAPP_FRAME_CACHE_NOTIFY: |
306 |
|
|
case IEEE80211_IAPP_FRAME_CACHE_RESPONSE: |
307 |
|
|
|
308 |
|
|
/* |
309 |
|
|
* XXX TODO |
310 |
|
|
*/ |
311 |
|
|
|
312 |
|
|
hostapd_log(HOSTAPD_LOG_VERBOSE, |
313 |
|
|
"%s: received unsupported IAPP message %d", |
314 |
|
|
iapp->i_iface, frame->hdr.i_command); |
315 |
|
|
return; |
316 |
|
|
|
317 |
|
|
default: |
318 |
|
|
return; |
319 |
|
|
} |
320 |
|
|
} |