aboutsummaryrefslogtreecommitdiffstats
path: root/if-bsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'if-bsd.c')
-rw-r--r--if-bsd.c323
1 files changed, 246 insertions, 77 deletions
diff --git a/if-bsd.c b/if-bsd.c
index d0ff246..462ec2a 100644
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -25,44 +25,123 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
#include <arpa/inet.h>
+#include <net/if.h>
#include <net/if_dl.h>
-#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
+#ifdef __DragonFly__
+# include <netproto/802_11/ieee80211_ioctl.h>
+#elif __APPLE__
+ /* FIXME: Add apple includes so we can work out SSID */
+#else
+# include <net80211/ieee80211_ioctl.h>
+#endif
#include <errno.h>
+#include <fnmatch.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
+#include "configure.h"
#include "dhcp.h"
+#include "if-options.h"
#include "net.h"
-/* Darwin doesn't define this for some very odd reason */
-#ifndef SA_SIZE
-# define SA_SIZE(sa) \
- ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
- sizeof(long) : \
- 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+/* FIXME: Why do we need to check for sa_family 255 */
+#define COPYOUT(sin, sa) \
+ sin.s_addr = ((sa) != NULL) ? \
+ (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
+
+static int r_fd = -1;
+static char *link_buf;
+static ssize_t link_buflen;
+
+int
+if_init(_unused struct interface *iface)
+{
+ /* BSD promotes secondary address by default */
+ return 0;
+}
+
+int
+if_conf(_unused struct interface *iface)
+{
+ /* No extra checks needed on BSD */
+ return 0;
+}
+
+int
+init_sockets(void)
+{
+ if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ return -1;
+ set_cloexec(socket_afnet);
+ if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+ return -1;
+ set_cloexec(r_fd);
+ return 0;
+}
+
+int
+getifssid(const char *ifname, char *ssid)
+{
+ int retval = -1;
+#if defined(SIOCG80211NWID)
+ struct ifreq ifr;
+ struct ieee80211_nwid nwid;
+#elif defined(IEEE80211_IOC_SSID)
+ struct ieee80211req ireq;
+ char nwid[IEEE80211_NWID_LEN + 1];
#endif
+#if defined(SIOCG80211NWID) /* NetBSD */
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ memset(&nwid, 0, sizeof(nwid));
+ ifr.ifr_data = (void *)&nwid;
+ if (ioctl(socket_afnet, SIOCG80211NWID, &ifr) == 0) {
+ retval = nwid.i_len;
+ memcpy(ssid, nwid.i_nwid, nwid.i_len);
+ ssid[nwid.i_len] = '\0';
+ }
+#elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
+ memset(&ireq, 0, sizeof(ireq));
+ strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_SSID;
+ ireq.i_val = -1;
+ ireq.i_data = &nwid;
+ if (ioctl(socket_afnet, SIOCG80211, &ireq) == 0) {
+ retval = ireq.i_len;
+ memcpy(ssid, nwid, ireq.i_len);
+ ssid[ireq.i_len] = '\0';
+ }
+#endif
+ return retval;
+}
+
int
-if_address(const char *ifname, const struct in_addr *address,
- const struct in_addr *netmask, const struct in_addr *broadcast,
- int action)
+if_address(const struct interface *iface, const struct in_addr *address,
+ const struct in_addr *netmask, const struct in_addr *broadcast,
+ int action)
{
- int s;
int retval;
struct ifaliasreq ifa;
union {
@@ -70,39 +149,36 @@ if_address(const char *ifname, const struct in_addr *address,
struct sockaddr_in *sin;
} _s;
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
-
memset(&ifa, 0, sizeof(ifa));
- strlcpy(ifa.ifra_name, ifname, sizeof(ifa.ifra_name));
+ strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
-#define ADDADDR(_var, _addr) \
- _s.sa = &_var; \
- _s.sin->sin_family = AF_INET; \
- _s.sin->sin_len = sizeof(*_s.sin); \
- memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));
+#define ADDADDR(_var, _addr) { \
+ _s.sa = &_var; \
+ _s.sin->sin_family = AF_INET; \
+ _s.sin->sin_len = sizeof(*_s.sin); \
+ memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
+ }
ADDADDR(ifa.ifra_addr, address);
ADDADDR(ifa.ifra_mask, netmask);
- if (action >= 0) {
+ if (action >= 0 && broadcast) {
ADDADDR(ifa.ifra_broadaddr, broadcast);
}
#undef ADDADDR
if (action < 0)
- retval = ioctl(s, SIOCDIFADDR, &ifa);
+ retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
else
- retval = ioctl(s, SIOCAIFADDR, &ifa);
- close(s);
+ retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
return retval;
}
+/* ARGSUSED4 */
int
if_route(const struct interface *iface, const struct in_addr *dest,
- const struct in_addr *net, const struct in_addr *gate,
- _unused int metric, int action)
+ const struct in_addr *net, const struct in_addr *gate,
+ _unused int metric, int action)
{
- int s;
union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
@@ -121,21 +197,18 @@ if_route(const struct interface *iface, const struct in_addr *dest,
size_t l;
int retval = 0;
-#define ADDSU(_su) { \
- l = SA_SIZE(&(_su.sa)); \
- memcpy(bp, &(_su), l); \
- bp += l; \
-}
-#define ADDADDR(_addr) { \
- memset (&su, 0, sizeof(su)); \
- su.sin.sin_family = AF_INET; \
- su.sin.sin_len = sizeof(su.sin); \
- memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
- ADDSU(su); \
-}
-
- if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
- return -1;
+#define ADDSU(_su) { \
+ l = ROUNDUP(_su.sa.sa_len); \
+ memcpy(bp, &(_su), l); \
+ bp += l; \
+ }
+#define ADDADDR(_a) { \
+ memset (&su, 0, sizeof(su)); \
+ su.sin.sin_family = AF_INET; \
+ su.sin.sin_len = sizeof(su.sin); \
+ memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \
+ ADDSU(su); \
+ }
memset(&rtm, 0, sizeof(rtm));
rtm.hdr.rtm_version = RTM_VERSION;
@@ -194,41 +267,72 @@ if_route(const struct interface *iface, const struct in_addr *dest,
ADDADDR(&iface->addr);
rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
- if (write(s, &rtm, l) == -1)
+ if (write(r_fd, &rtm, l) == -1)
retval = -1;
- close(s);
return retval;
}
int
-open_link_socket(struct interface *iface)
+open_link_socket(void)
{
int fd;
fd = socket(PF_ROUTE, SOCK_RAW, 0);
- if (fd == -1)
- return -1;
- set_cloexec(fd);
- if (iface->link_fd != -1)
- close(iface->link_fd);
- iface->link_fd = fd;
- return 0;
+ if (fd != -1) {
+ set_cloexec(fd);
+ set_nonblock(fd);
+ }
+ return fd;
+}
+
+static void
+get_addrs(int type, char *cp, struct sockaddr **sa)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (type & (1 << i)) {
+ sa[i] = (struct sockaddr *)cp;
+#ifdef DEBUG
+ printf ("got %d %d %s\n", i, sa[i]->sa_family,
+ inet_ntoa(((struct sockaddr_in *)sa[i])->
+ sin_addr));
+#endif
+ ADVANCE(cp, sa[i]);
+ } else
+ sa[i] = NULL;
+ }
}
-#define BUFFER_LEN 2048
int
-link_changed(struct interface *iface)
+manage_link(int fd)
{
- char buffer[2048], *p;
+ char *p, *e, *cp;
+ char ifname[IF_NAMESIZE];
ssize_t bytes;
struct rt_msghdr *rtm;
+ struct if_announcemsghdr *ifan;
struct if_msghdr *ifm;
- int i;
+ struct ifa_msghdr *ifam;
+ struct rt rt;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ int len;
+#ifdef RTM_CHGADDR
+ struct sockaddr_dl sdl;
+ unsigned char *hwaddr;
+#endif
- if ((i = if_nametoindex(iface->name)) == -1)
- return -1;
for (;;) {
- bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
+ if (ioctl(fd, FIONREAD, &len) == -1)
+ return -1;
+ if (link_buflen < len) {
+ p = realloc(link_buf, len);
+ if (p == NULL)
+ return -1;
+ link_buf = p;
+ link_buflen = len;
+ }
+ bytes = read(fd, link_buf, link_buflen);
if (bytes == -1) {
if (errno == EAGAIN)
return 0;
@@ -236,20 +340,85 @@ link_changed(struct interface *iface)
continue;
return -1;
}
- for (p = buffer; bytes > 0;
- bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
- p += ((struct rt_msghdr *)p)->rtm_msglen)
- {
- rtm = (struct rt_msghdr *)p;
- if (rtm->rtm_type != RTM_IFINFO)
- continue;
- ifm = (struct if_msghdr *)p;
- if (ifm->ifm_index != i)
- continue;
-
- /* Link changed */
- return 1;
+ e = link_buf + bytes;
+ for (p = link_buf; p < e; p += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)p;
+ switch(rtm->rtm_type) {
+#ifdef RTM_IFANNOUNCE
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *)(void *)p;
+ switch(ifan->ifan_what) {
+ case IFAN_ARRIVAL:
+ handle_interface(1, ifan->ifan_name);
+ break;
+ case IFAN_DEPARTURE:
+ handle_interface(-1, ifan->ifan_name);
+ break;
+ }
+ break;
+#endif
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)(void *)p;
+ memset(ifname, 0, sizeof(ifname));
+ if (if_indextoname(ifm->ifm_index, ifname))
+ handle_interface(0, ifname);
+ break;
+ case RTM_DELETE:
+ if (!(rtm->rtm_addrs & RTA_DST) ||
+ !(rtm->rtm_addrs & RTA_GATEWAY) ||
+ !(rtm->rtm_addrs & RTA_NETMASK))
+ break;
+ if (rtm->rtm_pid == getpid())
+ break;
+ cp = (char *)(void *)(rtm + 1);
+ sa = (struct sockaddr *)(void *)cp;
+ if (sa->sa_family != AF_INET)
+ break;
+ get_addrs(rtm->rtm_addrs, cp, rti_info);
+ rt.iface = NULL;
+ rt.next = NULL;
+ COPYOUT(rt.dest, rti_info[RTAX_DST]);
+ COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+ COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
+ route_deleted(&rt);
+ break;
+#ifdef RTM_CHGADDR
+ case RTM_CHGADDR: /* FALLTHROUGH */
+#endif
+ case RTM_DELADDR: /* FALLTHROUGH */
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)(void *)p;
+ if (!if_indextoname(ifam->ifam_index, ifname))
+ break;
+ cp = (char *)(void *)(ifam + 1);
+ get_addrs(ifam->ifam_addrs, cp, rti_info);
+ if (rti_info[RTAX_IFA] == NULL)
+ break;
+ switch (rti_info[RTAX_IFA]->sa_family) {
+#ifdef RTM_CHGADDR
+ case AF_LINK:
+ if (rtm->rtm_type != RTM_CHGADDR)
+ break;
+ memcpy(&sdl, rti_info[RTAX_IFA],
+ rti_info[RTAX_IFA]->sa_len);
+ hwaddr = xmalloc(sdl.sdl_alen);
+ memcpy(hwaddr, LLADDR(&sdl),
+ sdl.sdl_alen);
+ handle_hwaddr(ifname, hwaddr,
+ sdl.sdl_alen);
+ break;
+#endif
+ case AF_INET:
+ case 255: /* FIXME: Why 255? */
+ COPYOUT(rt.dest, rti_info[RTAX_IFA]);
+ COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+ COPYOUT(rt.gate, rti_info[RTAX_BRD]);
+ handle_ifa(rtm->rtm_type, ifname,
+ &rt.dest, &rt.net, &rt.gate);
+ break;
+ }
+ break;
+ }
}
}
- return 0;
}