diff options
Diffstat (limited to 'sys/net/rtsock.c')
-rw-r--r-- | sys/net/rtsock.c | 117 |
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) { |