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