return 0;
}
+static int
+get_option_uint16(struct dhcpcd_ctx *ctx,
+ uint16_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+ const uint8_t *p;
+ size_t len;
+ uint16_t d;
+
+ p = get_option(ctx, dhcp, option, &len);
+ if (!p || len < (ssize_t)sizeof(d))
+ return -1;
+ memcpy(&d, p, sizeof(d));
+ if (i)
+ *i = ntohs(d);
+ return 0;
+}
+
static int
get_option_uint8(struct dhcpcd_ctx *ctx,
uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
/* We need to obey routing options.
* If we have a CSR then we only use that.
* Otherwise we add static routes and then routers. */
-struct rt_head *
+static struct rt_head *
get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
{
struct if_options *ifo = ifp->options;
return routes;
}
+uint16_t
+dhcp_get_mtu(const struct interface *ifp)
+{
+ const struct dhcp_message *dhcp;
+ uint16_t mtu;
+
+ if ((dhcp = D_CSTATE(ifp)->new) == NULL ||
+ has_option_mask(ifp->options->nomask, DHO_MTU) ||
+ get_option_uint16(ifp->ctx, &mtu, dhcp, DHO_MTU) == -1)
+ return 0;
+ return mtu;
+}
+
+/* Grab our routers from the DHCP message and apply any MTU value
+ * the message contains */
+struct rt_head *
+dhcp_get_routes(struct interface *ifp)
+{
+ struct rt_head *routes;
+ uint16_t mtu;
+ const struct dhcp_message *dhcp;
+
+ dhcp = D_CSTATE(ifp)->new;
+ routes = get_option_routes(ifp, dhcp);
+ if ((mtu = dhcp_get_mtu(ifp)) != 0) {
+ struct rt *rt;
+
+ TAILQ_FOREACH(rt, routes, next) {
+ rt->mtu = mtu;
+ }
+ }
+ return routes;
+}
+
#define PUTADDR(_type, _val) \
{ \
*p++ = _type; \
const struct dhcp_message *, uint8_t);
#define IS_BOOTP(i, m) ((m) != NULL && \
get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
-struct rt_head *get_option_routes(struct interface *,
- const struct dhcp_message *);
+uint16_t dhcp_get_mtu(const struct interface *);
+struct rt_head *dhcp_get_routes(struct interface *);
ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
const struct interface *);
+++ /dev/null
-# Configure the MTU for the interface
-
-mtu_dir="$state_dir/mtu"
-
-set_mtu()
-{
- local mtu=$1
-
- if [ -w /sys/class/net/$interface/mtu ]; then
- echo "$mtu" >/sys/class/net/$interface/mtu
- else
- ifconfig "$interface" mtu "$mtu"
- fi
-}
-
-# Only set interface MTU on either a DHCP option recieved or a static
-# configuration for IPv4 which is wrapped in the DHCP setup.
-# IPv6 MTU is done via routing.
-if [ "$ifsuffix" = ".dhcp" ]; then
- if [ "$reason" = PREINIT -a -e "$mtu_dir/$interface" ]; then
- rm "$mtu_dir/$interface"
- elif [ -n "$new_interface_mtu" ] && $if_up; then
- # The smalled MTU dhcpcd can work with is 576
- if [ "$new_interface_mtu" -ge 576 ]; then
- if set_mtu "$new_interface_mtu"; then
- syslog info "MTU set to $new_interface_mtu"
- # Save the MTU so we can restore it later
- if [ ! -e "$mtu_dir/$interface" ]; then
- mkdir -p "$mtu_dir"
- echo "$ifmtu" > "$mtu_dir/$interface"
- fi
- fi
- fi
- elif [ -e "$mtu_dir/$interface" ]; then
- if $if_up || $if_down; then
- # No MTU in this state, so restore the prior MTU
- mtu=$(cat "$mtu_dir/$interface")
- syslog info "MTU restored to $mtu"
- set_mtu "$mtu"
- rm "$mtu_dir/$interface"
- fi
- fi
-fi
SCRIPTSDIR= ${LIBEXECDIR}/dhcpcd-hooks
SCRIPTS= 01-test 02-dump
-SCRIPTS+= 10-mtu 10-wpa_supplicant 15-timezone 20-resolv.conf
+SCRIPTS+= 10-wpa_supplicant 15-timezone 20-resolv.conf
SCRIPTS+= 29-lookup-hostname 30-hostname
SCRIPTS+= ${HOOKSCRIPTS}
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 3, 2015
+.Dd July 28, 2015
.Dt DHCPCD 8
.Os
.Sh NAME
.Pp
So to stop
.Nm
-from touching your DNS or MTU settings you would do:-
-.D1 dhcpcd -C resolv.conf -C mtu eth0
+from touching your DNS settings you would do:-
+.D1 dhcpcd -C resolv.conf eth0
.It Fl G , Fl Fl nogateway
Don't set any default routes.
.It Fl H , Fl Fl xidhwaddr
option classless_static_routes
# Most distributions have NTP support.
option ntp_servers
-# Respect the network MTU.
-# Some interface drivers reset when changing the MTU so disabled by default.
-#option interface_mtu
+# Respect the network MTU. This is applied to DHCP routes.
+option interface_mtu
# A ServerID is required by RFC2131.
require dhcp_server_identifier
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 22, 2015
+.Dd July 28, 2015
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
.Pp
So to stop
.Nm dhcpcd
-from touching your DNS or MTU settings you would do:-
-.D1 nohook resolv.conf, mtu
+from touching your DNS settings or starting wpa_supplicant you would do:-
+.D1 nohook resolv.conf, wpa_supplicant
.It Ic noipv4
Don't attempt to configure an IPv4 address.
.It Ic noipv4ll
get_addrs(rtm->rtm_addrs, cp, rti_info);
memset(rt, 0, sizeof(*rt));
+ rt->flags = (unsigned int)rtm->rtm_flags;
COPYOUT(rt->dest, rti_info[RTAX_DST]);
if (rtm->rtm_addrs & RTA_NETMASK)
COPYOUT(rt->net, rti_info[RTAX_NETMASK]);
COPYOUT(rt->gate, rti_info[RTAX_GATEWAY]);
COPYOUT(rt->src, rti_info[RTAX_IFA]);
+ if (rtm->rtm_inits & RTV_MTU)
+ rt->mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
+
if (rtm->rtm_index)
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
else if (rtm->rtm_addrs & RTA_IFP) {
sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
rt->iface = if_findsdl(ctx, sdl);
}
+
/* If we don't have an interface and it's a host route, it maybe
* to a local ip via the loopback interface. */
if (rt->iface == NULL &&
if (rtm.hdr.rtm_addrs & RTA_IFA)
ADDADDR(&state->addr);
+
+ if (rt->mtu) {
+ rtm.hdr.rtm_inits |= RTV_MTU;
+ rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
+ }
}
#undef ADDADDR
ipv6_mask(&rt->net, 128);
COPYOUT6(rt->gate, rti_info[RTAX_GATEWAY]);
+ if (rtm->rtm_inits & RTV_MTU)
+ rt->mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
+
if (rtm->rtm_index)
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
else if (rtm->rtm_addrs & RTA_IFP) {
return 0;
}
+static int
+rta_add_attr_32(struct rtattr *rta, unsigned short maxlen,
+ unsigned short type, uint32_t data)
+{
+ unsigned short len = RTA_LENGTH(sizeof(data));
+ struct rtattr *subrta;
+
+ if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ subrta = (struct rtattr*)(void *)
+ (((char*)rta) + RTA_ALIGN(rta->rta_len));
+ subrta->rta_type = type;
+ subrta->rta_len = len;
+ memcpy(RTA_DATA(subrta), &data, sizeof(data));
+ rta->rta_len = (unsigned short)(NLMSG_ALIGN(rta->rta_len) + len);
+ return 0;
+}
+
#ifdef HAVE_NL80211_H
static struct nlattr *
nla_next(struct nlattr *nla, size_t *rem)
if (rt->metric)
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
+ if (cmd != RTM_DELETE && rt->mtu) {
+ char metricsbuf[32];
+ struct rtattr *metrics = (void *)metricsbuf;
+
+ metrics->rta_type = RTA_METRICS;
+ metrics->rta_len = RTA_LENGTH(0);
+ rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
+ add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS,
+ RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics));
+ }
+
if (send_netlink(rt->iface->ctx, NULL,
NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
retval = -1;
return retval;
}
-static int
-rta_add_attr_32(struct rtattr *rta, unsigned short maxlen,
- unsigned short type, uint32_t data)
-{
- unsigned short len = RTA_LENGTH(sizeof(data));
- struct rtattr *subrta;
-
- if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
- errno = ENOBUFS;
- return -1;
- }
-
- subrta = (struct rtattr*)(void *)
- (((char*)rta) + RTA_ALIGN(rta->rta_len));
- subrta->rta_type = type;
- subrta->rta_len = len;
- memcpy(RTA_DATA(subrta), &data, sizeof(data));
- rta->rta_len = (unsigned short)(NLMSG_ALIGN(rta->rta_len) + len);
- return 0;
-}
-
int
if_route6(unsigned char cmd, const struct rt6 *rt)
{
add_attr_32(&nlm.hdr, sizeof(nlm),
RTA_PRIORITY, rt->metric);
}
- if (cmd == RTM_ADD && rt->mtu) {
+ if (cmd != RTM_DELETE && rt->mtu) {
char metricsbuf[32];
struct rtattr *metrics = (void *)metricsbuf;
static int
nc_route(struct rt *ort, struct rt *nrt)
{
+ int change;
/* Don't set default routes if not asked to */
if (nrt->dest.s_addr == 0 &&
desc_route(ort == NULL ? "adding" : "changing", nrt);
+ change = 0;
if (ort == NULL) {
ort = ipv4_findrt(nrt->iface->ctx, nrt, 0);
if (ort &&
ort->metric == nrt->metric &&
#endif
ort->gate.s_addr == nrt->gate.s_addr)))
- return 0;
- } else if (ort->flags & STATE_FAKE && !(nrt->flags & STATE_FAKE) &&
+ {
+ if (ort->mtu == nrt->mtu)
+ return 0;
+ change = 1;
+ }
+ } else if (ort->state & STATE_FAKE && !(nrt->state & STATE_FAKE) &&
ort->iface == nrt->iface &&
#ifdef HAVE_ROUTE_METRIC
ort->metric == nrt->metric &&
ort->dest.s_addr == nrt->dest.s_addr &&
ort->net.s_addr == nrt->net.s_addr &&
ort->gate.s_addr == nrt->gate.s_addr)
- return 0;
+ {
+ if (ort->mtu == nrt->mtu)
+ return 0;
+ change = 1;
+ }
+
+#ifdef RTF_CLONING
+ /* BSD can set routes to be cloning routes.
+ * Cloned routes inherit the parent flags.
+ * As such, we need to delete and re-add the route to flush children
+ * to correct the flags. */
+ if (change && ort != NULL && ort->flags & RTF_CLONING)
+ change = 0;
+#endif
+
+ if (change) {
+ if (if_route(RTM_CHANGE, nrt) == 0)
+ return 0;
+ if (errno != ESRCH)
+ logger(nrt->iface->ctx, LOG_ERR, "if_route (CHG): %m");
+ }
#ifdef HAVE_ROUTE_METRIC
/* With route metrics, we can safely add the new route before
return rt;
#endif
- if ((r = malloc(sizeof(*r))) == NULL) {
+ if ((r = calloc(1, sizeof(*r))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(rt);
return NULL;
r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
r->net.s_addr = s->net.s_addr;
r->gate.s_addr = INADDR_ANY;
+ r->mtu = dhcp_get_mtu(ifp);
r->src = s->addr;
TAILQ_INSERT_HEAD(rt, r, next);
if (s->addr.s_addr == INADDR_ANY)
return rt;
- r = malloc(sizeof(*r));
- if (r == NULL) {
+ if ((r = calloc(1, sizeof(*r))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(rt);
return NULL;
r->dest = s->addr;
r->net.s_addr = INADDR_BROADCAST;
r->gate.s_addr = htonl(INADDR_LOOPBACK);
+ r->mtu = dhcp_get_mtu(ifp);
r->src = s->addr;
TAILQ_INSERT_HEAD(rt, r, next);
return rt;
TAILQ_FOREACH(rt, ifp->options->routes, next) {
if (rt->gate.s_addr == 0)
break;
- r = malloc(sizeof(*r));
- if (r == NULL) {
+ if ((r = calloc(1, sizeof(*r))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(nrt);
return NULL;
TAILQ_INSERT_TAIL(nrt, r, next);
}
} else
- nrt = get_option_routes(ifp, D_STATE(ifp)->new);
+ nrt = dhcp_get_routes(ifp);
/* Copy our address as the source address */
if (nrt) {
(state = D_CSTATE(ifp)) == NULL)
return rt;
- r = malloc(sizeof(*r));
- if (r == NULL) {
+ if ((r = calloc(1, sizeof(*r))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(rt);
return NULL;
r->dest.s_addr = INADDR_ANY;
r->net.s_addr = INADDR_ANY;
r->gate.s_addr = state->dst.s_addr;
+ r->mtu = dhcp_get_mtu(ifp);
+ r->src = state->addr;
TAILQ_INSERT_HEAD(rt, r, next);
return rt;
}
"%s: router %s requires a host route",
ifp->name, inet_ntoa(rtp->gate));
}
- rtn = malloc(sizeof(*rtn));
- if (rtn == NULL) {
+ if ((rtn = calloc(1, sizeof(*rtn))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(rt);
return NULL;
rtn->dest.s_addr = rtp->gate.s_addr;
rtn->net.s_addr = htonl(INADDR_BROADCAST);
rtn->gate.s_addr = htonl(INADDR_ANY);
+ rtn->mtu = dhcp_get_mtu(ifp);
+ rtn->src = state->addr;
TAILQ_INSERT_BEFORE(rtp, rtn, next);
}
return rt;
struct rt *or;
state = D_CSTATE(rt->iface);
+ rt->state = state->added & STATE_FAKE;
#ifdef HAVE_ROUTE_METRIC
rt->metric = rt->iface->metric;
#endif
- rt->flags = state->added & STATE_FAKE;
/* Is this route already in our table? */
if ((find_route(nrs, rt, NULL)) != NULL)
return 0;
if ((or = find_route(rt->iface->ctx->ipv4_routes, rt, NULL))) {
if (state->added & STATE_FAKE)
return 0;
- if (or->flags & STATE_FAKE ||
+ if (or->state & STATE_FAKE ||
or->iface != rt->iface ||
#ifdef HAVE_ROUTE_METRIC
rt->metric != or->metric ||
#endif
rt->src.s_addr != or->src.s_addr ||
- rt->gate.s_addr != or->gate.s_addr)
+ rt->gate.s_addr != or->gate.s_addr ||
+ rt->mtu != or->mtu)
{
if (c_route(or, rt) != 0)
return 0;
free(or);
} else {
if (state->added & STATE_FAKE) {
- or = ipv4_findrt(rt->iface->ctx, rt, 1);
- if (or == NULL ||
- or->gate.s_addr != rt->gate.s_addr)
+ if ((or = ipv4_findrt(rt->iface->ctx, rt, 1)) == NULL)
return 0;
+ rt->iface = or->iface;
+ rt->gate.s_addr = or->gate.s_addr;
+#ifdef HAVE_ROUTE_METRIC
+ rt->metric = or->metric;
+#endif
+ rt->mtu = or->mtu;
+ rt->flags = or->flags;
} else {
if (n_route(rt) != 0)
return 0;
}
}
- rt->flags |= STATE_ADDED;
return 1;
}
#ifdef HAVE_ROUTE_METRIC
unsigned int metric;
#endif
+ unsigned int mtu;
struct in_addr src;
unsigned int flags;
+ unsigned int state;
};
TAILQ_HEAD(rt_head, rt);
state->addr.s_addr == INADDR_ANY)
return NULL;
- if ((rt = malloc(sizeof(*rt))) == NULL) {
+ if ((rt = calloc(1, sizeof(*rt))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__);
return NULL;
}
state->addr.s_addr == INADDR_ANY)
return NULL;
- if ((rt = malloc(sizeof(*rt))) == NULL) {
+ if ((rt = calloc(1, sizeof(*rt))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__);
return NULL;
}