summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2017-03-06 10:19:17 +0000
committermpi <mpi@openbsd.org>2017-03-06 10:19:17 +0000
commit96ac089d51c19253b98ed7ba484e2bfef81efc6b (patch)
tree96c5040a773bcd6d6219c356c7d80b5dad61ea17
parentGuard headers to make sure userland do not look at them. (diff)
downloadwireguard-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.c213
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);
}