xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/iapp.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
33ff40c12SJohn Marino  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  *
83ff40c12SJohn Marino  * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
93ff40c12SJohn Marino  * and IEEE has withdrawn it. In other words, it is likely better to look at
103ff40c12SJohn Marino  * using some other mechanism for AP-to-AP communication than extending the
113ff40c12SJohn Marino  * implementation here.
123ff40c12SJohn Marino  */
133ff40c12SJohn Marino 
143ff40c12SJohn Marino /* TODO:
153ff40c12SJohn Marino  * Level 1: no administrative or security support
163ff40c12SJohn Marino  *	(e.g., static BSSID to IP address mapping in each AP)
173ff40c12SJohn Marino  * Level 2: support for dynamic mapping of BSSID to IP address
183ff40c12SJohn Marino  * Level 3: support for encryption and authentication of IAPP messages
193ff40c12SJohn Marino  * - add support for MOVE-notify and MOVE-response (this requires support for
203ff40c12SJohn Marino  *   finding out IP address for previous AP using RADIUS)
213ff40c12SJohn Marino  * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
223ff40c12SJohn Marino  *   reassociation to another AP
233ff40c12SJohn Marino  * - implement counters etc. for IAPP MIB
243ff40c12SJohn Marino  * - verify endianness of fields in IAPP messages; are they big-endian as
253ff40c12SJohn Marino  *   used here?
263ff40c12SJohn Marino  * - RADIUS connection for AP registration and BSSID to IP address mapping
273ff40c12SJohn Marino  * - TCP connection for IAPP MOVE, CACHE
283ff40c12SJohn Marino  * - broadcast ESP for IAPP ADD-notify
293ff40c12SJohn Marino  * - ESP for IAPP MOVE messages
303ff40c12SJohn Marino  * - security block sending/processing
313ff40c12SJohn Marino  * - IEEE 802.11 context transfer
323ff40c12SJohn Marino  */
333ff40c12SJohn Marino 
343ff40c12SJohn Marino #include "utils/includes.h"
353ff40c12SJohn Marino #include <net/if.h>
363ff40c12SJohn Marino #include <sys/ioctl.h>
373ff40c12SJohn Marino #include <netpacket/packet.h>
383ff40c12SJohn Marino 
393ff40c12SJohn Marino #include "utils/common.h"
403ff40c12SJohn Marino #include "utils/eloop.h"
413ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
423ff40c12SJohn Marino #include "hostapd.h"
433ff40c12SJohn Marino #include "ap_config.h"
443ff40c12SJohn Marino #include "ieee802_11.h"
453ff40c12SJohn Marino #include "sta_info.h"
463ff40c12SJohn Marino #include "iapp.h"
473ff40c12SJohn Marino 
483ff40c12SJohn Marino 
493ff40c12SJohn Marino #define IAPP_MULTICAST "224.0.1.178"
503ff40c12SJohn Marino #define IAPP_UDP_PORT 3517
513ff40c12SJohn Marino #define IAPP_TCP_PORT 3517
523ff40c12SJohn Marino 
533ff40c12SJohn Marino struct iapp_hdr {
543ff40c12SJohn Marino 	u8 version;
553ff40c12SJohn Marino 	u8 command;
563ff40c12SJohn Marino 	be16 identifier;
573ff40c12SJohn Marino 	be16 length;
583ff40c12SJohn Marino 	/* followed by length-6 octets of data */
593ff40c12SJohn Marino } __attribute__ ((packed));
603ff40c12SJohn Marino 
613ff40c12SJohn Marino #define IAPP_VERSION 0
623ff40c12SJohn Marino 
633ff40c12SJohn Marino enum IAPP_COMMAND {
643ff40c12SJohn Marino 	IAPP_CMD_ADD_notify = 0,
653ff40c12SJohn Marino 	IAPP_CMD_MOVE_notify = 1,
663ff40c12SJohn Marino 	IAPP_CMD_MOVE_response = 2,
673ff40c12SJohn Marino 	IAPP_CMD_Send_Security_Block = 3,
683ff40c12SJohn Marino 	IAPP_CMD_ACK_Security_Block = 4,
693ff40c12SJohn Marino 	IAPP_CMD_CACHE_notify = 5,
703ff40c12SJohn Marino 	IAPP_CMD_CACHE_response = 6,
713ff40c12SJohn Marino };
723ff40c12SJohn Marino 
733ff40c12SJohn Marino 
743ff40c12SJohn Marino /* ADD-notify - multicast UDP on the local LAN */
753ff40c12SJohn Marino struct iapp_add_notify {
763ff40c12SJohn Marino 	u8 addr_len; /* ETH_ALEN */
773ff40c12SJohn Marino 	u8 reserved;
783ff40c12SJohn Marino 	u8 mac_addr[ETH_ALEN];
793ff40c12SJohn Marino 	be16 seq_num;
803ff40c12SJohn Marino } __attribute__ ((packed));
813ff40c12SJohn Marino 
823ff40c12SJohn Marino 
833ff40c12SJohn Marino /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
843ff40c12SJohn Marino struct iapp_layer2_update {
853ff40c12SJohn Marino 	u8 da[ETH_ALEN]; /* broadcast */
863ff40c12SJohn Marino 	u8 sa[ETH_ALEN]; /* STA addr */
873ff40c12SJohn Marino 	be16 len; /* 6 */
883ff40c12SJohn Marino 	u8 dsap; /* null DSAP address */
893ff40c12SJohn Marino 	u8 ssap; /* null SSAP address, CR=Response */
903ff40c12SJohn Marino 	u8 control;
913ff40c12SJohn Marino 	u8 xid_info[3];
923ff40c12SJohn Marino } __attribute__ ((packed));
933ff40c12SJohn Marino 
943ff40c12SJohn Marino 
953ff40c12SJohn Marino /* MOVE-notify - unicast TCP */
963ff40c12SJohn Marino struct iapp_move_notify {
973ff40c12SJohn Marino 	u8 addr_len; /* ETH_ALEN */
983ff40c12SJohn Marino 	u8 reserved;
993ff40c12SJohn Marino 	u8 mac_addr[ETH_ALEN];
1003ff40c12SJohn Marino 	u16 seq_num;
1013ff40c12SJohn Marino 	u16 ctx_block_len;
1023ff40c12SJohn Marino 	/* followed by ctx_block_len bytes */
1033ff40c12SJohn Marino } __attribute__ ((packed));
1043ff40c12SJohn Marino 
1053ff40c12SJohn Marino 
1063ff40c12SJohn Marino /* MOVE-response - unicast TCP */
1073ff40c12SJohn Marino struct iapp_move_response {
1083ff40c12SJohn Marino 	u8 addr_len; /* ETH_ALEN */
1093ff40c12SJohn Marino 	u8 status;
1103ff40c12SJohn Marino 	u8 mac_addr[ETH_ALEN];
1113ff40c12SJohn Marino 	u16 seq_num;
1123ff40c12SJohn Marino 	u16 ctx_block_len;
1133ff40c12SJohn Marino 	/* followed by ctx_block_len bytes */
1143ff40c12SJohn Marino } __attribute__ ((packed));
1153ff40c12SJohn Marino 
1163ff40c12SJohn Marino enum {
1173ff40c12SJohn Marino 	IAPP_MOVE_SUCCESSFUL = 0,
1183ff40c12SJohn Marino 	IAPP_MOVE_DENIED = 1,
1193ff40c12SJohn Marino 	IAPP_MOVE_STALE_MOVE = 2,
1203ff40c12SJohn Marino };
1213ff40c12SJohn Marino 
1223ff40c12SJohn Marino 
1233ff40c12SJohn Marino /* CACHE-notify */
1243ff40c12SJohn Marino struct iapp_cache_notify {
1253ff40c12SJohn Marino 	u8 addr_len; /* ETH_ALEN */
1263ff40c12SJohn Marino 	u8 reserved;
1273ff40c12SJohn Marino 	u8 mac_addr[ETH_ALEN];
1283ff40c12SJohn Marino 	u16 seq_num;
1293ff40c12SJohn Marino 	u8 current_ap[ETH_ALEN];
1303ff40c12SJohn Marino 	u16 ctx_block_len;
1313ff40c12SJohn Marino 	/* ctx_block_len bytes of context block followed by 16-bit context
1323ff40c12SJohn Marino 	 * timeout */
1333ff40c12SJohn Marino } __attribute__ ((packed));
1343ff40c12SJohn Marino 
1353ff40c12SJohn Marino 
1363ff40c12SJohn Marino /* CACHE-response - unicast TCP */
1373ff40c12SJohn Marino struct iapp_cache_response {
1383ff40c12SJohn Marino 	u8 addr_len; /* ETH_ALEN */
1393ff40c12SJohn Marino 	u8 status;
1403ff40c12SJohn Marino 	u8 mac_addr[ETH_ALEN];
1413ff40c12SJohn Marino 	u16 seq_num;
1423ff40c12SJohn Marino } __attribute__ ((packed));
1433ff40c12SJohn Marino 
1443ff40c12SJohn Marino enum {
1453ff40c12SJohn Marino 	IAPP_CACHE_SUCCESSFUL = 0,
1463ff40c12SJohn Marino 	IAPP_CACHE_STALE_CACHE = 1,
1473ff40c12SJohn Marino };
1483ff40c12SJohn Marino 
1493ff40c12SJohn Marino 
1503ff40c12SJohn Marino /* Send-Security-Block - unicast TCP */
1513ff40c12SJohn Marino struct iapp_send_security_block {
1523ff40c12SJohn Marino 	u8 iv[8];
1533ff40c12SJohn Marino 	u16 sec_block_len;
1543ff40c12SJohn Marino 	/* followed by sec_block_len bytes of security block */
1553ff40c12SJohn Marino } __attribute__ ((packed));
1563ff40c12SJohn Marino 
1573ff40c12SJohn Marino 
1583ff40c12SJohn Marino /* ACK-Security-Block - unicast TCP */
1593ff40c12SJohn Marino struct iapp_ack_security_block {
1603ff40c12SJohn Marino 	u8 iv[8];
1613ff40c12SJohn Marino 	u8 new_ap_ack_authenticator[48];
1623ff40c12SJohn Marino } __attribute__ ((packed));
1633ff40c12SJohn Marino 
1643ff40c12SJohn Marino 
1653ff40c12SJohn Marino struct iapp_data {
1663ff40c12SJohn Marino 	struct hostapd_data *hapd;
1673ff40c12SJohn Marino 	u16 identifier; /* next IAPP identifier */
1683ff40c12SJohn Marino 	struct in_addr own, multicast;
1693ff40c12SJohn Marino 	int udp_sock;
1703ff40c12SJohn Marino 	int packet_sock;
1713ff40c12SJohn Marino };
1723ff40c12SJohn Marino 
1733ff40c12SJohn Marino 
iapp_send_add(struct iapp_data * iapp,u8 * mac_addr,u16 seq_num)1743ff40c12SJohn Marino static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
1753ff40c12SJohn Marino {
1763ff40c12SJohn Marino 	char buf[128];
1773ff40c12SJohn Marino 	struct iapp_hdr *hdr;
1783ff40c12SJohn Marino 	struct iapp_add_notify *add;
1793ff40c12SJohn Marino 	struct sockaddr_in addr;
1803ff40c12SJohn Marino 
1813ff40c12SJohn Marino 	/* Send IAPP ADD-notify to remove possible association from other APs
1823ff40c12SJohn Marino 	 */
1833ff40c12SJohn Marino 
1843ff40c12SJohn Marino 	hdr = (struct iapp_hdr *) buf;
1853ff40c12SJohn Marino 	hdr->version = IAPP_VERSION;
1863ff40c12SJohn Marino 	hdr->command = IAPP_CMD_ADD_notify;
1873ff40c12SJohn Marino 	hdr->identifier = host_to_be16(iapp->identifier++);
1883ff40c12SJohn Marino 	hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
1893ff40c12SJohn Marino 
1903ff40c12SJohn Marino 	add = (struct iapp_add_notify *) (hdr + 1);
1913ff40c12SJohn Marino 	add->addr_len = ETH_ALEN;
1923ff40c12SJohn Marino 	add->reserved = 0;
1933ff40c12SJohn Marino 	os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
1943ff40c12SJohn Marino 
1953ff40c12SJohn Marino 	add->seq_num = host_to_be16(seq_num);
1963ff40c12SJohn Marino 
1973ff40c12SJohn Marino 	os_memset(&addr, 0, sizeof(addr));
1983ff40c12SJohn Marino 	addr.sin_family = AF_INET;
1993ff40c12SJohn Marino 	addr.sin_addr.s_addr = iapp->multicast.s_addr;
2003ff40c12SJohn Marino 	addr.sin_port = htons(IAPP_UDP_PORT);
2013ff40c12SJohn Marino 	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
2023ff40c12SJohn Marino 		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
2033ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
2043ff40c12SJohn Marino }
2053ff40c12SJohn Marino 
2063ff40c12SJohn Marino 
iapp_send_layer2_update(struct iapp_data * iapp,u8 * addr)2073ff40c12SJohn Marino static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
2083ff40c12SJohn Marino {
2093ff40c12SJohn Marino 	struct iapp_layer2_update msg;
2103ff40c12SJohn Marino 
2113ff40c12SJohn Marino 	/* Send Level 2 Update Frame to update forwarding tables in layer 2
2123ff40c12SJohn Marino 	 * bridge devices */
2133ff40c12SJohn Marino 
2143ff40c12SJohn Marino 	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
2153ff40c12SJohn Marino 	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
2163ff40c12SJohn Marino 
2173ff40c12SJohn Marino 	os_memset(msg.da, 0xff, ETH_ALEN);
2183ff40c12SJohn Marino 	os_memcpy(msg.sa, addr, ETH_ALEN);
2193ff40c12SJohn Marino 	msg.len = host_to_be16(6);
2203ff40c12SJohn Marino 	msg.dsap = 0; /* NULL DSAP address */
2213ff40c12SJohn Marino 	msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
2223ff40c12SJohn Marino 	msg.control = 0xaf; /* XID response lsb.1111F101.
2233ff40c12SJohn Marino 			     * F=0 (no poll command; unsolicited frame) */
2243ff40c12SJohn Marino 	msg.xid_info[0] = 0x81; /* XID format identifier */
2253ff40c12SJohn Marino 	msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
2263ff40c12SJohn Marino 	msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
2273ff40c12SJohn Marino 				   * FIX: what is correct RW with 802.11? */
2283ff40c12SJohn Marino 
2293ff40c12SJohn Marino 	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
2303ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
2313ff40c12SJohn Marino }
2323ff40c12SJohn Marino 
2333ff40c12SJohn Marino 
2343ff40c12SJohn Marino /**
2353ff40c12SJohn Marino  * iapp_new_station - IAPP processing for a new STA
2363ff40c12SJohn Marino  * @iapp: IAPP data
2373ff40c12SJohn Marino  * @sta: The associated station
2383ff40c12SJohn Marino  */
iapp_new_station(struct iapp_data * iapp,struct sta_info * sta)2393ff40c12SJohn Marino void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
2403ff40c12SJohn Marino {
241*a1157835SDaniel Fojt 	u16 seq = 0; /* TODO */
2423ff40c12SJohn Marino 
2433ff40c12SJohn Marino 	if (iapp == NULL)
2443ff40c12SJohn Marino 		return;
2453ff40c12SJohn Marino 
2463ff40c12SJohn Marino 	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
2473ff40c12SJohn Marino 	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
2483ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
2493ff40c12SJohn Marino 	iapp_send_layer2_update(iapp, sta->addr);
2503ff40c12SJohn Marino 	iapp_send_add(iapp, sta->addr, seq);
2513ff40c12SJohn Marino 
252*a1157835SDaniel Fojt 	/* TODO: If this was reassociation:
253*a1157835SDaniel Fojt 	 * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
2543ff40c12SJohn Marino 	 *                   Context Block, Timeout)
255*a1157835SDaniel Fojt 	 * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
2563ff40c12SJohn Marino 	 * IP address */
2573ff40c12SJohn Marino }
2583ff40c12SJohn Marino 
2593ff40c12SJohn Marino 
iapp_process_add_notify(struct iapp_data * iapp,struct sockaddr_in * from,struct iapp_hdr * hdr,int len)2603ff40c12SJohn Marino static void iapp_process_add_notify(struct iapp_data *iapp,
2613ff40c12SJohn Marino 				    struct sockaddr_in *from,
2623ff40c12SJohn Marino 				    struct iapp_hdr *hdr, int len)
2633ff40c12SJohn Marino {
2643ff40c12SJohn Marino 	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
2653ff40c12SJohn Marino 	struct sta_info *sta;
2663ff40c12SJohn Marino 
2673ff40c12SJohn Marino 	if (len != sizeof(*add)) {
2683ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
2693ff40c12SJohn Marino 			   len, (unsigned long) sizeof(*add));
2703ff40c12SJohn Marino 		return;
2713ff40c12SJohn Marino 	}
2723ff40c12SJohn Marino 
2733ff40c12SJohn Marino 	sta = ap_get_sta(iapp->hapd, add->mac_addr);
2743ff40c12SJohn Marino 
2753ff40c12SJohn Marino 	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
2763ff40c12SJohn Marino 	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
2773ff40c12SJohn Marino 		       HOSTAPD_LEVEL_INFO,
2783ff40c12SJohn Marino 		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
2793ff40c12SJohn Marino 		       be_to_host16(add->seq_num),
2803ff40c12SJohn Marino 		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
2813ff40c12SJohn Marino 		       sta ? "" : " (STA not found)");
2823ff40c12SJohn Marino 
2833ff40c12SJohn Marino 	if (!sta)
2843ff40c12SJohn Marino 		return;
2853ff40c12SJohn Marino 
2863ff40c12SJohn Marino 	/* TODO: could use seq_num to try to determine whether last association
2873ff40c12SJohn Marino 	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
2883ff40c12SJohn Marino 	 * this is not really a reliable verification. */
2893ff40c12SJohn Marino 
2903ff40c12SJohn Marino 	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
2913ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG,
2923ff40c12SJohn Marino 		       "Removing STA due to IAPP ADD-notify");
2933ff40c12SJohn Marino 	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
2943ff40c12SJohn Marino }
2953ff40c12SJohn Marino 
2963ff40c12SJohn Marino 
2973ff40c12SJohn Marino /**
2983ff40c12SJohn Marino  * iapp_receive_udp - Process IAPP UDP frames
2993ff40c12SJohn Marino  * @sock: File descriptor for the socket
3003ff40c12SJohn Marino  * @eloop_ctx: IAPP data (struct iapp_data *)
3013ff40c12SJohn Marino  * @sock_ctx: Not used
3023ff40c12SJohn Marino  */
iapp_receive_udp(int sock,void * eloop_ctx,void * sock_ctx)3033ff40c12SJohn Marino static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
3043ff40c12SJohn Marino {
3053ff40c12SJohn Marino 	struct iapp_data *iapp = eloop_ctx;
3063ff40c12SJohn Marino 	int len, hlen;
3073ff40c12SJohn Marino 	unsigned char buf[128];
3083ff40c12SJohn Marino 	struct sockaddr_in from;
3093ff40c12SJohn Marino 	socklen_t fromlen;
3103ff40c12SJohn Marino 	struct iapp_hdr *hdr;
3113ff40c12SJohn Marino 
3123ff40c12SJohn Marino 	/* Handle incoming IAPP frames (over UDP/IP) */
3133ff40c12SJohn Marino 
3143ff40c12SJohn Marino 	fromlen = sizeof(from);
3153ff40c12SJohn Marino 	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
3163ff40c12SJohn Marino 		       (struct sockaddr *) &from, &fromlen);
3173ff40c12SJohn Marino 	if (len < 0) {
3183ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
3193ff40c12SJohn Marino 			   strerror(errno));
3203ff40c12SJohn Marino 		return;
3213ff40c12SJohn Marino 	}
3223ff40c12SJohn Marino 
3233ff40c12SJohn Marino 	if (from.sin_addr.s_addr == iapp->own.s_addr)
3243ff40c12SJohn Marino 		return; /* ignore own IAPP messages */
3253ff40c12SJohn Marino 
3263ff40c12SJohn Marino 	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
3273ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG,
3283ff40c12SJohn Marino 		       "Received %d byte IAPP frame from %s%s\n",
3293ff40c12SJohn Marino 		       len, inet_ntoa(from.sin_addr),
3303ff40c12SJohn Marino 		       len < (int) sizeof(*hdr) ? " (too short)" : "");
3313ff40c12SJohn Marino 
3323ff40c12SJohn Marino 	if (len < (int) sizeof(*hdr))
3333ff40c12SJohn Marino 		return;
3343ff40c12SJohn Marino 
3353ff40c12SJohn Marino 	hdr = (struct iapp_hdr *) buf;
3363ff40c12SJohn Marino 	hlen = be_to_host16(hdr->length);
3373ff40c12SJohn Marino 	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
3383ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG,
3393ff40c12SJohn Marino 		       "RX: version=%d command=%d id=%d len=%d\n",
3403ff40c12SJohn Marino 		       hdr->version, hdr->command,
3413ff40c12SJohn Marino 		       be_to_host16(hdr->identifier), hlen);
3423ff40c12SJohn Marino 	if (hdr->version != IAPP_VERSION) {
3433ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
3443ff40c12SJohn Marino 			   hdr->version);
3453ff40c12SJohn Marino 		return;
3463ff40c12SJohn Marino 	}
3473ff40c12SJohn Marino 	if (hlen > len) {
3483ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
3493ff40c12SJohn Marino 			   hlen, len);
3503ff40c12SJohn Marino 		return;
3513ff40c12SJohn Marino 	}
3523ff40c12SJohn Marino 	if (hlen < len) {
3533ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
3543ff40c12SJohn Marino 			   len - hlen);
3553ff40c12SJohn Marino 		len = hlen;
3563ff40c12SJohn Marino 	}
3573ff40c12SJohn Marino 
3583ff40c12SJohn Marino 	switch (hdr->command) {
3593ff40c12SJohn Marino 	case IAPP_CMD_ADD_notify:
360*a1157835SDaniel Fojt 		iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
3613ff40c12SJohn Marino 		break;
3623ff40c12SJohn Marino 	case IAPP_CMD_MOVE_notify:
3633ff40c12SJohn Marino 		/* TODO: MOVE is using TCP; so move this to TCP handler once it
3643ff40c12SJohn Marino 		 * is implemented.. */
3653ff40c12SJohn Marino 		/* IAPP-MOVE.indication(MAC Address, New BSSID,
3663ff40c12SJohn Marino 		 * Sequence Number, AP Address, Context Block) */
3673ff40c12SJohn Marino 		/* TODO: process */
3683ff40c12SJohn Marino 		break;
3693ff40c12SJohn Marino 	default:
3703ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
3713ff40c12SJohn Marino 		break;
3723ff40c12SJohn Marino 	}
3733ff40c12SJohn Marino }
3743ff40c12SJohn Marino 
3753ff40c12SJohn Marino 
iapp_init(struct hostapd_data * hapd,const char * iface)3763ff40c12SJohn Marino struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
3773ff40c12SJohn Marino {
3783ff40c12SJohn Marino 	struct ifreq ifr;
3793ff40c12SJohn Marino 	struct sockaddr_ll addr;
3803ff40c12SJohn Marino 	int ifindex;
3813ff40c12SJohn Marino 	struct sockaddr_in *paddr, uaddr;
3823ff40c12SJohn Marino 	struct iapp_data *iapp;
3833ff40c12SJohn Marino 	struct ip_mreqn mreq;
384*a1157835SDaniel Fojt 	int reuseaddr = 1;
3853ff40c12SJohn Marino 
3863ff40c12SJohn Marino 	iapp = os_zalloc(sizeof(*iapp));
3873ff40c12SJohn Marino 	if (iapp == NULL)
3883ff40c12SJohn Marino 		return NULL;
3893ff40c12SJohn Marino 	iapp->hapd = hapd;
3903ff40c12SJohn Marino 	iapp->udp_sock = iapp->packet_sock = -1;
3913ff40c12SJohn Marino 
3923ff40c12SJohn Marino 	/* TODO:
3933ff40c12SJohn Marino 	 * open socket for sending and receiving IAPP frames over TCP
3943ff40c12SJohn Marino 	 */
3953ff40c12SJohn Marino 
3963ff40c12SJohn Marino 	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
3973ff40c12SJohn Marino 	if (iapp->udp_sock < 0) {
3983ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
3993ff40c12SJohn Marino 			   strerror(errno));
4003ff40c12SJohn Marino 		iapp_deinit(iapp);
4013ff40c12SJohn Marino 		return NULL;
4023ff40c12SJohn Marino 	}
4033ff40c12SJohn Marino 
4043ff40c12SJohn Marino 	os_memset(&ifr, 0, sizeof(ifr));
4053ff40c12SJohn Marino 	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
4063ff40c12SJohn Marino 	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
4073ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
4083ff40c12SJohn Marino 			   strerror(errno));
4093ff40c12SJohn Marino 		iapp_deinit(iapp);
4103ff40c12SJohn Marino 		return NULL;
4113ff40c12SJohn Marino 	}
4123ff40c12SJohn Marino 	ifindex = ifr.ifr_ifindex;
4133ff40c12SJohn Marino 
4143ff40c12SJohn Marino 	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
4153ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
4163ff40c12SJohn Marino 			   strerror(errno));
4173ff40c12SJohn Marino 		iapp_deinit(iapp);
4183ff40c12SJohn Marino 		return NULL;
4193ff40c12SJohn Marino 	}
4203ff40c12SJohn Marino 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
4213ff40c12SJohn Marino 	if (paddr->sin_family != AF_INET) {
4223ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
4233ff40c12SJohn Marino 			   paddr->sin_family);
4243ff40c12SJohn Marino 		iapp_deinit(iapp);
4253ff40c12SJohn Marino 		return NULL;
4263ff40c12SJohn Marino 	}
4273ff40c12SJohn Marino 	iapp->own.s_addr = paddr->sin_addr.s_addr;
4283ff40c12SJohn Marino 
4293ff40c12SJohn Marino 	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
4303ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
4313ff40c12SJohn Marino 			   strerror(errno));
4323ff40c12SJohn Marino 		iapp_deinit(iapp);
4333ff40c12SJohn Marino 		return NULL;
4343ff40c12SJohn Marino 	}
4353ff40c12SJohn Marino 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
4363ff40c12SJohn Marino 	if (paddr->sin_family != AF_INET) {
4373ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
4383ff40c12SJohn Marino 			   paddr->sin_family);
4393ff40c12SJohn Marino 		iapp_deinit(iapp);
4403ff40c12SJohn Marino 		return NULL;
4413ff40c12SJohn Marino 	}
4423ff40c12SJohn Marino 	inet_aton(IAPP_MULTICAST, &iapp->multicast);
4433ff40c12SJohn Marino 
4443ff40c12SJohn Marino 	os_memset(&uaddr, 0, sizeof(uaddr));
4453ff40c12SJohn Marino 	uaddr.sin_family = AF_INET;
4463ff40c12SJohn Marino 	uaddr.sin_port = htons(IAPP_UDP_PORT);
447*a1157835SDaniel Fojt 
448*a1157835SDaniel Fojt 	if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
449*a1157835SDaniel Fojt 		       sizeof(reuseaddr)) < 0) {
450*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
451*a1157835SDaniel Fojt 			   "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
452*a1157835SDaniel Fojt 			   strerror(errno));
453*a1157835SDaniel Fojt 		/*
454*a1157835SDaniel Fojt 		 * Ignore this and try to continue. This is fine for single
455*a1157835SDaniel Fojt 		 * BSS cases, but may fail if multiple BSSes enable IAPP.
456*a1157835SDaniel Fojt 		 */
457*a1157835SDaniel Fojt 	}
458*a1157835SDaniel Fojt 
4593ff40c12SJohn Marino 	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
4603ff40c12SJohn Marino 		 sizeof(uaddr)) < 0) {
4613ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
4623ff40c12SJohn Marino 			   strerror(errno));
4633ff40c12SJohn Marino 		iapp_deinit(iapp);
4643ff40c12SJohn Marino 		return NULL;
4653ff40c12SJohn Marino 	}
4663ff40c12SJohn Marino 
4673ff40c12SJohn Marino 	os_memset(&mreq, 0, sizeof(mreq));
4683ff40c12SJohn Marino 	mreq.imr_multiaddr = iapp->multicast;
4693ff40c12SJohn Marino 	mreq.imr_address.s_addr = INADDR_ANY;
4703ff40c12SJohn Marino 	mreq.imr_ifindex = 0;
4713ff40c12SJohn Marino 	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
4723ff40c12SJohn Marino 		       sizeof(mreq)) < 0) {
4733ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
4743ff40c12SJohn Marino 			   strerror(errno));
4753ff40c12SJohn Marino 		iapp_deinit(iapp);
4763ff40c12SJohn Marino 		return NULL;
4773ff40c12SJohn Marino 	}
4783ff40c12SJohn Marino 
4793ff40c12SJohn Marino 	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
4803ff40c12SJohn Marino 	if (iapp->packet_sock < 0) {
4813ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
4823ff40c12SJohn Marino 			   strerror(errno));
4833ff40c12SJohn Marino 		iapp_deinit(iapp);
4843ff40c12SJohn Marino 		return NULL;
4853ff40c12SJohn Marino 	}
4863ff40c12SJohn Marino 
4873ff40c12SJohn Marino 	os_memset(&addr, 0, sizeof(addr));
4883ff40c12SJohn Marino 	addr.sll_family = AF_PACKET;
4893ff40c12SJohn Marino 	addr.sll_ifindex = ifindex;
4903ff40c12SJohn Marino 	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
4913ff40c12SJohn Marino 		 sizeof(addr)) < 0) {
4923ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
4933ff40c12SJohn Marino 			   strerror(errno));
4943ff40c12SJohn Marino 		iapp_deinit(iapp);
4953ff40c12SJohn Marino 		return NULL;
4963ff40c12SJohn Marino 	}
4973ff40c12SJohn Marino 
4983ff40c12SJohn Marino 	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
4993ff40c12SJohn Marino 				     iapp, NULL)) {
5003ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
5013ff40c12SJohn Marino 		iapp_deinit(iapp);
5023ff40c12SJohn Marino 		return NULL;
5033ff40c12SJohn Marino 	}
5043ff40c12SJohn Marino 
5053ff40c12SJohn Marino 	wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
5063ff40c12SJohn Marino 
5073ff40c12SJohn Marino 	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
5083ff40c12SJohn Marino 	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
5093ff40c12SJohn Marino 	 * be openned only after receiving Initiate-Accept. If Initiate-Reject
5103ff40c12SJohn Marino 	 * is received, IAPP is not started. */
5113ff40c12SJohn Marino 
5123ff40c12SJohn Marino 	return iapp;
5133ff40c12SJohn Marino }
5143ff40c12SJohn Marino 
5153ff40c12SJohn Marino 
iapp_deinit(struct iapp_data * iapp)5163ff40c12SJohn Marino void iapp_deinit(struct iapp_data *iapp)
5173ff40c12SJohn Marino {
5183ff40c12SJohn Marino 	struct ip_mreqn mreq;
5193ff40c12SJohn Marino 
5203ff40c12SJohn Marino 	if (iapp == NULL)
5213ff40c12SJohn Marino 		return;
5223ff40c12SJohn Marino 
5233ff40c12SJohn Marino 	if (iapp->udp_sock >= 0) {
5243ff40c12SJohn Marino 		os_memset(&mreq, 0, sizeof(mreq));
5253ff40c12SJohn Marino 		mreq.imr_multiaddr = iapp->multicast;
5263ff40c12SJohn Marino 		mreq.imr_address.s_addr = INADDR_ANY;
5273ff40c12SJohn Marino 		mreq.imr_ifindex = 0;
5283ff40c12SJohn Marino 		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
5293ff40c12SJohn Marino 			       &mreq, sizeof(mreq)) < 0) {
5303ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
5313ff40c12SJohn Marino 				   strerror(errno));
5323ff40c12SJohn Marino 		}
5333ff40c12SJohn Marino 
5343ff40c12SJohn Marino 		eloop_unregister_read_sock(iapp->udp_sock);
5353ff40c12SJohn Marino 		close(iapp->udp_sock);
5363ff40c12SJohn Marino 	}
5373ff40c12SJohn Marino 	if (iapp->packet_sock >= 0) {
5383ff40c12SJohn Marino 		eloop_unregister_read_sock(iapp->packet_sock);
5393ff40c12SJohn Marino 		close(iapp->packet_sock);
5403ff40c12SJohn Marino 	}
5413ff40c12SJohn Marino 	os_free(iapp);
5423ff40c12SJohn Marino }
543