00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "utils/includes.h"
00041 #include <net/if.h>
00042 #include <sys/ioctl.h>
00043 #ifdef USE_KERNEL_HEADERS
00044 #include <linux/if_packet.h>
00045 #else
00046 #include <netpacket/packet.h>
00047 #endif
00048
00049 #include "utils/common.h"
00050 #include "utils/eloop.h"
00051 #include "common/ieee802_11_defs.h"
00052 #include "hostapd.h"
00053 #include "ap_config.h"
00054 #include "ieee802_11.h"
00055 #include "sta_info.h"
00056 #include "iapp.h"
00057
00058
00059 #define IAPP_MULTICAST "224.0.1.178"
00060 #define IAPP_UDP_PORT 3517
00061 #define IAPP_TCP_PORT 3517
00062
00063 struct iapp_hdr {
00064 u8 version;
00065 u8 command;
00066 be16 identifier;
00067 be16 length;
00068
00069 } __attribute__ ((packed));
00070
00071 #define IAPP_VERSION 0
00072
00073 enum IAPP_COMMAND {
00074 IAPP_CMD_ADD_notify = 0,
00075 IAPP_CMD_MOVE_notify = 1,
00076 IAPP_CMD_MOVE_response = 2,
00077 IAPP_CMD_Send_Security_Block = 3,
00078 IAPP_CMD_ACK_Security_Block = 4,
00079 IAPP_CMD_CACHE_notify = 5,
00080 IAPP_CMD_CACHE_response = 6,
00081 };
00082
00083
00084
00085 struct iapp_add_notify {
00086 u8 addr_len;
00087 u8 reserved;
00088 u8 mac_addr[ETH_ALEN];
00089 be16 seq_num;
00090 } __attribute__ ((packed));
00091
00092
00093
00094 struct iapp_layer2_update {
00095 u8 da[ETH_ALEN];
00096 u8 sa[ETH_ALEN];
00097 be16 len;
00098 u8 dsap;
00099 u8 ssap;
00100 u8 control;
00101 u8 xid_info[3];
00102 } __attribute__ ((packed));
00103
00104
00105
00106 struct iapp_move_notify {
00107 u8 addr_len;
00108 u8 reserved;
00109 u8 mac_addr[ETH_ALEN];
00110 u16 seq_num;
00111 u16 ctx_block_len;
00112
00113 } __attribute__ ((packed));
00114
00115
00116
00117 struct iapp_move_response {
00118 u8 addr_len;
00119 u8 status;
00120 u8 mac_addr[ETH_ALEN];
00121 u16 seq_num;
00122 u16 ctx_block_len;
00123
00124 } __attribute__ ((packed));
00125
00126 enum {
00127 IAPP_MOVE_SUCCESSFUL = 0,
00128 IAPP_MOVE_DENIED = 1,
00129 IAPP_MOVE_STALE_MOVE = 2,
00130 };
00131
00132
00133
00134 struct iapp_cache_notify {
00135 u8 addr_len;
00136 u8 reserved;
00137 u8 mac_addr[ETH_ALEN];
00138 u16 seq_num;
00139 u8 current_ap[ETH_ALEN];
00140 u16 ctx_block_len;
00141
00142
00143 } __attribute__ ((packed));
00144
00145
00146
00147 struct iapp_cache_response {
00148 u8 addr_len;
00149 u8 status;
00150 u8 mac_addr[ETH_ALEN];
00151 u16 seq_num;
00152 } __attribute__ ((packed));
00153
00154 enum {
00155 IAPP_CACHE_SUCCESSFUL = 0,
00156 IAPP_CACHE_STALE_CACHE = 1,
00157 };
00158
00159
00160
00161 struct iapp_send_security_block {
00162 u8 iv[8];
00163 u16 sec_block_len;
00164
00165 } __attribute__ ((packed));
00166
00167
00168
00169 struct iapp_ack_security_block {
00170 u8 iv[8];
00171 u8 new_ap_ack_authenticator[48];
00172 } __attribute__ ((packed));
00173
00174
00175 struct iapp_data {
00176 struct hostapd_data *hapd;
00177 u16 identifier;
00178 struct in_addr own, multicast;
00179 int udp_sock;
00180 int packet_sock;
00181 };
00182
00183
00184 static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
00185 {
00186 char buf[128];
00187 struct iapp_hdr *hdr;
00188 struct iapp_add_notify *add;
00189 struct sockaddr_in addr;
00190
00191
00192
00193
00194 hdr = (struct iapp_hdr *) buf;
00195 hdr->version = IAPP_VERSION;
00196 hdr->command = IAPP_CMD_ADD_notify;
00197 hdr->identifier = host_to_be16(iapp->identifier++);
00198 hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
00199
00200 add = (struct iapp_add_notify *) (hdr + 1);
00201 add->addr_len = ETH_ALEN;
00202 add->reserved = 0;
00203 os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
00204
00205 add->seq_num = host_to_be16(seq_num);
00206
00207 os_memset(&addr, 0, sizeof(addr));
00208 addr.sin_family = AF_INET;
00209 addr.sin_addr.s_addr = iapp->multicast.s_addr;
00210 addr.sin_port = htons(IAPP_UDP_PORT);
00211 if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
00212 (struct sockaddr *) &addr, sizeof(addr)) < 0)
00213 perror("sendto[IAPP-ADD]");
00214 }
00215
00216
00217 static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
00218 {
00219 struct iapp_layer2_update msg;
00220
00221
00222
00223
00224
00225
00226
00227 os_memset(msg.da, 0xff, ETH_ALEN);
00228 os_memcpy(msg.sa, addr, ETH_ALEN);
00229 msg.len = host_to_be16(6);
00230 msg.dsap = 0;
00231 msg.ssap = 0x01;
00232 msg.control = 0xaf;
00233
00234 msg.xid_info[0] = 0x81;
00235 msg.xid_info[1] = 1;
00236 msg.xid_info[2] = 1 << 1;
00237
00238
00239 if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
00240 perror("send[L2 Update]");
00241 }
00242
00243
00249 void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
00250 {
00251 struct ieee80211_mgmt *assoc;
00252 u16 seq;
00253
00254 if (iapp == NULL)
00255 return;
00256
00257 assoc = sta->last_assoc_req;
00258 seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
00259
00260
00261 hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
00262 HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
00263 iapp_send_layer2_update(iapp, sta->addr);
00264 iapp_send_add(iapp, sta->addr, seq);
00265
00266 if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
00267 WLAN_FC_STYPE_REASSOC_REQ) {
00268
00269
00270
00271
00272
00273 }
00274 }
00275
00276
00277 static void iapp_process_add_notify(struct iapp_data *iapp,
00278 struct sockaddr_in *from,
00279 struct iapp_hdr *hdr, int len)
00280 {
00281 struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
00282 struct sta_info *sta;
00283
00284 if (len != sizeof(*add)) {
00285 printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
00286 len, (unsigned long) sizeof(*add));
00287 return;
00288 }
00289
00290 sta = ap_get_sta(iapp->hapd, add->mac_addr);
00291
00292
00293 hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
00294 HOSTAPD_LEVEL_INFO,
00295 "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
00296 be_to_host16(add->seq_num),
00297 inet_ntoa(from->sin_addr), ntohs(from->sin_port),
00298 sta ? "" : " (STA not found)");
00299
00300 if (!sta)
00301 return;
00302
00303
00304
00305
00306
00307 hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
00308 HOSTAPD_LEVEL_DEBUG,
00309 "Removing STA due to IAPP ADD-notify");
00310 ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
00311 }
00312
00313
00320 static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
00321 {
00322 struct iapp_data *iapp = eloop_ctx;
00323 int len, hlen;
00324 unsigned char buf[128];
00325 struct sockaddr_in from;
00326 socklen_t fromlen;
00327 struct iapp_hdr *hdr;
00328
00329
00330
00331 fromlen = sizeof(from);
00332 len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
00333 (struct sockaddr *) &from, &fromlen);
00334 if (len < 0) {
00335 perror("recvfrom");
00336 return;
00337 }
00338
00339 if (from.sin_addr.s_addr == iapp->own.s_addr)
00340 return;
00341
00342 hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
00343 HOSTAPD_LEVEL_DEBUG,
00344 "Received %d byte IAPP frame from %s%s\n",
00345 len, inet_ntoa(from.sin_addr),
00346 len < (int) sizeof(*hdr) ? " (too short)" : "");
00347
00348 if (len < (int) sizeof(*hdr))
00349 return;
00350
00351 hdr = (struct iapp_hdr *) buf;
00352 hlen = be_to_host16(hdr->length);
00353 hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
00354 HOSTAPD_LEVEL_DEBUG,
00355 "RX: version=%d command=%d id=%d len=%d\n",
00356 hdr->version, hdr->command,
00357 be_to_host16(hdr->identifier), hlen);
00358 if (hdr->version != IAPP_VERSION) {
00359 printf("Dropping IAPP frame with unknown version %d\n",
00360 hdr->version);
00361 return;
00362 }
00363 if (hlen > len) {
00364 printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
00365 return;
00366 }
00367 if (hlen < len) {
00368 printf("Ignoring %d extra bytes from IAPP frame\n",
00369 len - hlen);
00370 len = hlen;
00371 }
00372
00373 switch (hdr->command) {
00374 case IAPP_CMD_ADD_notify:
00375 iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
00376 break;
00377 case IAPP_CMD_MOVE_notify:
00378
00379
00380
00381
00382
00383 break;
00384 default:
00385 printf("Unknown IAPP command %d\n", hdr->command);
00386 break;
00387 }
00388 }
00389
00390
00391 struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
00392 {
00393 struct ifreq ifr;
00394 struct sockaddr_ll addr;
00395 int ifindex;
00396 struct sockaddr_in *paddr, uaddr;
00397 struct iapp_data *iapp;
00398 struct ip_mreqn mreq;
00399
00400 iapp = os_zalloc(sizeof(*iapp));
00401 if (iapp == NULL)
00402 return NULL;
00403 iapp->hapd = hapd;
00404 iapp->udp_sock = iapp->packet_sock = -1;
00405
00406
00407
00408
00409
00410 iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
00411 if (iapp->udp_sock < 0) {
00412 perror("socket[PF_INET,SOCK_DGRAM]");
00413 iapp_deinit(iapp);
00414 return NULL;
00415 }
00416
00417 os_memset(&ifr, 0, sizeof(ifr));
00418 os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
00419 if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
00420 perror("ioctl(SIOCGIFINDEX)");
00421 iapp_deinit(iapp);
00422 return NULL;
00423 }
00424 ifindex = ifr.ifr_ifindex;
00425
00426 if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
00427 perror("ioctl(SIOCGIFADDR)");
00428 iapp_deinit(iapp);
00429 return NULL;
00430 }
00431 paddr = (struct sockaddr_in *) &ifr.ifr_addr;
00432 if (paddr->sin_family != AF_INET) {
00433 printf("Invalid address family %i (SIOCGIFADDR)\n",
00434 paddr->sin_family);
00435 iapp_deinit(iapp);
00436 return NULL;
00437 }
00438 iapp->own.s_addr = paddr->sin_addr.s_addr;
00439
00440 if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
00441 perror("ioctl(SIOCGIFBRDADDR)");
00442 iapp_deinit(iapp);
00443 return NULL;
00444 }
00445 paddr = (struct sockaddr_in *) &ifr.ifr_addr;
00446 if (paddr->sin_family != AF_INET) {
00447 printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
00448 paddr->sin_family);
00449 iapp_deinit(iapp);
00450 return NULL;
00451 }
00452 inet_aton(IAPP_MULTICAST, &iapp->multicast);
00453
00454 os_memset(&uaddr, 0, sizeof(uaddr));
00455 uaddr.sin_family = AF_INET;
00456 uaddr.sin_port = htons(IAPP_UDP_PORT);
00457 if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
00458 sizeof(uaddr)) < 0) {
00459 perror("bind[UDP]");
00460 iapp_deinit(iapp);
00461 return NULL;
00462 }
00463
00464 os_memset(&mreq, 0, sizeof(mreq));
00465 mreq.imr_multiaddr = iapp->multicast;
00466 mreq.imr_address.s_addr = INADDR_ANY;
00467 mreq.imr_ifindex = 0;
00468 if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
00469 sizeof(mreq)) < 0) {
00470 perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
00471 iapp_deinit(iapp);
00472 return NULL;
00473 }
00474
00475 iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
00476 if (iapp->packet_sock < 0) {
00477 perror("socket[PF_PACKET,SOCK_RAW]");
00478 iapp_deinit(iapp);
00479 return NULL;
00480 }
00481
00482 os_memset(&addr, 0, sizeof(addr));
00483 addr.sll_family = AF_PACKET;
00484 addr.sll_ifindex = ifindex;
00485 if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
00486 sizeof(addr)) < 0) {
00487 perror("bind[PACKET]");
00488 iapp_deinit(iapp);
00489 return NULL;
00490 }
00491
00492 if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
00493 iapp, NULL)) {
00494 printf("Could not register read socket for IAPP.\n");
00495 iapp_deinit(iapp);
00496 return NULL;
00497 }
00498
00499 printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
00500
00501
00502
00503
00504
00505
00506 return iapp;
00507 }
00508
00509
00510 void iapp_deinit(struct iapp_data *iapp)
00511 {
00512 struct ip_mreqn mreq;
00513
00514 if (iapp == NULL)
00515 return;
00516
00517 if (iapp->udp_sock >= 0) {
00518 os_memset(&mreq, 0, sizeof(mreq));
00519 mreq.imr_multiaddr = iapp->multicast;
00520 mreq.imr_address.s_addr = INADDR_ANY;
00521 mreq.imr_ifindex = 0;
00522 if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
00523 &mreq, sizeof(mreq)) < 0) {
00524 perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
00525 }
00526
00527 eloop_unregister_read_sock(iapp->udp_sock);
00528 close(iapp->udp_sock);
00529 }
00530 if (iapp->packet_sock >= 0) {
00531 eloop_unregister_read_sock(iapp->packet_sock);
00532 close(iapp->packet_sock);
00533 }
00534 os_free(iapp);
00535 }