diff options
Diffstat (limited to 'usr.sbin/hostapd/iapp.c')
-rw-r--r-- | usr.sbin/hostapd/iapp.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/usr.sbin/hostapd/iapp.c b/usr.sbin/hostapd/iapp.c new file mode 100644 index 00000000000..60c64c1b438 --- /dev/null +++ b/usr.sbin/hostapd/iapp.c @@ -0,0 +1,209 @@ +/* $OpenBSD: iapp.c,v 1.1 2005/04/13 18:12:23 reyk Exp $ */ + +/* + * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_arp.h> +#include <net/if_llc.h> +#include <net/bpf.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "hostapd.h" + +void +hostapd_iapp_init(struct hostapd_config *cfg) +{ + if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) + return; + + /* Get Host AP's BSSID */ + hostapd_priv_apme_bssid(cfg); + + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: attaching to Host AP with BSSID \"%s\"\n", + cfg->c_apme_iface, cfg->c_iapp_iface, + ether_ntoa((struct ether_addr *)cfg->c_apme_bssid)); +} + +void +hostapd_iapp_term(struct hostapd_config *cfg) +{ + if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) + return; + + /* XXX not yet used but inspired by the APME TERMINATE action */ + hostapd_log(HOSTAPD_LOG_VERBOSE, "%s/%s: detaching from Host AP\n", + cfg->c_apme_iface, cfg->c_iapp_iface); +} + +int +hostapd_iapp_add_notify(struct hostapd_config *cfg, struct hostapd_node *node) +{ + struct sockaddr_in *addr; + struct { + struct ieee80211_iapp_frame hdr; + struct ieee80211_iapp_add_notify add; + } __packed frame; + + /* + * Send an ADD.notify message to other accesspoints to notify + * about a new association on our Host AP. + */ + + bzero(&frame, sizeof(frame)); + + frame.hdr.i_version = IEEE80211_IAPP_VERSION; + frame.hdr.i_command = IEEE80211_IAPP_FRAME_ADD_NOTIFY; + frame.hdr.i_identifier = htons(cfg->c_iapp++); + + frame.add.a_length = IEEE80211_ADDR_LEN; + frame.add.a_seqnum = htons(node->ni_rxseq); + bcopy(node->ni_macaddr, frame.add.a_macaddr, IEEE80211_ADDR_LEN); + + if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) + addr = &cfg->c_iapp_broadcast; + else + addr = &cfg->c_iapp_multicast; + + if (sendto(cfg->c_iapp_udp, &frame, sizeof(frame), + 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) { + hostapd_log(HOSTAPD_LOG, + "%s/%s: failed to send ADD notification: %s\n", + cfg->c_apme_iface, cfg->c_iapp_iface, + strerror(errno)); + return (errno); + } + + hostapd_log(HOSTAPD_LOG, "%s/%s: sent ADD notification for %s\n", + cfg->c_apme_iface, cfg->c_iapp_iface, + ether_ntoa((struct ether_addr*)frame.add.a_macaddr)); + + /* Send a LLC XID frame, see llc.c for details */ + return (hostapd_priv_llc_xid(cfg, node)); +} + +void +hostapd_iapp_input(int fd, short sig, void *arg) +{ + struct hostapd_config *cfg = (struct hostapd_config *)arg; + struct sockaddr_in addr; + socklen_t addr_len; + u_int8_t buf[IAPP_MAXSIZE]; + struct hostapd_node node; + struct ieee80211_iapp_recv { + struct ieee80211_iapp_frame hdr; + union { + struct ieee80211_iapp_add_notify add; + } u; + } __packed *frame; + int ret = 0; + + /* Ignore invalid signals */ + if (sig != EV_READ) + return; + + /* + * Listen to possible messages from other IAPP + */ + + bzero(buf, sizeof(buf)); + + if (recvfrom(fd, buf, sizeof(buf), 0, + (struct sockaddr*)&addr, &addr_len) < 1) + return; + + if (memcmp(&cfg->c_iapp_addr.sin_addr, &addr.sin_addr, + sizeof(addr.sin_addr)) == 0) + return; + + frame = (struct ieee80211_iapp_recv*)buf; + + /* Validate the IAPP version */ + if (frame->hdr.i_version != IEEE80211_IAPP_VERSION || + addr_len < sizeof(struct sockaddr_in)) + return; + + cfg->c_stats.cn_rx_iapp++; + + /* + * Process the IAPP frame + */ + switch (frame->hdr.i_command) { + case IEEE80211_IAPP_FRAME_ADD_NOTIFY: + /* Don't support non-48bit MAC addresses, yet */ + if (frame->u.add.a_length != IEEE80211_ADDR_LEN) + return; + + node.ni_rxseq = frame->u.add.a_seqnum; + bcopy(frame->u.add.a_macaddr, node.ni_macaddr, + IEEE80211_ADDR_LEN); + + /* + * Try to remove a node from our Host AP and to free + * any allocated resources. Otherwise the received + * ADD.notify message will be ignored. + */ + if (cfg->c_flags & HOSTAPD_CFG_F_APME) + ret = hostapd_priv_apme_delnode(cfg, &node); + else + ret = 0; + + hostapd_log(HOSTAPD_LOG, "%s/%s: %s ADD notification " + "for %s at %s (%s)\n", + ret == 0 ? "received" : "ignored", + cfg->c_apme_iface, cfg->c_iapp_iface, + ether_ntoa((struct ether_addr*)node.ni_macaddr), + inet_ntoa(addr.sin_addr)); + break; + + case IEEE80211_IAPP_FRAME_MOVE_NOTIFY: + case IEEE80211_IAPP_FRAME_MOVE_RESPONSE: + case IEEE80211_IAPP_FRAME_SEND_SECURITY_BLOCK: + case IEEE80211_IAPP_FRAME_ACK_SECURITY_BLOCK: + case IEEE80211_IAPP_FRAME_CACHE_NOTIFY: + case IEEE80211_IAPP_FRAME_CACHE_RESPONSE: + + /* + * XXX TODO + */ + + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: received unsupported IAPP message %d\n", + cfg->c_apme_iface, cfg->c_iapp_iface, + frame->hdr.i_command); + return; + + default: + return; + } +} |