18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and IEEE has withdrawn it. In other words, it is likely better to look at
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * using some other mechanism for AP-to-AP communication than extending the
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * implementation here.
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* TODO:
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Level 1: no administrative or security support
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *	(e.g., static BSSID to IP address mapping in each AP)
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Level 2: support for dynamic mapping of BSSID to IP address
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Level 3: support for encryption and authentication of IAPP messages
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - add support for MOVE-notify and MOVE-response (this requires support for
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *   finding out IP address for previous AP using RADIUS)
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *   reassociation to another AP
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - implement counters etc. for IAPP MIB
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - verify endianness of fields in IAPP messages; are they big-endian as
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *   used here?
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - RADIUS connection for AP registration and BSSID to IP address mapping
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - TCP connection for IAPP MOVE, CACHE
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - broadcast ESP for IAPP ADD-notify
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - ESP for IAPP MOVE messages
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - security block sending/processing
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * - IEEE 802.11 context transfer
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <net/if.h>
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/ioctl.h>
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef USE_KERNEL_HEADERS
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <linux/if_packet.h>
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* USE_KERNEL_HEADERS */
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netpacket/packet.h>
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* USE_KERNEL_HEADERS */
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h"
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h"
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11.h"
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sta_info.h"
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "iapp.h"
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IAPP_MULTICAST "224.0.1.178"
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IAPP_UDP_PORT 3517
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IAPP_TCP_PORT 3517
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_hdr {
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 version;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 command;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	be16 identifier;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	be16 length;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* followed by length-6 octets of data */
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IAPP_VERSION 0
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum IAPP_COMMAND {
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_ADD_notify = 0,
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_MOVE_notify = 1,
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_MOVE_response = 2,
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_Send_Security_Block = 3,
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_ACK_Security_Block = 4,
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_CACHE_notify = 5,
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CMD_CACHE_response = 6,
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* ADD-notify - multicast UDP on the local LAN */
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_add_notify {
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr_len; /* ETH_ALEN */
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 reserved;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mac_addr[ETH_ALEN];
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	be16 seq_num;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_layer2_update {
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 da[ETH_ALEN]; /* broadcast */
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 sa[ETH_ALEN]; /* STA addr */
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	be16 len; /* 6 */
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 dsap; /* null DSAP address */
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 ssap; /* null SSAP address, CR=Response */
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 control;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 xid_info[3];
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* MOVE-notify - unicast TCP */
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_move_notify {
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr_len; /* ETH_ALEN */
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 reserved;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mac_addr[ETH_ALEN];
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 seq_num;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 ctx_block_len;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* followed by ctx_block_len bytes */
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* MOVE-response - unicast TCP */
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_move_response {
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr_len; /* ETH_ALEN */
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 status;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mac_addr[ETH_ALEN];
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 seq_num;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 ctx_block_len;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* followed by ctx_block_len bytes */
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum {
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_MOVE_SUCCESSFUL = 0,
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_MOVE_DENIED = 1,
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_MOVE_STALE_MOVE = 2,
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* CACHE-notify */
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_cache_notify {
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr_len; /* ETH_ALEN */
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 reserved;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mac_addr[ETH_ALEN];
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 seq_num;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 current_ap[ETH_ALEN];
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 ctx_block_len;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* ctx_block_len bytes of context block followed by 16-bit context
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * timeout */
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* CACHE-response - unicast TCP */
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_cache_response {
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr_len; /* ETH_ALEN */
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 status;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mac_addr[ETH_ALEN];
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 seq_num;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum {
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CACHE_SUCCESSFUL = 0,
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IAPP_CACHE_STALE_CACHE = 1,
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Send-Security-Block - unicast TCP */
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_send_security_block {
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 iv[8];
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 sec_block_len;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* followed by sec_block_len bytes of security block */
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* ACK-Security-Block - unicast TCP */
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_ack_security_block {
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 iv[8];
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 new_ap_ack_authenticator[48];
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__ ((packed));
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_data {
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 identifier; /* next IAPP identifier */
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct in_addr own, multicast;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int udp_sock;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int packet_sock;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[128];
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_hdr *hdr;
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_add_notify *add;
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in addr;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Send IAPP ADD-notify to remove possible association from other APs
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct iapp_hdr *) buf;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->version = IAPP_VERSION;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->command = IAPP_CMD_ADD_notify;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->identifier = host_to_be16(iapp->identifier++);
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add = (struct iapp_add_notify *) (hdr + 1);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add->addr_len = ETH_ALEN;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add->reserved = 0;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add->seq_num = host_to_be16(seq_num);
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&addr, 0, sizeof(addr));
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_family = AF_INET;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_addr.s_addr = iapp->multicast.s_addr;
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_port = htons(IAPP_UDP_PORT);
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
207cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_layer2_update msg;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Send Level 2 Update Frame to update forwarding tables in layer 2
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * bridge devices */
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(msg.da, 0xff, ETH_ALEN);
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(msg.sa, addr, ETH_ALEN);
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.len = host_to_be16(6);
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.dsap = 0; /* NULL DSAP address */
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.control = 0xaf; /* XID response lsb.1111F101.
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     * F=0 (no poll command; unsolicited frame) */
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.xid_info[0] = 0x81; /* XID format identifier */
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   * FIX: what is correct RW with 802.11? */
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
234cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iapp_new_station - IAPP processing for a new STA
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iapp: IAPP data
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sta: The associated station
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
245b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	u16 seq = 0; /* TODO */
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp == NULL)
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp_send_layer2_update(iapp, sta->addr);
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp_send_add(iapp, sta->addr, seq);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
256b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	/* TODO: If this was reassociation:
257b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	 * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
258b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	 *                   Context Block, Timeout)
259b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	 * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
260b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	 * IP address */
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void iapp_process_add_notify(struct iapp_data *iapp,
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    struct sockaddr_in *from,
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    struct iapp_hdr *hdr, int len)
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sta_info *sta;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len != sizeof(*add)) {
272cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
273cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   len, (unsigned long) sizeof(*add));
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta = ap_get_sta(iapp->hapd, add->mac_addr);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       HOSTAPD_LEVEL_INFO,
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       be_to_host16(add->seq_num),
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       sta ? "" : " (STA not found)");
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sta)
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: could use seq_num to try to determine whether last association
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this is not really a reliable verification. */
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       HOSTAPD_LEVEL_DEBUG,
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Removing STA due to IAPP ADD-notify");
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iapp_receive_udp - Process IAPP UDP frames
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sock: File descriptor for the socket
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @eloop_ctx: IAPP data (struct iapp_data *)
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sock_ctx: Not used
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_data *iapp = eloop_ctx;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int len, hlen;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char buf[128];
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in from;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	socklen_t fromlen;
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_hdr *hdr;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Handle incoming IAPP frames (over UDP/IP) */
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fromlen = sizeof(from);
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       (struct sockaddr *) &from, &fromlen);
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 0) {
322cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
323cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (from.sin_addr.s_addr == iapp->own.s_addr)
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* ignore own IAPP messages */
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       HOSTAPD_LEVEL_DEBUG,
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Received %d byte IAPP frame from %s%s\n",
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       len, inet_ntoa(from.sin_addr),
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       len < (int) sizeof(*hdr) ? " (too short)" : "");
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < (int) sizeof(*hdr))
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct iapp_hdr *) buf;
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hlen = be_to_host16(hdr->length);
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       HOSTAPD_LEVEL_DEBUG,
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "RX: version=%d command=%d id=%d len=%d\n",
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       hdr->version, hdr->command,
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       be_to_host16(hdr->identifier), hlen);
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->version != IAPP_VERSION) {
347cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
348cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   hdr->version);
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hlen > len) {
352cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
353cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   hlen, len);
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hlen < len) {
357cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   len - hlen);
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = hlen;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (hdr->command) {
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case IAPP_CMD_ADD_notify:
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case IAPP_CMD_MOVE_notify:
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: MOVE is using TCP; so move this to TCP handler once it
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * is implemented.. */
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* IAPP-MOVE.indication(MAC Address, New BSSID,
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Sequence Number, AP Address, Context Block) */
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: process */
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
374cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ifreq ifr;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_ll addr;
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in *paddr, uaddr;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iapp_data *iapp;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ip_mreqn mreq;
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp = os_zalloc(sizeof(*iapp));
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp == NULL)
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp->hapd = hapd;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp->udp_sock = iapp->packet_sock = -1;
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO:
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * open socket for sending and receiving IAPP frames over TCP
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp->udp_sock < 0) {
401cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
402cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&ifr, 0, sizeof(ifr));
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
410cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
411cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifindex = ifr.ifr_ifindex;
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
418cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
419cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (paddr->sin_family != AF_INET) {
425cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
426cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   paddr->sin_family);
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp->own.s_addr = paddr->sin_addr.s_addr;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
433cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
434cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (paddr->sin_family != AF_INET) {
440cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
441cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   paddr->sin_family);
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	inet_aton(IAPP_MULTICAST, &iapp->multicast);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&uaddr, 0, sizeof(uaddr));
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uaddr.sin_family = AF_INET;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uaddr.sin_port = htons(IAPP_UDP_PORT);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 sizeof(uaddr)) < 0) {
452cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
453cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&mreq, 0, sizeof(mreq));
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mreq.imr_multiaddr = iapp->multicast;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mreq.imr_address.s_addr = INADDR_ANY;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mreq.imr_ifindex = 0;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       sizeof(mreq)) < 0) {
464cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
465cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp->packet_sock < 0) {
472cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
473cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&addr, 0, sizeof(addr));
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sll_family = AF_PACKET;
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sll_ifindex = ifindex;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 sizeof(addr)) < 0) {
483cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
484cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			   strerror(errno));
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     iapp, NULL)) {
491cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iapp_deinit(iapp);
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
496cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * be openned only after receiving Initiate-Accept. If Initiate-Reject
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * is received, IAPP is not started. */
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return iapp;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid iapp_deinit(struct iapp_data *iapp)
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ip_mreqn mreq;
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp == NULL)
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp->udp_sock >= 0) {
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&mreq, 0, sizeof(mreq));
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mreq.imr_multiaddr = iapp->multicast;
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mreq.imr_address.s_addr = INADDR_ANY;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mreq.imr_ifindex = 0;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       &mreq, sizeof(mreq)) < 0) {
521cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
522cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   strerror(errno));
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(iapp->udp_sock);
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(iapp->udp_sock);
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iapp->packet_sock >= 0) {
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(iapp->packet_sock);
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(iapp->packet_sock);
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(iapp);
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
534