}
free(ctx.ifaces);
}
+ if (ctx.oifaces) {
+ while ((ifp = TAILQ_FIRST(ctx.oifaces))) {
+ TAILQ_REMOVE(ctx.oifaces, ifp, next);
+ if_free(ifp);
+ }
+ free(ctx.oifaces);
+ }
free(ctx.duid);
if (ctx.link_fd != -1) {
eloop_event_delete(ctx.eloop, ctx.link_fd);
unsigned char *duid;
size_t duid_len;
struct if_head *ifaces;
+ struct if_head *oifaces; /* interfaces not directly controlled */
int pf_inet_fd;
#if defined(INET6) && defined(BSD)
# include <net80211/ieee80211_ioctl.h>
#endif
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
if (rtm->rtm_inits & RTV_MTU)
rt->mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
- if (rtm->rtm_index)
+ if (rtm->rtm_index) {
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
- else if (rtm->rtm_addrs & RTA_IFP) {
+ if (rt->iface == NULL)
+ rt->iface = if_newoif(ctx, rtm->rtm_index);
+ } else if (rtm->rtm_addrs & RTA_IFP) {
struct sockaddr_dl *sdl;
sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
rt->iface = ia->iface;
}
+ assert(rt->iface != NULL);
+
return 0;
}
if (rtm->rtm_inits & RTV_MTU)
rt->mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
- if (rtm->rtm_index)
+ if (rtm->rtm_index) {
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
- else if (rtm->rtm_addrs & RTA_IFP) {
+ if (rt->iface == NULL)
+ rt->iface = if_newoif(ctx, rtm->rtm_index);
+ } else if (rtm->rtm_addrs & RTA_IFP) {
struct sockaddr_dl *sdl;
sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
rt->iface = ia->iface;
}
+ assert(rt->iface != NULL);
+
return 0;
}
#include <netinet/in.h>
#include <net/route.h>
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
size_t len;
struct rtmsg *rtm;
struct rtattr *rta;
+ unsigned int ifindex;
len = nlm->nlmsg_len - sizeof(*nlm);
if (len < sizeof(*rtm)) {
rta = (struct rtattr *)RTM_RTA(rtm);
len = RTM_PAYLOAD(nlm);
+ ifindex = 0;
while (RTA_OK(rta, len)) {
switch (rta->rta_type) {
case RTA_DST:
sizeof(rt->src.s_addr));
break;
case RTA_OIF:
- rt->iface = if_findindex(ctx->ifaces,
- *(unsigned int *)RTA_DATA(rta));
+ ifindex = *(unsigned int *)RTA_DATA(rta);
+ rt->iface = if_findindex(ctx->ifaces, ifindex);
break;
case RTA_PRIORITY:
rt->metric = *(unsigned int *)RTA_DATA(rta);
if ((ap = ipv4_findaddr(ctx, &rt->src)))
rt->iface = ap->iface;
}
+ /* If we still don't have an interface, create a temporary one */
+ if (rt->iface == NULL) {
+ rt->iface = if_newoif(ctx, ifindex);
+ assert(rt->iface != NULL);
+ }
return 0;
}
#endif
size_t len;
struct rtmsg *rtm;
struct rtattr *rta;
+ unsigned int ifindex;
len = nlm->nlmsg_len - sizeof(*nlm);
if (len < sizeof(*rtm)) {
sizeof(rt->gate.s6_addr));
break;
case RTA_OIF:
- rt->iface = if_findindex(ctx->ifaces,
- *(unsigned int *)RTA_DATA(rta));
+ ifindex = *(unsigned int *)RTA_DATA(rta);
+ rt->iface = if_findindex(ctx->ifaces, ifindex);
+ if (rt->iface == NULL)
+ rt->iface = if_newoif(ctx, ifindex);
break;
case RTA_PRIORITY:
rt->metric = *(unsigned int *)RTA_DATA(rta);
rta = RTA_NEXT(rta, len);
}
+ assert(rt->iface != NULL);
return 0;
}
#endif
if (rt->gate.s_addr != htonl(INADDR_ANY))
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
&rt->gate.s_addr, sizeof(rt->gate.s_addr));
- if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
- add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF,
- rt->iface->index);
if (subnet != -1) {
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
&src_addr.s_addr, sizeof(src_addr.s_addr));
}
}
+ if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
+ add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
+
if (rt->metric)
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
return if_findindexname(ifaces, idx, NULL);
}
+/* Creates a new interface just for handling route messages to the kernel
+ * if we ever need to change a route on an interface dhcpcd is NOT running on. */
+struct interface *
+if_newoif(struct dhcpcd_ctx *ctx, unsigned int idx)
+{
+ struct interface *ifp;
+
+ if (ctx->oifaces == NULL) {
+ if ((ctx->oifaces = malloc(sizeof(*ctx->oifaces))) == NULL) {
+ logger(ctx, LOG_ERR, "%s: malloc: %m", __func__);
+ return NULL;
+ }
+ TAILQ_INIT(ctx->oifaces);
+ } else {
+ TAILQ_FOREACH(ifp, ctx->oifaces, next) {
+ if (ifp->index == idx)
+ return ifp;
+ }
+ }
+
+ if ((ifp = calloc(1, sizeof(*ifp))) == NULL) {
+ logger(ctx, LOG_ERR, "%s: calloc: %m", __func__);
+ return NULL;
+ }
+
+ if (if_indextoname(idx, ifp->name) == NULL) {
+ logger(ctx, LOG_ERR, "%s: if_indextoname: %m", __func__);
+ free(ifp);
+ return NULL;
+ }
+
+ ifp->ctx = ctx;
+ ifp->index = idx;
+ TAILQ_INSERT_TAIL(ctx->oifaces, ifp, next);
+ return ifp;
+}
+
int
if_domtu(const struct interface *ifp, short int mtu)
{
/* The below functions are provided by if-KERNEL.c */
int if_conf(struct interface *);
int if_init(struct interface *);
+struct interface *if_newoif(struct dhcpcd_ctx *, unsigned int);
int if_getssid(struct interface *);
int if_vimaster(const struct dhcpcd_ctx *ctx, const char *);
int if_opensockets(struct dhcpcd_ctx *);
logger(nrt->iface->ctx, LOG_ERR, "if_route (CHG): %m");
}
- /* If the old route does not have an interface, give it the
- * interface of the new route for context. */
- if (ort && ort->iface == NULL)
- ort->iface = nrt->iface;
-
#ifdef HAVE_ROUTE_METRIC
/* With route metrics, we can safely add the new route before
* deleting the old route. */
logger(nrt->iface->ctx, LOG_ERR, "if_route6 (CHG): %m");
}
- /* If the old route does not have an interface, give it the
- * interface of the new route for context. */
- if (ort && ort->iface == NULL)
- ort->iface = nrt->iface;
-
#ifdef HAVE_ROUTE_METRIC
/* With route metrics, we can safely add the new route before
* deleting the old route. */