diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -150,7 +149,7 @@ int (*carp_get_vhid_p)(struct ifaddr *); /* - * Used by rtsock/raw_input callback code to decide whether to filter the update + * Used by rtsock callback code to decide whether to filter the update * notification to a socket bound to a particular FIB. */ #define RTS_FILTER_FIB M_PROTO8 @@ -159,7 +158,14 @@ */ #define m_rtsock_family m_pkthdr.PH_loc.eight[0] +struct rcb { + LIST_ENTRY(rcb) list; + struct socket *rcb_socket; + sa_family_t rcb_family; +}; + typedef struct { + LIST_HEAD(, rcb) cblist; int ip_count; /* attached w/ AF_INET */ int ip6_count; /* attached w/ AF_INET6 */ int any_count; /* total attached */ @@ -198,7 +204,6 @@ uint32_t weight, struct walkarg *w); 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_getmetrics(const struct rtentry *rt, const struct nhop_object *nh, struct rt_metrics *out); static void rt_dispatch(struct mbuf *, sa_family_t); @@ -267,84 +272,85 @@ vnet_rts_uninit, 0); #endif -static int -raw_input_rts_cb(struct mbuf *m, struct sockproto *proto, struct sockaddr *src, - struct rawcb *rp) +static void +rts_append_data(struct socket *so, struct mbuf *m) { - int fibnum; - - KASSERT(m != NULL, ("%s: m is NULL", __func__)); - KASSERT(proto != NULL, ("%s: proto is NULL", __func__)); - KASSERT(rp != NULL, ("%s: rp is NULL", __func__)); - /* No filtering requested. */ - if ((m->m_flags & RTS_FILTER_FIB) == 0) - return (0); - - /* Check if it is a rts and the fib matches the one of the socket. */ - fibnum = M_GETFIB(m); - if (proto->sp_family != PF_ROUTE || - rp->rcb_socket == NULL || - rp->rcb_socket->so_fibnum == fibnum) - return (0); - - /* Filtering requested and no match, the socket shall be skipped. */ - return (1); + if (sbappendaddr(&so->so_rcv, &route_src, m, NULL) == 0) { + soroverflow(so); + m_freem(m); + } else + sorwakeup(so); } static void rts_input(struct mbuf *m) { - struct sockproto route_proto; + struct rcb *rcb; + struct socket *last; - route_proto.sp_family = PF_ROUTE; - route_proto.sp_protocol = m->m_rtsock_family; - - raw_input_ext(m, &route_proto, &route_src, raw_input_rts_cb); -} - -/* - * It really doesn't make any sense at all for this code to share much - * with raw_usrreq.c, since its functionality is so restricted. XXX - */ -static void -rts_abort(struct socket *so) -{ + last = NULL; + RTSOCK_LOCK(); + LIST_FOREACH(rcb, &V_route_cb.cblist, list) { + if (rcb->rcb_family != AF_UNSPEC && + rcb->rcb_family != m->m_rtsock_family) + continue; + if ((m->m_flags & RTS_FILTER_FIB) && + M_GETFIB(m) != rcb->rcb_socket->so_fibnum) + continue; + if (last != NULL) { + struct mbuf *n; - raw_usrreqs.pru_abort(so); + n = m_copym(m, 0, M_COPYALL, M_NOWAIT); + if (n != NULL) + rts_append_data(last, n); + } + last = rcb->rcb_socket; + } + if (last != NULL) + rts_append_data(last, m); + else + m_freem(m); + RTSOCK_UNLOCK(); } static void rts_close(struct socket *so) { - raw_usrreqs.pru_close(so); + soisdisconnected(so); } -/* pru_accept is EOPNOTSUPP */ +static SYSCTL_NODE(_net, OID_AUTO, rtsock, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, + "Routing socket infrastructure"); +static u_long rts_sendspace = 8192; +SYSCTL_ULONG(_net_rtsock, OID_AUTO, sendspace, CTLFLAG_RW, &rts_sendspace, 0, + "Default routing socket send space"); +static u_long rts_recvspace = 8192; +SYSCTL_ULONG(_net_rtsock, OID_AUTO, recvspace, CTLFLAG_RW, &rts_recvspace, 0, + "Default routing socket receive space"); static int rts_attach(struct socket *so, int proto, struct thread *td) { - struct rawcb *rp; + struct rcb *rcb; int error; - KASSERT(so->so_pcb == NULL, ("rts_attach: so_pcb != NULL")); + error = soreserve(so, rts_sendspace, rts_recvspace); + if (error) + return (error); - /* XXX */ - rp = malloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO); + rcb = malloc(sizeof(*rcb), M_PCB, M_WAITOK); + rcb->rcb_socket = so; + rcb->rcb_family = proto; - so->so_pcb = (caddr_t)rp; + so->so_pcb = rcb; so->so_fibnum = td->td_proc->p_fibnum; - error = raw_attach(so, proto); - rp = sotorawcb(so); - if (error) { - so->so_pcb = NULL; - free(rp, M_PCB); - return error; - } + so->so_options |= SO_USELOOPBACK; + RTSOCK_LOCK(); - switch(rp->rcb_proto.sp_protocol) { + LIST_INSERT_HEAD(&V_route_cb.cblist, rcb, list); + switch (proto) { case AF_INET: V_route_cb.ip_count++; break; @@ -355,36 +361,18 @@ V_route_cb.any_count++; RTSOCK_UNLOCK(); soisconnected(so); - so->so_options |= SO_USELOOPBACK; - return 0; -} -static int -rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td) -{ - - return (raw_usrreqs.pru_bind(so, nam, td)); /* xxx just EINVAL */ -} - -static int -rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td) -{ - - return (raw_usrreqs.pru_connect(so, nam, td)); /* XXX just EINVAL */ + return (0); } -/* pru_connect2 is EOPNOTSUPP */ -/* pru_control is EOPNOTSUPP */ - static void rts_detach(struct socket *so) { - struct rawcb *rp = sotorawcb(so); - - KASSERT(rp != NULL, ("rts_detach: rp == NULL")); + struct rcb *rcb = so->so_pcb; RTSOCK_LOCK(); - switch(rp->rcb_proto.sp_protocol) { + LIST_REMOVE(rcb, list); + switch(rcb->rcb_family) { case AF_INET: V_route_cb.ip_count--; break; @@ -394,66 +382,18 @@ } V_route_cb.any_count--; RTSOCK_UNLOCK(); - raw_usrreqs.pru_detach(so); + free(rcb, M_PCB); + so->so_pcb = NULL; } -static int -rts_disconnect(struct socket *so) -{ - - return (raw_usrreqs.pru_disconnect(so)); -} - -/* pru_listen is EOPNOTSUPP */ - -static int -rts_peeraddr(struct socket *so, struct sockaddr **nam) -{ - - return (raw_usrreqs.pru_peeraddr(so, nam)); -} - -/* pru_rcvd is EOPNOTSUPP */ -/* pru_rcvoob is EOPNOTSUPP */ - -static int -rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, - struct mbuf *control, struct thread *td) -{ - - return (raw_usrreqs.pru_send(so, flags, m, nam, control, td)); -} - -/* pru_sense is null */ - static int rts_shutdown(struct socket *so) { - return (raw_usrreqs.pru_shutdown(so)); -} - -static int -rts_sockaddr(struct socket *so, struct sockaddr **nam) -{ - - return (raw_usrreqs.pru_sockaddr(so, nam)); + socantsendmore(so); + return (0); } -static struct pr_usrreqs route_usrreqs = { - .pru_abort = rts_abort, - .pru_attach = rts_attach, - .pru_bind = rts_bind, - .pru_connect = rts_connect, - .pru_detach = rts_detach, - .pru_disconnect = rts_disconnect, - .pru_peeraddr = rts_peeraddr, - .pru_send = rts_send, - .pru_shutdown = rts_shutdown, - .pru_sockaddr = rts_sockaddr, - .pru_close = rts_close, -}; - #ifndef _SOCKADDR_UNION_DEFINED #define _SOCKADDR_UNION_DEFINED /* @@ -1021,9 +961,9 @@ } #endif -/*ARGSUSED*/ static int -route_output(struct mbuf *m, struct socket *so, ...) +rts_send(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *nam, struct mbuf *control, struct thread *td) { struct rt_msghdr *rtm = NULL; struct rt_addrinfo info; @@ -1038,6 +978,13 @@ struct rib_cmd_info rc; struct nhop_object *nh; + if ((flags & PRUS_OOB) || control != NULL) { + m_freem(m); + if (control != NULL) + m_freem(control); + return (EOPNOTSUPP); + } + fibnum = so->so_fibnum; #define senderr(e) { error = e; goto flush;} if (m == NULL || ((m->m_len < sizeof(long)) && @@ -1231,7 +1178,7 @@ send_rtm_reply(struct socket *so, struct rt_msghdr *rtm, struct mbuf *m, sa_family_t saf, u_int fibnum, int rtm_errno) { - struct rawcb *rp = NULL; + struct rcb *rcb = NULL; /* * Check to see if we don't want our own messages. @@ -1244,7 +1191,7 @@ return; } /* There is another listener, so construct message */ - rp = sotorawcb(so); + rcb = so->so_pcb; } if (rtm != NULL) { @@ -1265,15 +1212,15 @@ if (m != NULL) { M_SETFIB(m, fibnum); m->m_flags |= RTS_FILTER_FIB; - if (rp) { + if (rcb) { /* * XXX insure we don't get a copy by * invalidating our protocol */ - unsigned short family = rp->rcb_proto.sp_family; - rp->rcb_proto.sp_family = 0; + sa_family_t family = rcb->rcb_family; + rcb->rcb_family = AF_UNSPEC; rt_dispatch(m, saf); - rp->rcb_proto.sp_family = family; + rcb->rcb_family = family; } else rt_dispatch(m, saf); } @@ -2696,13 +2643,20 @@ static struct domain routedomain; /* or at least forward */ +static struct pr_usrreqs route_usrreqs = { + .pru_abort = rts_close, + .pru_attach = rts_attach, + .pru_detach = rts_detach, + .pru_send = rts_send, + .pru_shutdown = rts_shutdown, + .pru_close = rts_close, +}; + static struct protosw routesw[] = { { .pr_type = SOCK_RAW, .pr_domain = &routedomain, .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_output = route_output, - .pr_ctlinput = raw_ctlinput, .pr_usrreqs = &route_usrreqs } };