vBulletin Search Engine Optimization
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| hi, On Thu, Dec 01, 2005 at 05:59:50AM +0100, Reyk Floeter wrote: > during the EuroBSDCon, while listening to claudio@'s talk about > OpenOSPFD, i had an idea to implement IP-based wireless roaming with > hostapd(8) in conjunction with ospfd(8). indeed, this idea and the > attached diff is very experimental... i need testers and comments > it is still very experimental but i slightly updated the diff. thanks for the previous comments from some people. to use multicast between multiple LANs correctly, the multicast ttl has to be increased. use the new configuration option "set mode multicast ttl 2" (or even a higher ttl). i tested it with bgpd, two accesspoints and one gateway which worked without problems... but using a border gateway daemon with private AS for wireless roaming is probably a bit strange ;-). ospfd has problems with updating the routes appearing from a different accesspoint, which could be probably fixed in the daemon itself. reyk Index: Makefile ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/Makefile,v retrieving revision 1.4 diff -u -p -r1.4 Makefile --- Makefile 30 Jul 2005 17:18:24 -0000 1.4 +++ Makefile 4 Dec 2005 08:06:46 -0000 @@ -1,7 +1,8 @@ # $OpenBSD: Makefile,v 1.4 2005/07/30 17:18:24 reyk Exp $ PROG= hostapd -SRCS= privsep.c apme.c handle.c iapp.c llc.c hostapd.c print-802_11.c parse.y +SRCS= privsep.c apme.c handle.c iapp.c llc.c hostapd.c \ + print-802_11.c roaming.c parse.y MAN= hostapd.8 hostapd.conf.5 LDADD= ${LIBEVENT} CFLAGS+= -Wall -I${.CURDIR} Index: apme.c ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/apme.c,v retrieving revision 1.8 diff -u -p -r1.8 apme.c --- apme.c 1 Dec 2005 01:11:30 -0000 1.8 +++ apme.c 4 Dec 2005 08:06:46 -0000 @@ -126,6 +126,10 @@ hostapd_apme_term(struct hostapd_apme *a TAILQ_REMOVE(&cfg->c_apmes, apme, a_entries); + /* Remove all dynamic roaming addresses */ + if (cfg->c_flags & HOSTAPD_CFG_F_PRIV) + hostapd_roaming_term(apme); + hostapd_log(HOSTAPD_LOG_DEBUG, "%s: Host AP interface removed\n", apme->a_iface); @@ -253,6 +257,7 @@ void hostapd_apme_frame(struct hostapd_apme *apme, u_int8_t *buf, u_int len) { struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; + struct hostapd_iapp *iapp = &cfg->c_iapp; struct hostapd_apme *other_apme; struct hostapd_node node; struct ieee80211_frame *wh; @@ -310,12 +315,16 @@ hostapd_apme_frame(struct hostapd_apme * TAILQ_FOREACH(other_apme, &cfg->c_apmes, a_entries) { if (apme == other_apme) continue; + if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) + hostapd_roaming_del(other_apme, &node); if (hostapd_apme_delnode(other_apme, &node) == 0) cfg->c_stats.cn_tx_apme++; } hostapd_iapp_add_notify(apme, &node); + if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) + hostapd_roaming_add(apme, &node); } void Index: hostapd.c ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/hostapd.c,v retrieving revision 1.24 diff -u -p -r1.24 hostapd.c --- hostapd.c 1 Dec 2005 01:11:30 -0000 1.24 +++ hostapd.c 4 Dec 2005 08:06:47 -0000 @@ -285,6 +285,11 @@ hostapd_udp_init(struct hostapd_config * IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) hostapd_fatal("failed to add multicast membership to " "%s: %s\n", IAPP_MCASTADDR, strerror(errno)); + + if (setsockopt(iapp->i_udp, IPPROTO_IP, IP_MULTICAST_TTL, + &iapp->i_ttl, sizeof(iapp->i_ttl)) < 0) + hostapd_fatal("failed to set multicast ttl to " + "%u: %s\n", iapp->i_ttl, strerror(errno)); } } Index: hostapd.conf.5 ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/hostapd.conf.5,v retrieving revision 1.25 diff -u -p -r1.25 hostapd.conf.5 --- hostapd.conf.5 1 Dec 2005 08:28:58 -0000 1.25 +++ hostapd.conf.5 4 Dec 2005 08:06:48 -0000 @@ -157,6 +157,30 @@ messages. This option is enabled by default. .It Xo .Op Ic not +.Ic address roaming +.Aq Ar table +.Xc +Enable enable roaming of IP addresses. +After successful association of a station, +.Xr hostapd 8 +will lookup the station address in the table +.Aq Ar table +and configure any assigned IP address on the +.Em hostap interface . +Received +.Em ADD.notify +will trigger the deletion of the configured addresses, +it indicates that the station left the +.Em hostap . +This option allows the implementation of large wireless networks +without the need for sharing the same collision domain, if used in +combination with a routing daemon like +.Xr ospfd 8 +or +.Xr bgpd 8 . +It is disabled by default. +.It Xo +.Op Ic not .Ic radiotap .Xc Receive @@ -174,6 +198,7 @@ The supported modes are: .Ic multicast .Op Ic address Ar ipv4addr .Op Ic port Ar number +.Op Ic ttl Ar number .Xc Use multicast frames. .It Xo Index: hostapd.h ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/hostapd.h,v retrieving revision 1.14 diff -u -p -r1.14 hostapd.h --- hostapd.h 1 Dec 2005 02:03:58 -0000 1.14 +++ hostapd.h 4 Dec 2005 08:06:48 -0000 @@ -263,12 +263,20 @@ struct hostapd_iapp { struct sockaddr_in i_addr; struct sockaddr_in i_broadcast; struct sockaddr_in i_multicast; + u_int8_t i_ttl; u_int8_t i_flags; #define HOSTAPD_IAPP_F_ADD_NOTIFY 0x01 #define HOSTAPD_IAPP_F_RADIOTAP 0x02 +#define HOSTAPD_IAPP_F_ROAMING_ADDRESS 0x04 #define HOSTAPD_IAPP_F_DEFAULT \ (HOSTAPD_IAPP_F_ADD_NOTIFY | HOSTAPD_IAPP_F_RADIOTAP) +#define HOSTAPD_IAPP_F_ROAMING \ + (HOSTAPD_IAPP_F_ROAMING_ADDRESS) +#define HOSTAPD_IAPP_F_ADD \ + (HOSTAPD_IAPP_F_ADD_NOTIFY | HOSTAPD_IAPP_F_ROAMING) + + struct hostapd_table *i_addr_tbl; }; struct hostapd_config { @@ -277,6 +285,9 @@ struct hostapd_config { struct hostapd_iapp c_iapp; + int c_rtsock; + int c_rtseq; + u_int8_t c_flags; #define HOSTAPD_CFG_F_APME 0x01 @@ -354,6 +365,8 @@ int hostapd_priv_apme_getnode(struct ho struct hostapd_node *); int hostapd_priv_apme_setnode(struct hostapd_apme *, struct hostapd_node *node, int); +int hostapd_priv_roaming(struct hostapd_apme *, struct hostapd_node *, + int); void hostapd_apme_init(struct hostapd_apme *); int hostapd_apme_deauth(struct hostapd_apme *); @@ -385,6 +398,14 @@ int hostapd_llc_send_xid(struct hostapd int hostapd_handle_input(struct hostapd_apme *, u_int8_t *, u_int); void hostapd_print_ieee80211(u_int, u_int, u_int8_t *, u_int); + +void hostapd_roaming_init(struct hostapd_config *); +void hostapd_roaming_term(struct hostapd_apme *); +int hostapd_roaming(struct hostapd_apme *, struct hostapd_node *, int); +int hostapd_roaming_add(struct hostapd_apme *, + struct hostapd_node *node); +int hostapd_roaming_del(struct hostapd_apme *, + struct hostapd_node *node); __END_DECLS Index: iapp.c ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/iapp.c,v retrieving revision 1.13 diff -u -p -r1.13 iapp.c --- iapp.c 1 Dec 2005 02:03:58 -0000 1.13 +++ iapp.c 4 Dec 2005 08:06:48 -0000 @@ -258,17 +258,22 @@ hostapd_iapp_input(int fd, short sig, vo * any allocated resources. Otherwise the received * ADD.notify message will be ignored. */ - if (cfg->c_flags & HOSTAPD_CFG_F_APME) { + if (iapp->i_flags & HOSTAPD_IAPP_F_ADD && + cfg->c_flags & HOSTAPD_CFG_F_APME) { TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { - if ((ret = hostapd_apme_delnode(apme, + if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) + hostapd_roaming_del(apme, &node); + if (iapp->i_flags & HOSTAPD_IAPP_F_ADD_NOTIFY && + (ret = hostapd_apme_delnode(apme, &node)) == 0) cfg->c_stats.cn_tx_apme++; } } else ret = 0; - hostapd_log(HOSTAPD_LOG, "%s: %s ADD notification " - "for %s at %s\n", + hostapd_log(iapp->i_flags & HOSTAPD_IAPP_F_ADD ? + HOSTAPD_LOG : HOSTAPD_LOG_VERBOSE, + "%s: %s ADD notification for %s at %s\n", iapp->i_iface, ret == 0 ? "received" : "ignored", etheraddr_string(node.ni_macaddr), Index: parse.y ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/parse.y,v retrieving revision 1.17 diff -u -p -r1.17 parse.y --- parse.y 1 Dec 2005 02:03:58 -0000 1.17 +++ parse.y 4 Dec 2005 08:06:50 -0000 @@ -127,7 +127,7 @@ u_int negative; %token ERROR CONST TABLE NODE DELETE ADD LOG VERBOSE LIMIT QUICK SKIP %token REASON UNSPECIFIED EXPIRE LEAVE ASSOC TOOMANY NOT AUTHED ASSOCED %token RESERVED RSN REQUIRED INCONSISTENT IE INVALID MIC FAILURE OPEN -%token ADDRESS PORT ON NOTIFY +%token ADDRESS PORT ON NOTIFY ROAMING TTL %token <v.string> STRING %token <v.val> VALUE %type <v.val> number @@ -175,7 +175,7 @@ option : SET HOSTAP INTERFACE hostapifa | SET IAPP HANDLE SUBTYPE iappsubtypes ; -iappmode : MULTICAST iappmodeaddr iappmodeport +iappmode : MULTICAST iappmodeaddr iappmodeport iappmodettl { hostapd_cfg.c_flags &= ~HOSTAPD_CFG_F_BRDCAST; } @@ -200,6 +200,13 @@ iappmodeport : /* empty */ } ; +iappmodettl : /* empty */ + | TTL number + { + hostapd_cfg.c_iapp.i_ttl = $2; + } + ; + hostapmode : RADIOTAP { hostapd_cfg.c_apme_dlt = DLT_IEEE802_11_RADIO; @@ -283,6 +290,18 @@ iappsubtype : not ADD NOTIFY { HOSTAPD_IAPP_FLAG(RADIOTAP); } + | not ADDRESS ROAMING table + { + if ((hostapd_cfg.c_iapp.i_addr_tbl = + hostapd_table_lookup(&hostapd_cfg, $4)) == NULL) { + yyerror("undefined table <%s>", $4); + free($4); + YYERROR; + } + free($4); + + HOSTAPD_IAPP_FLAG(ROAMING_ADDRESS); + } ; eventopt : /* empty */ @@ -1018,6 +1037,7 @@ lookup(char *token) { "resend", RESEND }, { "reserved", RESERVED }, { "response", RESPONSE }, + { "roaming", ROAMING }, { "rsn", RSN }, { "sec", SEC }, { "set", SET }, @@ -1026,6 +1046,7 @@ lookup(char *token) { "table", TABLE }, { "to", TO }, { "toomany", TOOMANY }, + { "ttl", TTL }, { "type", TYPE }, { "unspecified", UNSPECIFIED }, { "usec", USEC }, @@ -1327,6 +1348,7 @@ hostapd_parse_file(struct hostapd_config TAILQ_INIT(&cfg->c_frames); cfg->c_iapp.i_multicast.sin_addr.s_addr = INADDR_ANY; cfg->c_iapp.i_flags = HOSTAPD_IAPP_F_DEFAULT; + cfg->c_iapp.i_ttl = IP_DEFAULT_MULTICAST_TTL; lineno = 1; errors = 0; Index: privsep.c ================================================== ================= RCS file: /cvs/src/usr.sbin/hostapd/privsep.c,v retrieving revision 1.16 diff -u -p -r1.16 privsep.c --- privsep.c 1 Dec 2005 01:11:30 -0000 1.16 +++ privsep.c 4 Dec 2005 08:06:50 -0000 @@ -57,6 +57,8 @@ enum hostapd_cmd_types { PRIV_APME_GETNODE, /* Get a node from the Host AP */ PRIV_APME_ADDNODE, /* Delete a node from the Host AP */ PRIV_APME_DELNODE, /* Delete a node from the Host AP */ + PRIV_APME_ADDROAMING, /* Add an address to the kernel */ + PRIV_APME_DELROAMING, /* Delete an address from the kernel */ PRIV_LLC_SEND_XID /* Send IEEE 802.3 LLC XID frame */ }; @@ -152,6 +154,9 @@ hostapd_priv_init(struct hostapd_config hostapd_fatal("unable to open ioctl socket\n"); } + /* Setup privileged kernel level IP roaming support */ + hostapd_roaming_init(cfg); + setproctitle("[priv]"); /* Start a new event listener */ @@ -193,7 +198,7 @@ hostapd_priv(int fd, short sig, void *ar struct ieee80211_nodereq nr; struct ifreq ifr; unsigned long request; - int ret, cmd; + int ret = 0, cmd; /* Terminate the event if we got an invalid signal */ if (sig != EV_READ) @@ -287,6 +292,19 @@ hostapd_priv(int fd, short sig, void *ar hostapd_must_write(fd, &ret, sizeof(int)); break; + case PRIV_APME_ADDROAMING: + case PRIV_APME_DELROAMING: + hostapd_log(HOSTAPD_LOG_DEBUG, + "[priv]: msg PRIV_APME_[ADD|DEL]ROAMING received\n"); + + hostapd_must_read(fd, &node, sizeof(struct hostapd_node)); + + if ((apme = hostapd_priv_getapme(fd, cfg)) == NULL) + break; + ret = hostapd_roaming(apme, &node, cmd == PRIV_APME_ADDROAMING); + hostapd_must_write(fd, &ret, sizeof(int)); + break; + default: hostapd_fatal("[priv]: unknown command %d\n", cmd); } @@ -393,6 +411,32 @@ hostapd_priv_llc_xid(struct hostapd_conf if (ret == 0) cfg->c_stats.cn_tx_llc++; + return (ret); +} + +int +hostapd_priv_roaming(struct hostapd_apme *apme, struct hostapd_node *node, + int add) +{ + struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; + int ret, cmd; + + if (priv_fd < 0) + hostapd_fatal("%s: called from privileged portion\n", __func__); + + if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) + hostapd_fatal("%s: Host AP is not available\n", __func__); + + if (add) + cmd = PRIV_APME_ADDROAMING; + else + cmd = PRIV_APME_DELROAMING; + hostapd_must_write(priv_fd, &cmd, sizeof(int)); + hostapd_must_write(priv_fd, node, sizeof(struct hostapd_node)); + hostapd_must_write(priv_fd, &apme->a_iface, IFNAMSIZ); + + hostapd_must_read(priv_fd, &ret, sizeof(int)); + return (ret); } Index: roaming.c ================================================== ================= RCS file: roaming.c diff -N roaming.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ roaming.c 4 Dec 2005 08:06:50 -0000 @@ -0,0 +1,278 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> + * + * 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/types.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/tree.h> +#include <sys/ioctl.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/route.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include "hostapd.h" + +int hostapd_roaming_addr(struct hostapd_apme *, struct hostapd_inaddr *, int); +int hostapd_roaming_route(struct hostapd_apme *, struct hostapd_inaddr *, + struct hostapd_inaddr *, int); + +void +hostapd_roaming_init(struct hostapd_config *cfg) +{ + struct hostapd_iapp *iapp = &cfg->c_iapp; + int v; + + if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0 || + (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) == 0) + return; + + /* Open a new routing socket, restricted to IPv4 traffic for now */ + if ((cfg->c_rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET)) == -1) + hostapd_fatal("failed to init inet socket: %s\n", + strerror(errno)); + + v = 0; + if (setsockopt(cfg->c_rtsock, SOL_SOCKET, SO_USELOOPBACK, + &v, sizeof(v)) == -1) + hostapd_fatal("failed to setup inet socket: %s\n", + strerror(errno)); +} + +void +hostapd_roaming_term(struct hostapd_apme *apme) +{ + struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; + struct hostapd_iapp *iapp = &cfg->c_iapp; + struct hostapd_entry *entry; + + if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING_ADDRESS && + iapp->i_addr_tbl != NULL) { + RB_FOREACH(entry, hostapd_tree, &iapp->i_addr_tbl->t_tree) { + if ((entry->e_flags & HOSTAPD_ENTRY_F_INADDR) == 0) + continue; + hostapd_roaming_addr(apme, &entry->e_inaddr, 0); + } + } +} + +int +hostapd_roaming(struct hostapd_apme *apme, struct hostapd_node *node, int add) +{ + struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; + struct hostapd_iapp *iapp = &cfg->c_iapp; + struct hostapd_entry *entry; + int ret; + + if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING_ADDRESS && + iapp->i_addr_tbl != NULL) { + if ((entry = hostapd_entry_lookup(iapp->i_addr_tbl, + node->ni_macaddr)) == NULL || + (entry->e_flags & HOSTAPD_ENTRY_F_INADDR) == 0) + return (ESRCH); + if ((ret = hostapd_roaming_addr(apme, &entry->e_inaddr, + add)) != 0) + return (ret); + } + + return (0); +} + + +int +hostapd_roaming_addr(struct hostapd_apme *apme, struct hostapd_inaddr *addr, + int add) +{ + struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; + struct hostapd_iapp *iapp = &cfg->c_iapp; + struct sockaddr_in *ifaddr, *ifmask, *ifbroadaddr; + struct ifaliasreq ifra; + + /* Delete any route to the address */ + hostapd_roaming_route(apme, addr, NULL, 0); + + bzero(&ifra, sizeof(ifra)); + + ifaddr = (struct sockaddr_in *)&ifra.ifra_addr; + ifaddr->sin_family = AF_INET; + ifaddr->sin_len = sizeof(struct sockaddr_in); + ifaddr->sin_addr.s_addr = addr->in_v4.s_addr; + + ifbroadaddr = (struct sockaddr_in *)&ifra.ifra_broadaddr; + ifbroadaddr->sin_family = AF_INET; + ifbroadaddr->sin_len = sizeof(struct sockaddr_in); + ifbroadaddr->sin_addr.s_addr = + addr->in_v4.s_addr | htonl(0xffffffffUL >> addr->in_netmask); + + if (add) { + ifmask = (struct sockaddr_in *)&ifra.ifra_mask; + ifmask->sin_family = AF_INET; + ifmask->sin_len = sizeof(struct sockaddr_in); + ifmask->sin_addr.s_addr = + htonl(0xffffffffUL << (32 - addr->in_netmask)); + } + + strlcpy(ifra.ifra_name, apme->a_iface, sizeof(ifra.ifra_name)); + if (ioctl(cfg->c_apme_ctl, SIOCDIFADDR, &ifra) < 0) { + if (errno != EADDRNOTAVAIL) { + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: failed to delete address %s\n", + apme->a_iface, iapp->i_iface, + inet_ntoa(addr->in_v4)); + return (errno); + } + } + if (add && ioctl(cfg->c_apme_ctl, SIOCAIFADDR, &ifra) < 0) { + if (errno != EEXIST) { + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: failed to add address %s\n", + apme->a_iface, iapp->i_iface, + inet_ntoa(addr->in_v4)); + return (errno); + } + } + + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: %s address %s\n", + apme->a_iface, iapp->i_iface, + add ? "added" : "deleted", + inet_ntoa(addr->in_v4)); + +#if 0 + if (add) { + /* Add direct route with label to the address */ + hostapd_roaming_route(apme, addr, addr, 1); + } +#endif + + return (0); +} + +int +hostapd_roaming_route(struct hostapd_apme *apme, struct hostapd_inaddr *addr, + struct hostapd_inaddr *gateway, int add) +{ + struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; + struct hostapd_iapp *iapp = &cfg->c_iapp; + struct { + struct rt_msghdr rm_hdr; + struct sockaddr_in rm_dst; + struct sockaddr_in rm_gateway; + struct sockaddr_in rm_netmask; + struct sockaddr_rtlabel rm_label; + } rm; + size_t len = sizeof(rm); + + bzero(&rm, len); + + rm.rm_hdr.rtm_msglen = len; + rm.rm_hdr.rtm_version = RTM_VERSION; + rm.rm_hdr.rtm_type = add ? RTM_CHANGE : RTM_DELETE; + rm.rm_hdr.rtm_flags = add ? (RTF_UP | RTF_DONE) : RTF_DONE; + rm.rm_hdr.rtm_seq = cfg->c_rtseq++; + rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_LABEL; + + rm.rm_dst.sin_family = AF_INET; + rm.rm_dst.sin_len = sizeof(rm.rm_dst); + if (addr->in_netmask) { + rm.rm_dst.sin_addr.s_addr = addr->in_v4.s_addr & + htonl(~(0xffffffffUL >> addr->in_netmask)); + } else + rm.rm_dst.sin_addr.s_addr = addr->in_v4.s_addr; + + rm.rm_hdr.rtm_addrs |= RTA_NETMASK; + rm.rm_netmask.sin_len = sizeof(rm.rm_netmask); + rm.rm_netmask.sin_family = AF_INET; + if (addr->in_netmask) + rm.rm_netmask.sin_addr.s_addr = + htonl(0xffffffffUL << (32 - addr->in_netmask)); + else if (addr->in_netmask < 0) + rm.rm_hdr.rtm_flags |= RTF_HOST; + + rm.rm_gateway.sin_family = AF_INET; + rm.rm_gateway.sin_len = sizeof(rm.rm_gateway); + if (add) { + rm.rm_gateway.sin_addr.s_addr = gateway->in_v4.s_addr; + + rm.rm_label.sr_len = sizeof(rm.rm_label); + snprintf(rm.rm_label.sr_label, sizeof(rm.rm_label.sr_label), + "apme-%s", apme->a_iface); + } + + retry: + if (write(cfg->c_rtsock, &rm, len) == -1) { + switch (errno) { + case ESRCH: + if (rm.rm_hdr.rtm_type == RTM_CHANGE) { + rm.rm_hdr.rtm_type = RTM_ADD; + goto retry; + } else if (rm.rm_hdr.rtm_type == RTM_DELETE) { + /* Ignore */ + break; + } + /* FALLTHROUGH */ + default: + goto bad; + } + } + + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: %s route to %s\n", + apme->a_iface, iapp->i_iface, + add ? "added" : "deleted", + inet_ntoa(addr->in_v4)); + + return (0); + + bad: + hostapd_log(HOSTAPD_LOG_VERBOSE, + "%s/%s: failed to %s route to %s: %s\n", + apme->a_iface, iapp->i_iface, + add ? "add" : "delete", + inet_ntoa(addr->in_v4), + strerror(errno)); + + return (ESRCH); +} + +int +hostapd_roaming_add(struct hostapd_apme *apme, struct hostapd_node *node) +{ + return (hostapd_priv_roaming(apme, node, 1)); +} + +int +hostapd_roaming_del(struct hostapd_apme *apme, struct hostapd_node *node) +{ + return (hostapd_priv_roaming(apme, node, 0)); +} |
| Thread Tools | |
| Display Modes | |
|
|