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