diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | package/deps.mak | 14 | ||||
-rw-r--r-- | package/modes | 2 | ||||
-rw-r--r-- | package/targets.mak | 5 | ||||
-rw-r--r-- | src/include/bcnm/bcnm.h | 16 | ||||
-rw-r--r-- | src/include/bcnm/if.h | 22 | ||||
-rw-r--r-- | src/libbcnm/bcnm_if_getstate.c | 30 | ||||
-rw-r--r-- | src/libbcnm/bcnm_if_link_event.c | 77 | ||||
-rw-r--r-- | src/libbcnm/bcnm_if_link_init.c | 38 | ||||
-rw-r--r-- | src/libbcnm/deps-lib/bcnm | 3 | ||||
-rw-r--r-- | src/utils/bcnm-waitif.c | 91 |
11 files changed, 296 insertions, 3 deletions
@@ -7,3 +7,4 @@ *.so.xyzzy config.mak src/include/bcnm/config.h +bcnm-waitif diff --git a/package/deps.mak b/package/deps.mak index 26807a4..c77018a 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -2,7 +2,11 @@ # This file has been generated by tools/gen-deps.sh # +src/include/bcnm/bcnm.h: src/include/bcnm/if.h src/libwpactrl/wpactrl-internal.h: src/include/bcnm/wpactrl.h +src/libbcnm/bcnm_if_getstate.o src/libbcnm/bcnm_if_getstate.lo: src/libbcnm/bcnm_if_getstate.c src/include/bcnm/if.h +src/libbcnm/bcnm_if_link_event.o src/libbcnm/bcnm_if_link_event.lo: src/libbcnm/bcnm_if_link_event.c src/include/bcnm/if.h +src/libbcnm/bcnm_if_link_init.o src/libbcnm/bcnm_if_link_init.lo: src/libbcnm/bcnm_if_link_init.c src/include/bcnm/if.h src/libwpactrl/wpactrl_ackmsg.o src/libwpactrl/wpactrl_ackmsg.lo: src/libwpactrl/wpactrl_ackmsg.c src/include/bcnm/wpactrl.h src/libwpactrl/wpactrl_addnetwork.o src/libwpactrl/wpactrl_addnetwork.lo: src/libwpactrl/wpactrl_addnetwork.c src/include/bcnm/wpactrl.h src/libwpactrl/wpactrl_associate.o src/libwpactrl/wpactrl_associate.lo: src/libwpactrl/wpactrl_associate.c src/include/bcnm/wpactrl.h @@ -38,11 +42,21 @@ src/libwpactrl/wpactrl_xchg_start.o src/libwpactrl/wpactrl_xchg_start.lo: src/li src/libwpactrl/wpactrl_xchg_timeout.o src/libwpactrl/wpactrl_xchg_timeout.lo: src/libwpactrl/wpactrl_xchg_timeout.c src/include/bcnm/wpactrl.h src/libwpactrl/wpactrl_xchg_zero.o src/libwpactrl/wpactrl_xchg_zero.lo: src/libwpactrl/wpactrl_xchg_zero.c src/include/bcnm/wpactrl.h src/libwpactrl/wpactrl_zero.o src/libwpactrl/wpactrl_zero.lo: src/libwpactrl/wpactrl_zero.c src/include/bcnm/wpactrl.h +src/utils/bcnm-waitif.o src/utils/bcnm-waitif.lo: src/utils/bcnm-waitif.c src/include/bcnm/if.h ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) +libbcnm.a.xyzzy: src/libbcnm/bcnm_if_getstate.o src/libbcnm/bcnm_if_link_init.o src/libbcnm/bcnm_if_link_event.o +else +libbcnm.a.xyzzy: src/libbcnm/bcnm_if_getstate.lo src/libbcnm/bcnm_if_link_init.lo src/libbcnm/bcnm_if_link_event.lo +endif +libbcnm.so.xyzzy: EXTRA_LIBS := +libbcnm.so.xyzzy: src/libbcnm/bcnm_if_getstate.lo src/libbcnm/bcnm_if_link_init.lo src/libbcnm/bcnm_if_link_event.lo +ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) libwpactrl.a.xyzzy: src/libwpactrl/wpactrl_ackmsg.o src/libwpactrl/wpactrl_addnetwork.o src/libwpactrl/wpactrl_associate.o src/libwpactrl/wpactrl_bssid_scan.o src/libwpactrl/wpactrl_command.o src/libwpactrl/wpactrl_end.o src/libwpactrl/wpactrl_env_parse.o src/libwpactrl/wpactrl_fd_recv.o src/libwpactrl/wpactrl_fd_timed_recv.o src/libwpactrl/wpactrl_filter_add.o src/libwpactrl/wpactrl_filter_exact_search.o src/libwpactrl/wpactrl_filter_match.o src/libwpactrl/wpactrl_filter_remove.o src/libwpactrl/wpactrl_findnetwork.o src/libwpactrl/wpactrl_flags_scan.o src/libwpactrl/wpactrl_msg.o src/libwpactrl/wpactrl_networks_parse.o src/libwpactrl/wpactrl_query.o src/libwpactrl/wpactrl_querysa.o src/libwpactrl/wpactrl_removenetwork.o src/libwpactrl/wpactrl_scan_parse.o src/libwpactrl/wpactrl_selectnetwork.o src/libwpactrl/wpactrl_setnetworkoption.o src/libwpactrl/wpactrl_start.o src/libwpactrl/wpactrl_startscan.o src/libwpactrl/wpactrl_update.o src/libwpactrl/wpactrl_xchg_cbres_free.o src/libwpactrl/wpactrl_xchg_cbres_zero.o src/libwpactrl/wpactrl_xchg_computedeadline.o src/libwpactrl/wpactrl_xchg_event.o src/libwpactrl/wpactrl_xchg_init.o src/libwpactrl/wpactrl_xchg_start.o src/libwpactrl/wpactrl_xchg_timeout.o src/libwpactrl/wpactrl_xchg_zero.o src/libwpactrl/wpactrl_zero.o else libwpactrl.a.xyzzy: src/libwpactrl/wpactrl_ackmsg.lo src/libwpactrl/wpactrl_addnetwork.lo src/libwpactrl/wpactrl_associate.lo src/libwpactrl/wpactrl_bssid_scan.lo src/libwpactrl/wpactrl_command.lo src/libwpactrl/wpactrl_end.lo src/libwpactrl/wpactrl_env_parse.lo src/libwpactrl/wpactrl_fd_recv.lo src/libwpactrl/wpactrl_fd_timed_recv.lo src/libwpactrl/wpactrl_filter_add.lo src/libwpactrl/wpactrl_filter_exact_search.lo src/libwpactrl/wpactrl_filter_match.lo src/libwpactrl/wpactrl_filter_remove.lo src/libwpactrl/wpactrl_findnetwork.lo src/libwpactrl/wpactrl_flags_scan.lo src/libwpactrl/wpactrl_msg.lo src/libwpactrl/wpactrl_networks_parse.lo src/libwpactrl/wpactrl_query.lo src/libwpactrl/wpactrl_querysa.lo src/libwpactrl/wpactrl_removenetwork.lo src/libwpactrl/wpactrl_scan_parse.lo src/libwpactrl/wpactrl_selectnetwork.lo src/libwpactrl/wpactrl_setnetworkoption.lo src/libwpactrl/wpactrl_start.lo src/libwpactrl/wpactrl_startscan.lo src/libwpactrl/wpactrl_update.lo src/libwpactrl/wpactrl_xchg_cbres_free.lo src/libwpactrl/wpactrl_xchg_cbres_zero.lo src/libwpactrl/wpactrl_xchg_computedeadline.lo src/libwpactrl/wpactrl_xchg_event.lo src/libwpactrl/wpactrl_xchg_init.lo src/libwpactrl/wpactrl_xchg_start.lo src/libwpactrl/wpactrl_xchg_timeout.lo src/libwpactrl/wpactrl_xchg_zero.lo src/libwpactrl/wpactrl_zero.lo endif libwpactrl.so.xyzzy: EXTRA_LIBS := libwpactrl.so.xyzzy: src/libwpactrl/wpactrl_ackmsg.lo src/libwpactrl/wpactrl_addnetwork.lo src/libwpactrl/wpactrl_associate.lo src/libwpactrl/wpactrl_bssid_scan.lo src/libwpactrl/wpactrl_command.lo src/libwpactrl/wpactrl_end.lo src/libwpactrl/wpactrl_env_parse.lo src/libwpactrl/wpactrl_fd_recv.lo src/libwpactrl/wpactrl_fd_timed_recv.lo src/libwpactrl/wpactrl_filter_add.lo src/libwpactrl/wpactrl_filter_exact_search.lo src/libwpactrl/wpactrl_filter_match.lo src/libwpactrl/wpactrl_filter_remove.lo src/libwpactrl/wpactrl_findnetwork.lo src/libwpactrl/wpactrl_flags_scan.lo src/libwpactrl/wpactrl_msg.lo src/libwpactrl/wpactrl_networks_parse.lo src/libwpactrl/wpactrl_query.lo src/libwpactrl/wpactrl_querysa.lo src/libwpactrl/wpactrl_removenetwork.lo src/libwpactrl/wpactrl_scan_parse.lo src/libwpactrl/wpactrl_selectnetwork.lo src/libwpactrl/wpactrl_setnetworkoption.lo src/libwpactrl/wpactrl_start.lo src/libwpactrl/wpactrl_startscan.lo src/libwpactrl/wpactrl_update.lo src/libwpactrl/wpactrl_xchg_cbres_free.lo src/libwpactrl/wpactrl_xchg_cbres_zero.lo src/libwpactrl/wpactrl_xchg_computedeadline.lo src/libwpactrl/wpactrl_xchg_event.lo src/libwpactrl/wpactrl_xchg_init.lo src/libwpactrl/wpactrl_xchg_start.lo src/libwpactrl/wpactrl_xchg_timeout.lo src/libwpactrl/wpactrl_xchg_zero.lo src/libwpactrl/wpactrl_zero.lo +bcnm-waitif: EXTRA_LIBS := -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} +bcnm-waitif: src/utils/bcnm-waitif.o libbcnm.a.xyzzy diff --git a/package/modes b/package/modes index 8b13789..25814dd 100644 --- a/package/modes +++ b/package/modes @@ -1 +1 @@ - +bcnm-waitif 0755 diff --git a/package/targets.mak b/package/targets.mak index ebc5af6..9d63078 100644 --- a/package/targets.mak +++ b/package/targets.mak @@ -1,5 +1,6 @@ -BIN_TARGETS := +BIN_TARGETS := \ +bcnm-waitif LIBEXEC_TARGETS := -LIB_DEFS := WPACTRL=wpactrl +LIB_DEFS := BCNM=bcnm WPACTRL=wpactrl diff --git a/src/include/bcnm/bcnm.h b/src/include/bcnm/bcnm.h new file mode 100644 index 0000000..f3d5bf2 --- /dev/null +++ b/src/include/bcnm/bcnm.h @@ -0,0 +1,16 @@ +/* ISC license. */ + +#ifndef BCNM_BCNM_H +#define BCNM_BCNM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <bcnm/if.h> + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/bcnm/if.h b/src/include/bcnm/if.h new file mode 100644 index 0000000..c4217ab --- /dev/null +++ b/src/include/bcnm/if.h @@ -0,0 +1,22 @@ +/* ISC license. */ + +#ifndef BCNM_IF_H +#define BCNM_IF_H + +#include <sys/types.h> +#include <net/if.h> + +typedef struct bcnm_if_link_state_s bcnm_if_link_state_t, *bcnm_if_link_state_t_ref ; +struct bcnm_if_link_state_s +{ + char ifname[IF_NAMESIZE] ; + unsigned int state : 15 ; + unsigned int changed : 1 ; +} ; +#define BCNM_IF_LINK_STATE_ZERO { "", 0, 0 } + +extern int bcnm_if_getstate (char const *) ; +extern int bcnm_if_link_init (unsigned int) ; +extern ssize_t bcnm_if_link_event (int, bcnm_if_link_state_t *, size_t) ; + +#endif diff --git a/src/libbcnm/bcnm_if_getstate.c b/src/libbcnm/bcnm_if_getstate.c new file mode 100644 index 0000000..af50268 --- /dev/null +++ b/src/libbcnm/bcnm_if_getstate.c @@ -0,0 +1,30 @@ +/* ISC license. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <bcnm/if.h> + +int bcnm_if_getstate (char const *ifname) +{ + struct ifreq blah ; + int sfd ; + int e = errno ; + size_t len = strlen(ifname) ; + if (len >= IFNAMSIZ) return (errno = ENAMETOOLONG, -1) ; + memcpy(blah.ifr_name, ifname, len+1) ; + sfd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0) ; + if (sfd < 0) return -1 ; + if (ioctl(sfd, SIOCGIFFLAGS, &blah) < 0) + return errno == ENODEV ? (errno = e, 0) : -1 ; + close(sfd) ; + return 1 | !!(blah.ifr_flags & IFF_UP) << 1 | !!(blah.ifr_flags & IFF_RUNNING) << 2 ; +} diff --git a/src/libbcnm/bcnm_if_link_event.c b/src/libbcnm/bcnm_if_link_event.c new file mode 100644 index 0000000..fd7157a --- /dev/null +++ b/src/libbcnm/bcnm_if_link_event.c @@ -0,0 +1,77 @@ +/* ISC license. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <string.h> +#include <errno.h> +#include <net/if.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include <bcnm/if.h> + +static inline ssize_t fd_recvmsg_nb (int fd, struct msghdr *hdr) +{ + int e = errno ; + ssize_t r ; + do r = recvmsg(fd, hdr, MSG_DONTWAIT) ; + while (r == -1 && errno == EINTR) ; + if (r == -1 && errno == EWOULDBLOCK) return (errno = e, 0) ; + if (!r) return (errno = EPIPE, -1) ; + return r ; +} + +static int answer (bcnm_if_link_state_t *tab, size_t n, char const *ifname, unsigned int state) +{ + size_t i = 0 ; + for (; i < n ; i++) if (!strcmp(ifname, tab[i].ifname)) break ; + if (i >= n) return 0 ; + tab[i].state = state ; + tab[i].changed = 1 ; + return 1 ; +} + +ssize_t bcnm_if_link_event (int fd, bcnm_if_link_state_t *tab, size_t n) +{ + ssize_t e = 0 ; + struct sockaddr_nl nl ; + struct nlmsghdr buf[8192 / sizeof(struct nlmsghdr)] ; + struct iovec v = { .iov_base = buf, .iov_len = sizeof(struct nlmsghdr) * (8192 / sizeof(struct nlmsghdr)) } ; + struct msghdr msg = + { + .msg_name = &nl, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = &v, + .msg_iovlen = 1, + .msg_control = 0, + .msg_controllen = 0, + .msg_flags = 0 + } ; + ssize_t r = fd_recvmsg_nb(fd, &msg) ; + if (r <= 0) return r ; + if (msg.msg_flags & MSG_TRUNC) return (errno = ENOBUFS, -1) ; + if (nl.nl_pid) return (errno = EPROTO, -1) ; + for (struct nlmsghdr *hdr = buf ; NLMSG_OK(hdr, r) ; hdr = NLMSG_NEXT(hdr, r)) + { + struct ifinfomsg *ifi = NLMSG_DATA(hdr) ; + char ifname[IF_NAMESIZE] ; + switch (hdr->nlmsg_type) + { + case NLMSG_DONE : goto out ; + case NLMSG_ERROR : return (errno = EPROTO, -1) ; + case RTM_DELLINK : + if_indextoname(ifi->ifi_index, ifname) ; + e += answer(tab, n, ifname, 0) ; + break ; + case RTM_NEWLINK : + if_indextoname(ifi->ifi_index, ifname) ; + e += answer(tab, n, ifname, 1 | !!(ifi->ifi_flags & IFF_UP) << 1 | !!(ifi->ifi_flags & IFF_RUNNING) << 2) ; + break ; + } + } + out: + return e ; +} diff --git a/src/libbcnm/bcnm_if_link_init.c b/src/libbcnm/bcnm_if_link_init.c new file mode 100644 index 0000000..dad93fd --- /dev/null +++ b/src/libbcnm/bcnm_if_link_init.c @@ -0,0 +1,38 @@ +/* ISC license. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <unistd.h> +#include <errno.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include <bcnm/if.h> + +int bcnm_if_link_init (unsigned int kbufsz) +{ + struct sockaddr_nl nl = + { + .nl_family = AF_NETLINK, + .nl_pad = 0, + .nl_groups = RTNLGRP_LINK, + .nl_pid = 0 + } ; + int fd = socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE) ; + if (fd < 0) return -1 ; + if (bind(fd, (struct sockaddr *)&nl, sizeof(struct sockaddr_nl)) < 0) goto err ; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &kbufsz, sizeof(unsigned int)) < 0) + { + if (errno != EPERM + || setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &kbufsz, sizeof(unsigned int)) < 0) goto err ; + } + return fd ; + + err: + close(fd) ; + return -1 ; +} + diff --git a/src/libbcnm/deps-lib/bcnm b/src/libbcnm/deps-lib/bcnm new file mode 100644 index 0000000..3e3bada --- /dev/null +++ b/src/libbcnm/deps-lib/bcnm @@ -0,0 +1,3 @@ +bcnm_if_getstate.o +bcnm_if_link_init.o +bcnm_if_link_event.o diff --git a/src/utils/bcnm-waitif.c b/src/utils/bcnm-waitif.c new file mode 100644 index 0000000..c5fd556 --- /dev/null +++ b/src/utils/bcnm-waitif.c @@ -0,0 +1,91 @@ +/* ISC license. */ + +#include <string.h> +#include <net/if.h> + +#include <skalibs/strerr2.h> +#include <skalibs/sgetopt.h> +#include <skalibs/types.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> + +#include <bcnm/if.h> + +#define USAGE "bcnm-waitif [ -u | -d ] [ -t timeout ] [ -k kbufsize ] mask interface..." +#define dieusage() strerr_dieusage(100, USAGE) + +static inline int check (bcnm_if_link_state_t *tab, size_t n, unsigned int mask, int not) +{ + size_t i = 0 ; + for (; i < n ; i++) + if ((tab[i].state & mask) != (not ? 0 : mask)) return 0 ; + return 1 ; +} + +int main (int argc, char const *const *argv) +{ + iopause_fd x = { .events = IOPAUSE_READ } ; + tain_t deadline, tto ; + int not = 0 ; + unsigned int mask = 1 ; + unsigned int kbufsize = 131072 ; + PROG = "bcnm-waitif" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "udt:k:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'u' : not = 0 ; break ; + case 'd' : not = 1 ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'k' : if (!uint0_scan(l.arg, &kbufsize)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&tto, t) ; + else tto = tain_infinite_relative ; + } + if (argc < 2) dieusage() ; + if (!uint0_scan(*argv++, &mask)) + strerr_dief2x(100, "invalid mask: ", argv[-1]) ; + + x.fd = bcnm_if_link_init(kbufsize) ; + if (x.fd < 0) strerr_diefu1sys(111, "bcnm_if_link_init") ; + + tain_now_set_stopwatch_g() ; + tain_add_g(&deadline, &tto) ; + + { + size_t n = --argc ; + bcnm_if_link_state_t tab[n] ; + for (size_t i = 0 ; i < n ; i++) + { + int r ; + size_t len = strlen(argv[i]) ; + if (len >= IF_NAMESIZE - 1) + strerr_dief2x(100, "interface name too long: ", argv[i]) ; + memcpy(tab[i].ifname, argv[i], len+1) ; + tab[i].changed = 0 ; + r = bcnm_if_getstate(argv[i]) ; + if (r < 0) strerr_diefu2sys(111, "get state for interface ", argv[i]) ; + tab[i].state = r ; + } + + for (;;) + { + int r ; + if (check(tab, n, mask, not)) return 0 ; + r = iopause_g(&x, 1, &deadline) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + if (!r) strerr_dief1x(99, "timed out") ; + if (bcnm_if_link_event(x.fd, tab, n) < 0) + strerr_diefu1sys(111, "read rtnetlink event") ; + } + } + return 0 ; +} |