summaryrefslogtreecommitdiff
path: root/sys/net/rtsock.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/rtsock.c')
-rw-r--r--sys/net/rtsock.c117
1 files changed, 64 insertions, 53 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index a40f067325b1..3a6afcaba6d7 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -151,7 +151,7 @@ struct walkarg {
};
static void rts_input(struct mbuf *m);
-static struct mbuf *rt_msg1(int type, struct rt_addrinfo *rtinfo);
+static struct mbuf *rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo);
static int rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo,
struct walkarg *w, int *plen);
static int rt_xaddrs(caddr_t cp, caddr_t cplim,
@@ -160,9 +160,10 @@ static int sysctl_dumpentry(struct radix_node *rn, void *vw);
static int sysctl_iflist(int af, struct walkarg *w);
static int sysctl_ifmalist(int af, struct walkarg *w);
static int route_output(struct mbuf *m, struct socket *so);
-static void rt_setmetrics(const struct rt_msghdr *rtm, struct rtentry *rt);
static void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out);
static void rt_dispatch(struct mbuf *, sa_family_t);
+static struct sockaddr *rtsock_fix_netmask(struct sockaddr *dst,
+ struct sockaddr *smask, struct sockaddr_storage *dmask);
static struct netisr_handler rtsock_nh = {
.nh_name = "rtsock",
@@ -521,8 +522,8 @@ route_output(struct mbuf *m, struct socket *so)
struct rtentry *rt = NULL;
struct radix_node_head *rnh;
struct rt_addrinfo info;
-#ifdef INET6
struct sockaddr_storage ss;
+#ifdef INET6
struct sockaddr_in6 *sin6;
int i, rti_need_deembed = 0;
#endif
@@ -532,7 +533,6 @@ route_output(struct mbuf *m, struct socket *so)
sa_family_t saf = AF_UNSPEC;
struct rawcb *rp = NULL;
struct walkarg w;
- char msgbuf[512];
fibnum = so->so_fibnum;
@@ -549,20 +549,12 @@ route_output(struct mbuf *m, struct socket *so)
/*
* Most of current messages are in range 200-240 bytes,
- * minimize possible failures by using on-stack buffer
- * which should fit for most messages.
- * However, use stable memory if we need to handle
- * something large.
+ * minimize possible re-allocation on reply using larger size
+ * buffer aligned on 1k boundaty.
*/
- if (len < sizeof(msgbuf)) {
- alloc_len = sizeof(msgbuf);
- rtm = (struct rt_msghdr *)msgbuf;
- } else {
- alloc_len = roundup2(len, 1024);
- rtm = malloc(alloc_len, M_TEMP, M_NOWAIT);
- if (rtm == NULL)
- senderr(ENOBUFS);
- }
+ alloc_len = roundup2(len, 1024);
+ if ((rtm = malloc(alloc_len, M_TEMP, M_NOWAIT)) == NULL)
+ senderr(ENOBUFS);
m_copydata(m, 0, len, (caddr_t)rtm);
bzero(&info, sizeof(info));
@@ -570,8 +562,7 @@ route_output(struct mbuf *m, struct socket *so)
if (rtm->rtm_version != RTM_VERSION) {
/* Do not touch message since format is unknown */
- if ((char *)rtm != msgbuf)
- free(rtm, M_TEMP);
+ free(rtm, M_TEMP);
rtm = NULL;
senderr(EPROTONOSUPPORT);
}
@@ -584,6 +575,10 @@ route_output(struct mbuf *m, struct socket *so)
rtm->rtm_pid = curproc->p_pid;
info.rti_addrs = rtm->rtm_addrs;
+
+ info.rti_mflags = rtm->rtm_inits;
+ info.rti_rmx = &rtm->rtm_rmx;
+
/*
* rt_xaddrs() performs s6_addr[2] := sin6_scope_id for AF_INET6
* link-local address because rtrequest requires addresses with
@@ -670,7 +665,6 @@ route_output(struct mbuf *m, struct socket *so)
rti_need_deembed = (V_deembed_scopeid) ? 1 : 0;
#endif
RT_LOCK(saved_nrt);
- rt_setmetrics(rtm, saved_nrt);
rtm->rtm_index = saved_nrt->rt_ifp->if_index;
RT_REMREF(saved_nrt);
RT_UNLOCK(saved_nrt);
@@ -792,7 +786,8 @@ report:
}
info.rti_info[RTAX_DST] = rt_key(rt);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
- info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt),
+ rt_mask(rt), &ss);
info.rti_info[RTAX_GENMASK] = 0;
if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
ifp = rt->rt_ifp;
@@ -859,7 +854,7 @@ flush:
*/
if ((so->so_options & SO_USELOOPBACK) == 0) {
if (V_route_cb.any_count <= 1) {
- if (rtm != NULL && (char *)rtm != msgbuf)
+ if (rtm != NULL)
free(rtm, M_TEMP);
m_freem(m);
return (error);
@@ -897,8 +892,7 @@ flush:
} else if (m->m_pkthdr.len > rtm->rtm_msglen)
m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
- if ((char *)rtm != msgbuf)
- free(rtm, M_TEMP);
+ free(rtm, M_TEMP);
}
if (m != NULL) {
M_SETFIB(m, fibnum);
@@ -920,20 +914,6 @@ flush:
}
static void
-rt_setmetrics(const struct rt_msghdr *rtm, struct rtentry *rt)
-{
-
- if (rtm->rtm_inits & RTV_MTU)
- rt->rt_mtu = rtm->rtm_rmx.rmx_mtu;
- if (rtm->rtm_inits & RTV_WEIGHT)
- rt->rt_weight = rtm->rtm_rmx.rmx_weight;
- /* Kernel -> userland timebase conversion. */
- if (rtm->rtm_inits & RTV_EXPIRE)
- rt->rt_expire = rtm->rtm_rmx.rmx_expire ?
- rtm->rtm_rmx.rmx_expire - time_second + time_uptime : 0;
-}
-
-static void
rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out)
{
@@ -990,10 +970,33 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
}
/*
- * Used by the routing socket.
+ * Fill in @dmask with valid netmask leaving original @smask
+ * intact. Mostly used with radix netmasks.
+ */
+static struct sockaddr *
+rtsock_fix_netmask(struct sockaddr *dst, struct sockaddr *smask,
+ struct sockaddr_storage *dmask)
+{
+ if (dst == NULL || smask == NULL)
+ return (NULL);
+
+ memset(dmask, 0, dst->sa_len);
+ memcpy(dmask, smask, smask->sa_len);
+ dmask->ss_len = dst->sa_len;
+ dmask->ss_family = dst->sa_family;
+
+ return ((struct sockaddr *)dmask);
+}
+
+/*
+ * Writes information related to @rtinfo object to newly-allocated mbuf.
+ * Assumes MCLBYTES is enough to construct any message.
+ * Used for OS notifications of vaious events (if/ifa announces,etc)
+ *
+ * Returns allocated mbuf or NULL on failure.
*/
static struct mbuf *
-rt_msg1(int type, struct rt_addrinfo *rtinfo)
+rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo)
{
struct rt_msghdr *rtm;
struct mbuf *m;
@@ -1205,7 +1208,7 @@ rt_missmsg_fib(int type, struct rt_addrinfo *rtinfo, int flags, int error,
if (V_route_cb.any_count == 0)
return;
- m = rt_msg1(type, rtinfo);
+ m = rtsock_msg_mbuf(type, rtinfo);
if (m == NULL)
return;
@@ -1244,7 +1247,7 @@ rt_ifmsg(struct ifnet *ifp)
if (V_route_cb.any_count == 0)
return;
bzero((caddr_t)&info, sizeof(info));
- m = rt_msg1(RTM_IFINFO, &info);
+ m = rtsock_msg_mbuf(RTM_IFINFO, &info);
if (m == NULL)
return;
ifm = mtod(m, struct if_msghdr *);
@@ -1270,6 +1273,7 @@ rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
struct mbuf *m;
struct ifa_msghdr *ifam;
struct ifnet *ifp = ifa->ifa_ifp;
+ struct sockaddr_storage ss;
if (V_route_cb.any_count == 0)
return (0);
@@ -1279,9 +1283,10 @@ rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
- info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+ info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(
+ info.rti_info[RTAX_IFP], ifa->ifa_netmask, &ss);
info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
- if ((m = rt_msg1(ncmd, &info)) == NULL)
+ if ((m = rtsock_msg_mbuf(ncmd, &info)) == NULL)
return (ENOBUFS);
ifam = mtod(m, struct ifa_msghdr *);
ifam->ifam_index = ifp->if_index;
@@ -1318,15 +1323,16 @@ rtsock_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
struct sockaddr *sa;
struct mbuf *m;
struct rt_msghdr *rtm;
+ struct sockaddr_storage ss;
if (V_route_cb.any_count == 0)
return (0);
bzero((caddr_t)&info, sizeof(info));
- info.rti_info[RTAX_NETMASK] = rt_mask(rt);
info.rti_info[RTAX_DST] = sa = rt_key(rt);
+ info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(sa, rt_mask(rt), &ss);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
- if ((m = rt_msg1(cmd, &info)) == NULL)
+ if ((m = rtsock_msg_mbuf(cmd, &info)) == NULL)
return (ENOBUFS);
rtm = mtod(m, struct rt_msghdr *);
rtm->rtm_index = ifp->if_index;
@@ -1368,7 +1374,7 @@ rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma)
* (similarly to how ARP entries, e.g., are presented).
*/
info.rti_info[RTAX_GATEWAY] = ifma->ifma_lladdr;
- m = rt_msg1(cmd, &info);
+ m = rtsock_msg_mbuf(cmd, &info);
if (m == NULL)
return;
ifmam = mtod(m, struct ifma_msghdr *);
@@ -1389,7 +1395,7 @@ rt_makeifannouncemsg(struct ifnet *ifp, int type, int what,
if (V_route_cb.any_count == 0)
return NULL;
bzero((caddr_t)info, sizeof(*info));
- m = rt_msg1(type, info);
+ m = rtsock_msg_mbuf(type, info);
if (m != NULL) {
ifan = mtod(m, struct if_announcemsghdr *);
ifan->ifan_index = ifp->if_index;
@@ -1496,6 +1502,7 @@ sysctl_dumpentry(struct radix_node *rn, void *vw)
struct rtentry *rt = (struct rtentry *)rn;
int error = 0, size;
struct rt_addrinfo info;
+ struct sockaddr_storage ss;
if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
return 0;
@@ -1506,7 +1513,8 @@ sysctl_dumpentry(struct radix_node *rn, void *vw)
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = rt_key(rt);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
- info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt),
+ rt_mask(rt), &ss);
info.rti_info[RTAX_GENMASK] = 0;
if (rt->rt_ifp) {
info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addr->ifa_addr;
@@ -1682,6 +1690,7 @@ sysctl_iflist(int af, struct walkarg *w)
struct ifaddr *ifa;
struct rt_addrinfo info;
int len, error = 0;
+ struct sockaddr_storage ss;
bzero((caddr_t)&info, sizeof(info));
IFNET_RLOCK_NOSLEEP();
@@ -1710,7 +1719,8 @@ sysctl_iflist(int af, struct walkarg *w)
ifa->ifa_addr) != 0)
continue;
info.rti_info[RTAX_IFA] = ifa->ifa_addr;
- info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+ info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(
+ ifa->ifa_addr, ifa->ifa_netmask, &ss);
info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
error = rtsock_msg_buffer(RTM_NEWADDR, &info, w, &len);
if (error != 0)
@@ -1727,8 +1737,9 @@ sysctl_iflist(int af, struct walkarg *w)
}
}
IF_ADDR_RUNLOCK(ifp);
- info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] =
- info.rti_info[RTAX_BRD] = NULL;
+ info.rti_info[RTAX_IFA] = NULL;
+ info.rti_info[RTAX_NETMASK] = NULL;
+ info.rti_info[RTAX_BRD] = NULL;
}
done:
if (ifp != NULL)
@@ -1764,7 +1775,7 @@ sysctl_ifmalist(int af, struct walkarg *w)
info.rti_info[RTAX_GATEWAY] =
(ifma->ifma_addr->sa_family != AF_LINK) ?
ifma->ifma_lladdr : NULL;
- error = rtsock_msg_buffer(RTM_NEWADDR, &info, w, &len);
+ error = rtsock_msg_buffer(RTM_NEWMADDR, &info, w, &len);
if (error != 0)
goto done;
if (w->w_req && w->w_tmem) {