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