diff options
author | 2017-01-24 00:17:14 +0000 | |
---|---|---|
committer | 2017-01-24 00:17:14 +0000 | |
commit | 978e78df19cb45b047225a86a6a300aee9fcd747 (patch) | |
tree | 3cd19be0909bfbd5541f06979e56d20fad665411 | |
parent | tls_config_add_keypair_mem is the function to add additional keypairs and (diff) | |
download | wireguard-openbsd-978e78df19cb45b047225a86a6a300aee9fcd747.tar.xz wireguard-openbsd-978e78df19cb45b047225a86a6a300aee9fcd747.zip |
Introduce rt_report() a function that generates a route message from an
rt_entry. Use this function in the success case of all route commands.
Reduce the goto madness in route_output and make the code hopefully a
bit easier to read and work with.
OK mpi@ bluhm@
-rw-r--r-- | sys/net/rtsock.c | 211 |
1 files changed, 114 insertions, 97 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 1b2d482004f..ddfc48ba401 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtsock.c,v 1.219 2017/01/23 07:27:21 dlg Exp $ */ +/* $OpenBSD: rtsock.c,v 1.220 2017/01/24 00:17:14 claudio Exp $ */ /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ /* @@ -459,30 +459,94 @@ route_input(struct mbuf *m0, sa_family_t sa_family) m_freem(m); } +struct rt_msghdr * +rt_report(struct rtentry *rt, u_char type, int seq, int tableid) +{ + struct rt_msghdr *rtm; + struct rt_addrinfo info; + struct sockaddr_rtlabel sa_rl; + struct sockaddr_in6 sa_mask; +#ifdef BFD + struct sockaddr_bfd sa_bfd; +#endif +#ifdef MPLS + struct sockaddr_mpls sa_mpls; +#endif + struct ifnet *ifp = NULL; + int len; + + bzero(&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_plen2mask(rt, &sa_mask); + info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl); +#ifdef BFD + if (rt->rt_flags & RTF_BFD) + info.rti_info[RTAX_BFD] = bfd2sa(rt, &sa_bfd); +#endif +#ifdef MPLS + if (rt->rt_flags & RTF_MPLS) { + bzero(&sa_mpls, sizeof(sa_mpls)); + sa_mpls.smpls_family = AF_MPLS; + sa_mpls.smpls_len = sizeof(sa_mpls); + sa_mpls.smpls_label = ((struct rt_mpls *) + rt->rt_llinfo)->mpls_label; + info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls; + info.rti_mpls = ((struct rt_mpls *) + rt->rt_llinfo)->mpls_operation; + } +#endif + ifp = if_get(rt->rt_ifidx); + if (ifp != NULL) { + info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl); + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; + if (ifp->if_flags & IFF_POINTOPOINT) + info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr; + } + if_put(ifp); + /* RTAX_GENMASK, RTAX_AUTHOR, RTAX_SRCMASK ignored */ + + /* build new route message */ + len = rt_msg2(type, RTM_VERSION, &info, NULL, NULL); + /* XXX why can't we wait? Should be process context... */ + rtm = malloc(len, M_RTABLE, M_NOWAIT | M_ZERO); + if (rtm == NULL) + return NULL; + + rt_msg2(type, RTM_VERSION, &info, (caddr_t)rtm, NULL); + rtm->rtm_type = type; + rtm->rtm_index = rt->rt_ifidx; + rtm->rtm_tableid = tableid; + rtm->rtm_priority = rt->rt_priority & RTP_MASK; + rtm->rtm_flags = rt->rt_flags; + rtm->rtm_pid = curproc->p_p->ps_pid; + rtm->rtm_seq = seq; + rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); + rtm->rtm_addrs = info.rti_addrs; +#ifdef MPLS + rtm->rtm_mpls = info.rti_mpls; +#endif + return rtm; +} + int route_output(struct mbuf *m, ...) { struct rt_msghdr *rtm = NULL; struct rtentry *rt = NULL; - struct rtentry *saved_nrt = NULL; struct rt_addrinfo info; - int plen, len, newgate = 0, error = 0; + int plen, len, seq, newgate = 0, error = 0; struct ifnet *ifp = NULL; struct ifaddr *ifa = NULL; struct socket *so; struct rawcb *rp = NULL; - struct sockaddr_rtlabel sa_rl; - struct sockaddr_in6 sa_mask; -#ifdef BFD - struct sockaddr_bfd sa_bfd; -#endif #ifdef MPLS - struct sockaddr_mpls sa_mpls, *psa_mpls; + struct sockaddr_mpls *psa_mpls; #endif va_list ap; u_int tableid; u_int8_t prio; - u_char vers; + u_char vers, type; va_start(ap, m); so = va_arg(ap, struct socket *); @@ -639,16 +703,12 @@ route_output(struct mbuf *m, ...) rtfree(rt); rt = NULL; - error = rtrequest(RTM_ADD, &info, prio, &saved_nrt, tableid); - if (error == 0) { + error = rtrequest(RTM_ADD, &info, prio, &rt, tableid); + if (error == 0) rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, - &saved_nrt->rt_rmx); - /* write back the priority the kernel used */ - rtm->rtm_priority = saved_nrt->rt_priority & RTP_MASK; - rtm->rtm_index = saved_nrt->rt_ifidx; - rtm->rtm_flags = saved_nrt->rt_flags; - rtfree(saved_nrt); - } + &rt->rt_rmx); + else + goto flush; break; case RTM_DELETE: rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], @@ -668,7 +728,7 @@ route_output(struct mbuf *m, ...) /* Reset the MTU of the gateway route. */ rtable_walk(tableid, rt_key(rt)->sa_family, route_cleargateway, rt); - goto report; + break; } /* @@ -678,84 +738,15 @@ route_output(struct mbuf *m, ...) if ((rt != NULL) && ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)) { error = EINVAL; - goto report; + break; } rtfree(rt); rt = NULL; error = rtrequest(RTM_DELETE, &info, prio, &rt, tableid); - if (error == 0) - goto report; - break; - case RTM_GET: - rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY], - prio); - if (rt == NULL) { - error = ESRCH; + if (error != 0) goto flush; - } - -report: - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = - rt_plen2mask(rt, &sa_mask); - info.rti_info[RTAX_LABEL] = - rtlabel_id2sa(rt->rt_labelid, &sa_rl); -#ifdef BFD - if (rt->rt_flags & RTF_BFD) - info.rti_info[RTAX_BFD] = bfd2sa(rt, &sa_bfd); -#endif -#ifdef MPLS - if (rt->rt_flags & RTF_MPLS) { - bzero(&sa_mpls, sizeof(sa_mpls)); - sa_mpls.smpls_family = AF_MPLS; - sa_mpls.smpls_len = sizeof(sa_mpls); - sa_mpls.smpls_label = ((struct rt_mpls *) - rt->rt_llinfo)->mpls_label; - info.rti_info[RTAX_SRC] = - (struct sockaddr *)&sa_mpls; - info.rti_mpls = ((struct rt_mpls *) - rt->rt_llinfo)->mpls_operation; - rtm->rtm_mpls = info.rti_mpls; - } -#endif - info.rti_info[RTAX_IFP] = NULL; - info.rti_info[RTAX_IFA] = NULL; - ifp = if_get(rt->rt_ifidx); - if (ifp != NULL && rtm->rtm_addrs & (RTA_IFP|RTA_IFA)) { - info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl); - info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; - if (ifp->if_flags & IFF_POINTOPOINT) - info.rti_info[RTAX_BRD] = - rt->rt_ifa->ifa_dstaddr; - else - info.rti_info[RTAX_BRD] = NULL; - } - if_put(ifp); - len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL, - NULL); - if (len > rtm->rtm_msglen) { - struct rt_msghdr *new_rtm; - new_rtm = malloc(len, M_RTABLE, M_NOWAIT); - if (new_rtm == NULL) { - error = ENOBUFS; - goto flush; - } - memcpy(new_rtm, rtm, rtm->rtm_msglen); - free(rtm, M_RTABLE, 0); - rtm = new_rtm; - } - rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm, - NULL); - rtm->rtm_flags = rt->rt_flags; - rtm->rtm_use = 0; - rtm->rtm_priority = rt->rt_priority & RTP_MASK; - rtm->rtm_index = rt->rt_ifidx; - rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); - rtm->rtm_addrs = info.rti_addrs; break; case RTM_CHANGE: case RTM_LOCK: @@ -907,9 +898,6 @@ change: rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); - rtm->rtm_index = rt->rt_ifidx; - rtm->rtm_priority = rt->rt_priority & RTP_MASK; - rtm->rtm_flags = rt->rt_flags; ifp = if_get(rt->rt_ifidx); KASSERT(ifp != NULL); @@ -929,13 +917,43 @@ change: rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); rt->rt_rmx.rmx_locks |= (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); - rtm->rtm_priority = rt->rt_priority & RTP_MASK; break; } break; + case RTM_GET: + rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], + info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY], + prio); + if (rt == NULL) { + error = ESRCH; + goto flush; + } + break; + } + + /* + * From here on these vars need to be valid + * rt, rtm, error, so, m, tableid, sa_family + * + * Other notes: + * - to end up here previous calls passed OK, error is most probably 0 + * - error cases take the flush route or in bad cases fail + * - fail does not report the message back but just fails the call + * if the message is not valid then fail should be used + */ + + type = rtm->rtm_type; + seq = rtm->rtm_seq; + free(rtm, M_RTABLE, 0); + rtm = rt_report(rt, type, seq, tableid); + if (rtm == NULL) { + error = ENOBUFS; + goto fail; } flush: + if (rt) + rtfree(rt); if (rtm) { if (error) rtm->rtm_errno = error; @@ -943,14 +961,13 @@ flush: rtm->rtm_flags |= RTF_DONE; } } - if (rt) - rtfree(rt); /* * Check to see if we don't want our own messages. */ if (!(so->so_options & SO_USELOOPBACK)) { if (route_cb.any_count <= 1) { + /* no other listener and no loopback of messages */ fail: free(rtm, M_RTABLE, 0); m_freem(m); |