diff options
author | 2017-03-06 10:19:17 +0000 | |
---|---|---|
committer | 2017-03-06 10:19:17 +0000 | |
commit | 96ac089d51c19253b98ed7ba484e2bfef81efc6b (patch) | |
tree | 96c5040a773bcd6d6219c356c7d80b5dad61ea17 | |
parent | Guard headers to make sure userland do not look at them. (diff) | |
download | wireguard-openbsd-96ac089d51c19253b98ed7ba484e2bfef81efc6b.tar.xz wireguard-openbsd-96ac089d51c19253b98ed7ba484e2bfef81efc6b.zip |
Move the guts of route_output() meesing with the routing table in their
own function.
ok bluhm@
-rw-r--r-- | sys/net/rtsock.c | 213 |
1 files changed, 106 insertions, 107 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 11286c5a793..d955e5e21bc 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtsock.c,v 1.229 2017/03/06 08:56:39 mpi Exp $ */ +/* $OpenBSD: rtsock.c,v 1.230 2017/03/06 10:19:17 mpi Exp $ */ /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ /* @@ -104,6 +104,8 @@ int route_arp_conflict(struct rtentry *, struct rt_addrinfo *); int route_cleargateway(struct rtentry *, void *, unsigned int); void route_senddesync(void *); +int rtm_output(struct rt_msghdr *, struct rtentry **, struct rt_addrinfo *, + uint8_t, unsigned int); struct rt_msghdr *rtm_report(struct rtentry *, u_char, int, int); struct mbuf *rtm_msg1(int, struct rt_addrinfo *); int rtm_msg2(int, int, struct rt_addrinfo *, caddr_t, @@ -535,13 +537,8 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, struct rt_msghdr *rtm = NULL; struct rtentry *rt = NULL; struct rt_addrinfo info; - int plen, len, seq, newgate = 0, error = 0; - struct ifnet *ifp = NULL; - struct ifaddr *ifa = NULL; + int len, seq, error = 0; struct rawcb *rp = NULL; -#ifdef MPLS - struct sockaddr_mpls *psa_mpls; -#endif u_int tableid; u_int8_t prio; u_char vers, type; @@ -679,21 +676,79 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, error = EINVAL; goto fail; } - goto flush; + } else { + error = rtm_output(rtm, &rt, &info, prio, tableid); + if (!error) { + type = rtm->rtm_type; + seq = rtm->rtm_seq; + free(rtm, M_RTABLE, 0); + rtm = rtm_report(rt, type, seq, tableid); + } + } + + rtfree(rt); + if (error) { + rtm->rtm_errno = error; + } else { + rtm->rtm_flags |= RTF_DONE; + } + + /* + * 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); + return (error); + } + /* There is another listener, so construct message */ + rp = sotorawcb(so); + rp->rcb_proto.sp_family = 0; /* Avoid us */ + } + if (rtm) { + if (m_copyback(m, 0, rtm->rtm_msglen, rtm, M_NOWAIT)) { + m_freem(m); + m = NULL; + } else if (m->m_pkthdr.len > rtm->rtm_msglen) + m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); + free(rtm, M_RTABLE, 0); } + if (m) + route_input(m, info.rti_info[RTAX_DST] ? + info.rti_info[RTAX_DST]->sa_family : AF_UNSPEC); + if (rp) + rp->rcb_proto.sp_family = PF_ROUTE; /* Readd us */ + + return (error); +} + +int +rtm_output(struct rt_msghdr *rtm, struct rtentry **prt, + struct rt_addrinfo *info, uint8_t prio, unsigned int tableid) +{ + struct rtentry *rt = *prt; + struct ifnet *ifp = NULL; + struct ifaddr *ifa = NULL; +#ifdef MPLS + struct sockaddr_mpls *psa_mpls; +#endif + int plen, newgate = 0, error = 0; switch (rtm->rtm_type) { case RTM_ADD: - if (info.rti_info[RTAX_GATEWAY] == NULL) { + if (info->rti_info[RTAX_GATEWAY] == NULL) { error = EINVAL; - goto flush; + break; } - rt = rtable_match(tableid, info.rti_info[RTAX_DST], NULL); - if ((error = route_arp_conflict(rt, &info))) { + rt = rtable_match(tableid, info->rti_info[RTAX_DST], NULL); + if ((error = route_arp_conflict(rt, info))) { rtfree(rt); rt = NULL; - goto flush; + break; } /* @@ -707,16 +762,14 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, rtfree(rt); rt = NULL; - error = rtrequest(RTM_ADD, &info, prio, &rt, tableid); + error = rtrequest(RTM_ADD, info, prio, &rt, tableid); if (error == 0) rtm_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); - else - goto flush; break; case RTM_DELETE: - rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY], + rt = rtable_lookup(tableid, info->rti_info[RTAX_DST], + info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY], prio); /* @@ -748,14 +801,14 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, rtfree(rt); rt = NULL; - error = rtrequest(RTM_DELETE, &info, prio, &rt, tableid); + error = rtrequest(RTM_DELETE, info, prio, &rt, tableid); if (error != 0) - goto flush; + break; break; case RTM_CHANGE: case RTM_LOCK: - rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY], + rt = rtable_lookup(tableid, info->rti_info[RTAX_DST], + info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY], prio); #ifndef SMALL_KERNEL /* @@ -763,7 +816,7 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, * a matching gateway. */ if ((rt != NULL) && ISSET(rt->rt_flags, RTF_MPATH) && - (info.rti_info[RTAX_GATEWAY] == NULL)) { + (info->rti_info[RTAX_GATEWAY] == NULL)) { rtfree(rt); rt = NULL; } @@ -772,10 +825,10 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, * If RTAX_GATEWAY is the argument we're trying to * change, try to find a compatible route. */ - if ((rt == NULL) && (info.rti_info[RTAX_GATEWAY] != NULL) && + if ((rt == NULL) && (info->rti_info[RTAX_GATEWAY] != NULL) && (rtm->rtm_type == RTM_CHANGE)) { - rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK], NULL, prio); + rt = rtable_lookup(tableid, info->rti_info[RTAX_DST], + info->rti_info[RTAX_NETMASK], NULL, prio); #ifndef SMALL_KERNEL /* Ensure we don't pick a multipath one. */ if ((rt != NULL) && ISSET(rt->rt_flags, RTF_MPATH)) { @@ -787,26 +840,26 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, if (rt == NULL) { error = ESRCH; - goto flush; + break; } /* * RTM_CHANGE/LOCK need a perfect match. */ - plen = rtable_satoplen(info.rti_info[RTAX_DST]->sa_family, - info.rti_info[RTAX_NETMASK]); + plen = rtable_satoplen(info->rti_info[RTAX_DST]->sa_family, + info->rti_info[RTAX_NETMASK]); if (rt_plen(rt) != plen ) { error = ESRCH; - goto flush; + break; } switch (rtm->rtm_type) { case RTM_CHANGE: - if (info.rti_info[RTAX_GATEWAY] != NULL) + if (info->rti_info[RTAX_GATEWAY] != NULL) if (rt->rt_gateway == NULL || bcmp(rt->rt_gateway, - info.rti_info[RTAX_GATEWAY], - info.rti_info[RTAX_GATEWAY]->sa_len)) { + info->rti_info[RTAX_GATEWAY], + info->rti_info[RTAX_GATEWAY]->sa_len)) { newgate = 1; } /* @@ -815,11 +868,11 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, * flags may also be different; ifp may be specified * by ll sockaddr when protocol address is ambiguous. */ - if (newgate || info.rti_info[RTAX_IFP] != NULL || - info.rti_info[RTAX_IFA] != NULL) { - if ((error = rt_getifa(&info, tableid)) != 0) - goto flush; - ifa = info.rti_ifa; + if (newgate || info->rti_info[RTAX_IFP] != NULL || + info->rti_info[RTAX_IFA] != NULL) { + if ((error = rt_getifa(info, tableid)) != 0) + break; + ifa = info->rti_ifa; if (rt->rt_ifa != ifa) { ifp = if_get(rt->rt_ifidx); KASSERT(ifp != NULL); @@ -838,17 +891,17 @@ route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, } } change: - if (info.rti_info[RTAX_GATEWAY] != NULL && (error = - rt_setgate(rt, info.rti_info[RTAX_GATEWAY], + if (info->rti_info[RTAX_GATEWAY] != NULL && (error = + rt_setgate(rt, info->rti_info[RTAX_GATEWAY], tableid))) - goto flush; + break; #ifdef MPLS if ((rtm->rtm_flags & RTF_MPLS) && - info.rti_info[RTAX_SRC] != NULL) { + info->rti_info[RTAX_SRC] != NULL) { struct rt_mpls *rt_mpls; psa_mpls = (struct sockaddr_mpls *) - info.rti_info[RTAX_SRC]; + info->rti_info[RTAX_SRC]; if (rt->rt_llinfo == NULL) { rt->rt_llinfo = @@ -863,7 +916,7 @@ change: psa_mpls->smpls_label; } - rt_mpls->mpls_operation = info.rti_mpls; + rt_mpls->mpls_operation = info->rti_mpls; /* XXX: set experimental bits */ @@ -883,7 +936,7 @@ change: #ifdef BFD if (ISSET(rtm->rtm_flags, RTF_BFD)) { if ((error = bfdset(rt))) - goto flush; + break; } else if (!ISSET(rtm->rtm_flags, RTF_BFD) && ISSET(rtm->rtm_fmask, RTF_BFD)) { bfdclear(rt); @@ -904,14 +957,14 @@ change: ifp->if_rtrequest(ifp, RTM_ADD, rt); if_put(ifp); - if (info.rti_info[RTAX_LABEL] != NULL) { + if (info->rti_info[RTAX_LABEL] != NULL) { char *rtlabel = ((struct sockaddr_rtlabel *) - info.rti_info[RTAX_LABEL])->sr_label; + info->rti_info[RTAX_LABEL])->sr_label; rtlabel_unref(rt->rt_labelid); rt->rt_labelid = rtlabel_name2id(rtlabel); } - if_group_routechange(info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK]); + if_group_routechange(info->rti_info[RTAX_DST], + info->rti_info[RTAX_NETMASK]); /* FALLTHROUGH */ case RTM_LOCK: rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); @@ -921,68 +974,14 @@ change: } break; case RTM_GET: - rt = rtable_lookup(tableid, info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK], info.rti_info[RTAX_GATEWAY], + rt = rtable_lookup(tableid, info->rti_info[RTAX_DST], + info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY], prio); - if (rt == NULL) { + 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 = rtm_report(rt, type, seq, tableid); -flush: - rtfree(rt); - if (error) { - rtm->rtm_errno = error; - } else { - rtm->rtm_flags |= RTF_DONE; - } - - /* - * 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); - return (error); - } - /* There is another listener, so construct message */ - rp = sotorawcb(so); - rp->rcb_proto.sp_family = 0; /* Avoid us */ - } - if (rtm) { - if (m_copyback(m, 0, rtm->rtm_msglen, rtm, M_NOWAIT)) { - m_freem(m); - m = NULL; - } else if (m->m_pkthdr.len > rtm->rtm_msglen) - m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); - free(rtm, M_RTABLE, 0); - } - if (m) - route_input(m, info.rti_info[RTAX_DST] ? - info.rti_info[RTAX_DST]->sa_family : AF_UNSPEC); - if (rp) - rp->rcb_proto.sp_family = PF_ROUTE; /* Readd us */ - + *prt = rt; return (error); } |