1214501Srpaulo/*
2214501Srpaulo * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
3214501Srpaulo * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo *
8214501Srpaulo * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
9214501Srpaulo * and IEEE has withdrawn it. In other words, it is likely better to look at
10214501Srpaulo * using some other mechanism for AP-to-AP communication than extending the
11214501Srpaulo * implementation here.
12214501Srpaulo */
13214501Srpaulo
14214501Srpaulo/* TODO:
15214501Srpaulo * Level 1: no administrative or security support
16214501Srpaulo *	(e.g., static BSSID to IP address mapping in each AP)
17214501Srpaulo * Level 2: support for dynamic mapping of BSSID to IP address
18214501Srpaulo * Level 3: support for encryption and authentication of IAPP messages
19214501Srpaulo * - add support for MOVE-notify and MOVE-response (this requires support for
20214501Srpaulo *   finding out IP address for previous AP using RADIUS)
21214501Srpaulo * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
22214501Srpaulo *   reassociation to another AP
23214501Srpaulo * - implement counters etc. for IAPP MIB
24214501Srpaulo * - verify endianness of fields in IAPP messages; are they big-endian as
25214501Srpaulo *   used here?
26214501Srpaulo * - RADIUS connection for AP registration and BSSID to IP address mapping
27214501Srpaulo * - TCP connection for IAPP MOVE, CACHE
28214501Srpaulo * - broadcast ESP for IAPP ADD-notify
29214501Srpaulo * - ESP for IAPP MOVE messages
30214501Srpaulo * - security block sending/processing
31214501Srpaulo * - IEEE 802.11 context transfer
32214501Srpaulo */
33214501Srpaulo
34214501Srpaulo#include "utils/includes.h"
35214501Srpaulo#include <net/if.h>
36214501Srpaulo#include <sys/ioctl.h>
37214501Srpaulo#ifdef USE_KERNEL_HEADERS
38214501Srpaulo#include <linux/if_packet.h>
39214501Srpaulo#else /* USE_KERNEL_HEADERS */
40214501Srpaulo#include <netpacket/packet.h>
41214501Srpaulo#endif /* USE_KERNEL_HEADERS */
42214501Srpaulo
43214501Srpaulo#include "utils/common.h"
44214501Srpaulo#include "utils/eloop.h"
45214501Srpaulo#include "common/ieee802_11_defs.h"
46214501Srpaulo#include "hostapd.h"
47214501Srpaulo#include "ap_config.h"
48214501Srpaulo#include "ieee802_11.h"
49214501Srpaulo#include "sta_info.h"
50214501Srpaulo#include "iapp.h"
51214501Srpaulo
52214501Srpaulo
53214501Srpaulo#define IAPP_MULTICAST "224.0.1.178"
54214501Srpaulo#define IAPP_UDP_PORT 3517
55214501Srpaulo#define IAPP_TCP_PORT 3517
56214501Srpaulo
57214501Srpaulostruct iapp_hdr {
58214501Srpaulo	u8 version;
59214501Srpaulo	u8 command;
60214501Srpaulo	be16 identifier;
61214501Srpaulo	be16 length;
62214501Srpaulo	/* followed by length-6 octets of data */
63214501Srpaulo} __attribute__ ((packed));
64214501Srpaulo
65214501Srpaulo#define IAPP_VERSION 0
66214501Srpaulo
67214501Srpauloenum IAPP_COMMAND {
68214501Srpaulo	IAPP_CMD_ADD_notify = 0,
69214501Srpaulo	IAPP_CMD_MOVE_notify = 1,
70214501Srpaulo	IAPP_CMD_MOVE_response = 2,
71214501Srpaulo	IAPP_CMD_Send_Security_Block = 3,
72214501Srpaulo	IAPP_CMD_ACK_Security_Block = 4,
73214501Srpaulo	IAPP_CMD_CACHE_notify = 5,
74214501Srpaulo	IAPP_CMD_CACHE_response = 6,
75214501Srpaulo};
76214501Srpaulo
77214501Srpaulo
78214501Srpaulo/* ADD-notify - multicast UDP on the local LAN */
79214501Srpaulostruct iapp_add_notify {
80214501Srpaulo	u8 addr_len; /* ETH_ALEN */
81214501Srpaulo	u8 reserved;
82214501Srpaulo	u8 mac_addr[ETH_ALEN];
83214501Srpaulo	be16 seq_num;
84214501Srpaulo} __attribute__ ((packed));
85214501Srpaulo
86214501Srpaulo
87214501Srpaulo/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
88214501Srpaulostruct iapp_layer2_update {
89214501Srpaulo	u8 da[ETH_ALEN]; /* broadcast */
90214501Srpaulo	u8 sa[ETH_ALEN]; /* STA addr */
91214501Srpaulo	be16 len; /* 6 */
92214501Srpaulo	u8 dsap; /* null DSAP address */
93214501Srpaulo	u8 ssap; /* null SSAP address, CR=Response */
94214501Srpaulo	u8 control;
95214501Srpaulo	u8 xid_info[3];
96214501Srpaulo} __attribute__ ((packed));
97214501Srpaulo
98214501Srpaulo
99214501Srpaulo/* MOVE-notify - unicast TCP */
100214501Srpaulostruct iapp_move_notify {
101214501Srpaulo	u8 addr_len; /* ETH_ALEN */
102214501Srpaulo	u8 reserved;
103214501Srpaulo	u8 mac_addr[ETH_ALEN];
104214501Srpaulo	u16 seq_num;
105214501Srpaulo	u16 ctx_block_len;
106214501Srpaulo	/* followed by ctx_block_len bytes */
107214501Srpaulo} __attribute__ ((packed));
108214501Srpaulo
109214501Srpaulo
110214501Srpaulo/* MOVE-response - unicast TCP */
111214501Srpaulostruct iapp_move_response {
112214501Srpaulo	u8 addr_len; /* ETH_ALEN */
113214501Srpaulo	u8 status;
114214501Srpaulo	u8 mac_addr[ETH_ALEN];
115214501Srpaulo	u16 seq_num;
116214501Srpaulo	u16 ctx_block_len;
117214501Srpaulo	/* followed by ctx_block_len bytes */
118214501Srpaulo} __attribute__ ((packed));
119214501Srpaulo
120214501Srpauloenum {
121214501Srpaulo	IAPP_MOVE_SUCCESSFUL = 0,
122214501Srpaulo	IAPP_MOVE_DENIED = 1,
123214501Srpaulo	IAPP_MOVE_STALE_MOVE = 2,
124214501Srpaulo};
125214501Srpaulo
126214501Srpaulo
127214501Srpaulo/* CACHE-notify */
128214501Srpaulostruct iapp_cache_notify {
129214501Srpaulo	u8 addr_len; /* ETH_ALEN */
130214501Srpaulo	u8 reserved;
131214501Srpaulo	u8 mac_addr[ETH_ALEN];
132214501Srpaulo	u16 seq_num;
133214501Srpaulo	u8 current_ap[ETH_ALEN];
134214501Srpaulo	u16 ctx_block_len;
135214501Srpaulo	/* ctx_block_len bytes of context block followed by 16-bit context
136214501Srpaulo	 * timeout */
137214501Srpaulo} __attribute__ ((packed));
138214501Srpaulo
139214501Srpaulo
140214501Srpaulo/* CACHE-response - unicast TCP */
141214501Srpaulostruct iapp_cache_response {
142214501Srpaulo	u8 addr_len; /* ETH_ALEN */
143214501Srpaulo	u8 status;
144214501Srpaulo	u8 mac_addr[ETH_ALEN];
145214501Srpaulo	u16 seq_num;
146214501Srpaulo} __attribute__ ((packed));
147214501Srpaulo
148214501Srpauloenum {
149214501Srpaulo	IAPP_CACHE_SUCCESSFUL = 0,
150214501Srpaulo	IAPP_CACHE_STALE_CACHE = 1,
151214501Srpaulo};
152214501Srpaulo
153214501Srpaulo
154214501Srpaulo/* Send-Security-Block - unicast TCP */
155214501Srpaulostruct iapp_send_security_block {
156214501Srpaulo	u8 iv[8];
157214501Srpaulo	u16 sec_block_len;
158214501Srpaulo	/* followed by sec_block_len bytes of security block */
159214501Srpaulo} __attribute__ ((packed));
160214501Srpaulo
161214501Srpaulo
162214501Srpaulo/* ACK-Security-Block - unicast TCP */
163214501Srpaulostruct iapp_ack_security_block {
164214501Srpaulo	u8 iv[8];
165214501Srpaulo	u8 new_ap_ack_authenticator[48];
166214501Srpaulo} __attribute__ ((packed));
167214501Srpaulo
168214501Srpaulo
169214501Srpaulostruct iapp_data {
170214501Srpaulo	struct hostapd_data *hapd;
171214501Srpaulo	u16 identifier; /* next IAPP identifier */
172214501Srpaulo	struct in_addr own, multicast;
173214501Srpaulo	int udp_sock;
174214501Srpaulo	int packet_sock;
175214501Srpaulo};
176214501Srpaulo
177214501Srpaulo
178214501Srpaulostatic void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
179214501Srpaulo{
180214501Srpaulo	char buf[128];
181214501Srpaulo	struct iapp_hdr *hdr;
182214501Srpaulo	struct iapp_add_notify *add;
183214501Srpaulo	struct sockaddr_in addr;
184214501Srpaulo
185214501Srpaulo	/* Send IAPP ADD-notify to remove possible association from other APs
186214501Srpaulo	 */
187214501Srpaulo
188214501Srpaulo	hdr = (struct iapp_hdr *) buf;
189214501Srpaulo	hdr->version = IAPP_VERSION;
190214501Srpaulo	hdr->command = IAPP_CMD_ADD_notify;
191214501Srpaulo	hdr->identifier = host_to_be16(iapp->identifier++);
192214501Srpaulo	hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
193214501Srpaulo
194214501Srpaulo	add = (struct iapp_add_notify *) (hdr + 1);
195214501Srpaulo	add->addr_len = ETH_ALEN;
196214501Srpaulo	add->reserved = 0;
197214501Srpaulo	os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
198214501Srpaulo
199214501Srpaulo	add->seq_num = host_to_be16(seq_num);
200214501Srpaulo
201214501Srpaulo	os_memset(&addr, 0, sizeof(addr));
202214501Srpaulo	addr.sin_family = AF_INET;
203214501Srpaulo	addr.sin_addr.s_addr = iapp->multicast.s_addr;
204214501Srpaulo	addr.sin_port = htons(IAPP_UDP_PORT);
205214501Srpaulo	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
206214501Srpaulo		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
207214501Srpaulo		perror("sendto[IAPP-ADD]");
208214501Srpaulo}
209214501Srpaulo
210214501Srpaulo
211214501Srpaulostatic void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
212214501Srpaulo{
213214501Srpaulo	struct iapp_layer2_update msg;
214214501Srpaulo
215214501Srpaulo	/* Send Level 2 Update Frame to update forwarding tables in layer 2
216214501Srpaulo	 * bridge devices */
217214501Srpaulo
218214501Srpaulo	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
219214501Srpaulo	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
220214501Srpaulo
221214501Srpaulo	os_memset(msg.da, 0xff, ETH_ALEN);
222214501Srpaulo	os_memcpy(msg.sa, addr, ETH_ALEN);
223214501Srpaulo	msg.len = host_to_be16(6);
224214501Srpaulo	msg.dsap = 0; /* NULL DSAP address */
225214501Srpaulo	msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
226214501Srpaulo	msg.control = 0xaf; /* XID response lsb.1111F101.
227214501Srpaulo			     * F=0 (no poll command; unsolicited frame) */
228214501Srpaulo	msg.xid_info[0] = 0x81; /* XID format identifier */
229214501Srpaulo	msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
230214501Srpaulo	msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
231214501Srpaulo				   * FIX: what is correct RW with 802.11? */
232214501Srpaulo
233214501Srpaulo	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
234214501Srpaulo		perror("send[L2 Update]");
235214501Srpaulo}
236214501Srpaulo
237214501Srpaulo
238214501Srpaulo/**
239214501Srpaulo * iapp_new_station - IAPP processing for a new STA
240214501Srpaulo * @iapp: IAPP data
241214501Srpaulo * @sta: The associated station
242214501Srpaulo */
243214501Srpaulovoid iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
244214501Srpaulo{
245214501Srpaulo	struct ieee80211_mgmt *assoc;
246214501Srpaulo	u16 seq;
247214501Srpaulo
248214501Srpaulo	if (iapp == NULL)
249214501Srpaulo		return;
250214501Srpaulo
251214501Srpaulo	assoc = sta->last_assoc_req;
252214501Srpaulo	seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
253214501Srpaulo
254214501Srpaulo	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
255214501Srpaulo	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
256214501Srpaulo		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
257214501Srpaulo	iapp_send_layer2_update(iapp, sta->addr);
258214501Srpaulo	iapp_send_add(iapp, sta->addr, seq);
259214501Srpaulo
260214501Srpaulo	if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
261214501Srpaulo	    WLAN_FC_STYPE_REASSOC_REQ) {
262214501Srpaulo		/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
263214501Srpaulo		 *                   Context Block, Timeout)
264214501Srpaulo		 */
265214501Srpaulo		/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
266214501Srpaulo		 * IP address */
267214501Srpaulo	}
268214501Srpaulo}
269214501Srpaulo
270214501Srpaulo
271214501Srpaulostatic void iapp_process_add_notify(struct iapp_data *iapp,
272214501Srpaulo				    struct sockaddr_in *from,
273214501Srpaulo				    struct iapp_hdr *hdr, int len)
274214501Srpaulo{
275214501Srpaulo	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
276214501Srpaulo	struct sta_info *sta;
277214501Srpaulo
278214501Srpaulo	if (len != sizeof(*add)) {
279214501Srpaulo		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
280214501Srpaulo		       len, (unsigned long) sizeof(*add));
281214501Srpaulo		return;
282214501Srpaulo	}
283214501Srpaulo
284214501Srpaulo	sta = ap_get_sta(iapp->hapd, add->mac_addr);
285214501Srpaulo
286214501Srpaulo	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
287214501Srpaulo	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
288214501Srpaulo		       HOSTAPD_LEVEL_INFO,
289214501Srpaulo		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
290214501Srpaulo		       be_to_host16(add->seq_num),
291214501Srpaulo		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
292214501Srpaulo		       sta ? "" : " (STA not found)");
293214501Srpaulo
294214501Srpaulo	if (!sta)
295214501Srpaulo		return;
296214501Srpaulo
297214501Srpaulo	/* TODO: could use seq_num to try to determine whether last association
298214501Srpaulo	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
299214501Srpaulo	 * this is not really a reliable verification. */
300214501Srpaulo
301214501Srpaulo	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
302214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
303214501Srpaulo		       "Removing STA due to IAPP ADD-notify");
304214501Srpaulo	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
305214501Srpaulo}
306214501Srpaulo
307214501Srpaulo
308214501Srpaulo/**
309214501Srpaulo * iapp_receive_udp - Process IAPP UDP frames
310214501Srpaulo * @sock: File descriptor for the socket
311214501Srpaulo * @eloop_ctx: IAPP data (struct iapp_data *)
312214501Srpaulo * @sock_ctx: Not used
313214501Srpaulo */
314214501Srpaulostatic void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
315214501Srpaulo{
316214501Srpaulo	struct iapp_data *iapp = eloop_ctx;
317214501Srpaulo	int len, hlen;
318214501Srpaulo	unsigned char buf[128];
319214501Srpaulo	struct sockaddr_in from;
320214501Srpaulo	socklen_t fromlen;
321214501Srpaulo	struct iapp_hdr *hdr;
322214501Srpaulo
323214501Srpaulo	/* Handle incoming IAPP frames (over UDP/IP) */
324214501Srpaulo
325214501Srpaulo	fromlen = sizeof(from);
326214501Srpaulo	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
327214501Srpaulo		       (struct sockaddr *) &from, &fromlen);
328214501Srpaulo	if (len < 0) {
329214501Srpaulo		perror("recvfrom");
330214501Srpaulo		return;
331214501Srpaulo	}
332214501Srpaulo
333214501Srpaulo	if (from.sin_addr.s_addr == iapp->own.s_addr)
334214501Srpaulo		return; /* ignore own IAPP messages */
335214501Srpaulo
336214501Srpaulo	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
337214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
338214501Srpaulo		       "Received %d byte IAPP frame from %s%s\n",
339214501Srpaulo		       len, inet_ntoa(from.sin_addr),
340214501Srpaulo		       len < (int) sizeof(*hdr) ? " (too short)" : "");
341214501Srpaulo
342214501Srpaulo	if (len < (int) sizeof(*hdr))
343214501Srpaulo		return;
344214501Srpaulo
345214501Srpaulo	hdr = (struct iapp_hdr *) buf;
346214501Srpaulo	hlen = be_to_host16(hdr->length);
347214501Srpaulo	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
348214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
349214501Srpaulo		       "RX: version=%d command=%d id=%d len=%d\n",
350214501Srpaulo		       hdr->version, hdr->command,
351214501Srpaulo		       be_to_host16(hdr->identifier), hlen);
352214501Srpaulo	if (hdr->version != IAPP_VERSION) {
353214501Srpaulo		printf("Dropping IAPP frame with unknown version %d\n",
354214501Srpaulo		       hdr->version);
355214501Srpaulo		return;
356214501Srpaulo	}
357214501Srpaulo	if (hlen > len) {
358214501Srpaulo		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
359214501Srpaulo		return;
360214501Srpaulo	}
361214501Srpaulo	if (hlen < len) {
362214501Srpaulo		printf("Ignoring %d extra bytes from IAPP frame\n",
363214501Srpaulo		       len - hlen);
364214501Srpaulo		len = hlen;
365214501Srpaulo	}
366214501Srpaulo
367214501Srpaulo	switch (hdr->command) {
368214501Srpaulo	case IAPP_CMD_ADD_notify:
369214501Srpaulo		iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
370214501Srpaulo		break;
371214501Srpaulo	case IAPP_CMD_MOVE_notify:
372214501Srpaulo		/* TODO: MOVE is using TCP; so move this to TCP handler once it
373214501Srpaulo		 * is implemented.. */
374214501Srpaulo		/* IAPP-MOVE.indication(MAC Address, New BSSID,
375214501Srpaulo		 * Sequence Number, AP Address, Context Block) */
376214501Srpaulo		/* TODO: process */
377214501Srpaulo		break;
378214501Srpaulo	default:
379214501Srpaulo		printf("Unknown IAPP command %d\n", hdr->command);
380214501Srpaulo		break;
381214501Srpaulo	}
382214501Srpaulo}
383214501Srpaulo
384214501Srpaulo
385214501Srpaulostruct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
386214501Srpaulo{
387214501Srpaulo	struct ifreq ifr;
388214501Srpaulo	struct sockaddr_ll addr;
389214501Srpaulo	int ifindex;
390214501Srpaulo	struct sockaddr_in *paddr, uaddr;
391214501Srpaulo	struct iapp_data *iapp;
392214501Srpaulo	struct ip_mreqn mreq;
393214501Srpaulo
394214501Srpaulo	iapp = os_zalloc(sizeof(*iapp));
395214501Srpaulo	if (iapp == NULL)
396214501Srpaulo		return NULL;
397214501Srpaulo	iapp->hapd = hapd;
398214501Srpaulo	iapp->udp_sock = iapp->packet_sock = -1;
399214501Srpaulo
400214501Srpaulo	/* TODO:
401214501Srpaulo	 * open socket for sending and receiving IAPP frames over TCP
402214501Srpaulo	 */
403214501Srpaulo
404214501Srpaulo	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
405214501Srpaulo	if (iapp->udp_sock < 0) {
406214501Srpaulo		perror("socket[PF_INET,SOCK_DGRAM]");
407214501Srpaulo		iapp_deinit(iapp);
408214501Srpaulo		return NULL;
409214501Srpaulo	}
410214501Srpaulo
411214501Srpaulo	os_memset(&ifr, 0, sizeof(ifr));
412214501Srpaulo	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
413214501Srpaulo	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
414214501Srpaulo		perror("ioctl(SIOCGIFINDEX)");
415214501Srpaulo		iapp_deinit(iapp);
416214501Srpaulo		return NULL;
417214501Srpaulo	}
418214501Srpaulo	ifindex = ifr.ifr_ifindex;
419214501Srpaulo
420214501Srpaulo	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
421214501Srpaulo		perror("ioctl(SIOCGIFADDR)");
422214501Srpaulo		iapp_deinit(iapp);
423214501Srpaulo		return NULL;
424214501Srpaulo	}
425214501Srpaulo	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
426214501Srpaulo	if (paddr->sin_family != AF_INET) {
427214501Srpaulo		printf("Invalid address family %i (SIOCGIFADDR)\n",
428214501Srpaulo		       paddr->sin_family);
429214501Srpaulo		iapp_deinit(iapp);
430214501Srpaulo		return NULL;
431214501Srpaulo	}
432214501Srpaulo	iapp->own.s_addr = paddr->sin_addr.s_addr;
433214501Srpaulo
434214501Srpaulo	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
435214501Srpaulo		perror("ioctl(SIOCGIFBRDADDR)");
436214501Srpaulo		iapp_deinit(iapp);
437214501Srpaulo		return NULL;
438214501Srpaulo	}
439214501Srpaulo	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
440214501Srpaulo	if (paddr->sin_family != AF_INET) {
441214501Srpaulo		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
442214501Srpaulo		       paddr->sin_family);
443214501Srpaulo		iapp_deinit(iapp);
444214501Srpaulo		return NULL;
445214501Srpaulo	}
446214501Srpaulo	inet_aton(IAPP_MULTICAST, &iapp->multicast);
447214501Srpaulo
448214501Srpaulo	os_memset(&uaddr, 0, sizeof(uaddr));
449214501Srpaulo	uaddr.sin_family = AF_INET;
450214501Srpaulo	uaddr.sin_port = htons(IAPP_UDP_PORT);
451214501Srpaulo	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
452214501Srpaulo		 sizeof(uaddr)) < 0) {
453214501Srpaulo		perror("bind[UDP]");
454214501Srpaulo		iapp_deinit(iapp);
455214501Srpaulo		return NULL;
456214501Srpaulo	}
457214501Srpaulo
458214501Srpaulo	os_memset(&mreq, 0, sizeof(mreq));
459214501Srpaulo	mreq.imr_multiaddr = iapp->multicast;
460214501Srpaulo	mreq.imr_address.s_addr = INADDR_ANY;
461214501Srpaulo	mreq.imr_ifindex = 0;
462214501Srpaulo	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
463214501Srpaulo		       sizeof(mreq)) < 0) {
464214501Srpaulo		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
465214501Srpaulo		iapp_deinit(iapp);
466214501Srpaulo		return NULL;
467214501Srpaulo	}
468214501Srpaulo
469214501Srpaulo	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
470214501Srpaulo	if (iapp->packet_sock < 0) {
471214501Srpaulo		perror("socket[PF_PACKET,SOCK_RAW]");
472214501Srpaulo		iapp_deinit(iapp);
473214501Srpaulo		return NULL;
474214501Srpaulo	}
475214501Srpaulo
476214501Srpaulo	os_memset(&addr, 0, sizeof(addr));
477214501Srpaulo	addr.sll_family = AF_PACKET;
478214501Srpaulo	addr.sll_ifindex = ifindex;
479214501Srpaulo	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
480214501Srpaulo		 sizeof(addr)) < 0) {
481214501Srpaulo		perror("bind[PACKET]");
482214501Srpaulo		iapp_deinit(iapp);
483214501Srpaulo		return NULL;
484214501Srpaulo	}
485214501Srpaulo
486214501Srpaulo	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
487214501Srpaulo				     iapp, NULL)) {
488214501Srpaulo		printf("Could not register read socket for IAPP.\n");
489214501Srpaulo		iapp_deinit(iapp);
490214501Srpaulo		return NULL;
491214501Srpaulo	}
492214501Srpaulo
493214501Srpaulo	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
494214501Srpaulo
495214501Srpaulo	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
496214501Srpaulo	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
497214501Srpaulo	 * be openned only after receiving Initiate-Accept. If Initiate-Reject
498214501Srpaulo	 * is received, IAPP is not started. */
499214501Srpaulo
500214501Srpaulo	return iapp;
501214501Srpaulo}
502214501Srpaulo
503214501Srpaulo
504214501Srpaulovoid iapp_deinit(struct iapp_data *iapp)
505214501Srpaulo{
506214501Srpaulo	struct ip_mreqn mreq;
507214501Srpaulo
508214501Srpaulo	if (iapp == NULL)
509214501Srpaulo		return;
510214501Srpaulo
511214501Srpaulo	if (iapp->udp_sock >= 0) {
512214501Srpaulo		os_memset(&mreq, 0, sizeof(mreq));
513214501Srpaulo		mreq.imr_multiaddr = iapp->multicast;
514214501Srpaulo		mreq.imr_address.s_addr = INADDR_ANY;
515214501Srpaulo		mreq.imr_ifindex = 0;
516214501Srpaulo		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
517214501Srpaulo			       &mreq, sizeof(mreq)) < 0) {
518214501Srpaulo			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
519214501Srpaulo		}
520214501Srpaulo
521214501Srpaulo		eloop_unregister_read_sock(iapp->udp_sock);
522214501Srpaulo		close(iapp->udp_sock);
523214501Srpaulo	}
524214501Srpaulo	if (iapp->packet_sock >= 0) {
525214501Srpaulo		eloop_unregister_read_sock(iapp->packet_sock);
526214501Srpaulo		close(iapp->packet_sock);
527214501Srpaulo	}
528214501Srpaulo	os_free(iapp);
529214501Srpaulo}
530