From 82c23eba89cf4963f60f4fb2b1f416904145edeb Mon Sep 17 00:00:00 2001 From: Bill Fenner Date: Mon, 11 Nov 1996 04:56:32 +0000 Subject: [PATCH] Add the IP_RECVIF socket option, which supplies a packet's incoming interface using a sockaddr_dl. Fix the other packet-information socket options (SO_TIMESTAMP, IP_RECVDSTADDR) to work for multicast UDP and raw sockets as well. (They previously only worked for unicast UDP). --- sys/kern/uipc_sockbuf.c | 28 +++++++++- sys/kern/uipc_socket2.c | 28 +++++++++- sys/netinet/in.h | 3 +- sys/netinet/in_pcb.h | 6 +- sys/netinet/ip_input.c | 62 ++++++++++++++++++++- sys/netinet/ip_output.c | 12 +++- sys/netinet/ip_var.h | 4 +- sys/netinet/raw_ip.c | 34 ++++++++---- sys/netinet/udp_usrreq.c | 115 ++++++++------------------------------- 9 files changed, 180 insertions(+), 112 deletions(-) diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 954831245570..024ce995ab40 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 - * $Id: uipc_socket2.c,v 1.15 1996/10/07 04:32:27 pst Exp $ + * $Id: uipc_socket2.c,v 1.16 1996/10/11 19:26:35 pst Exp $ */ #include @@ -800,6 +800,32 @@ sbdroprecord(sb) } } +/* + * Create a "control" mbuf containing the specified data + * with the specified type for presentation on a socket buffer. + */ +struct mbuf * +sbcreatecontrol(p, size, type, level) + caddr_t p; + register int size; + int type, level; +{ + register struct cmsghdr *cp; + struct mbuf *m; + + if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) + return ((struct mbuf *) NULL); + cp = mtod(m, struct cmsghdr *); + /* XXX check size? */ + (void)memcpy(CMSG_DATA(cp), p, size); + size += sizeof(*cp); + m->m_len = size; + cp->cmsg_len = size; + cp->cmsg_level = level; + cp->cmsg_type = type; + return (m); +} + #ifdef PRU_OLDSTYLE /* * The following routines mediate between the old-style `pr_usrreq' diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 954831245570..024ce995ab40 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 - * $Id: uipc_socket2.c,v 1.15 1996/10/07 04:32:27 pst Exp $ + * $Id: uipc_socket2.c,v 1.16 1996/10/11 19:26:35 pst Exp $ */ #include @@ -800,6 +800,32 @@ sbdroprecord(sb) } } +/* + * Create a "control" mbuf containing the specified data + * with the specified type for presentation on a socket buffer. + */ +struct mbuf * +sbcreatecontrol(p, size, type, level) + caddr_t p; + register int size; + int type, level; +{ + register struct cmsghdr *cp; + struct mbuf *m; + + if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) + return ((struct mbuf *) NULL); + cp = mtod(m, struct cmsghdr *); + /* XXX check size? */ + (void)memcpy(CMSG_DATA(cp), p, size); + size += sizeof(*cp); + m->m_len = size; + cp->cmsg_len = size; + cp->cmsg_level = level; + cp->cmsg_type = type; + return (m); +} + #ifdef PRU_OLDSTYLE /* * The following routines mediate between the old-style `pr_usrreq' diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 21cfeef0f026..b0fbc3d2a45c 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 - * $Id: in.h,v 1.21 1996/10/19 20:23:12 alex Exp $ + * $Id: in.h,v 1.22 1996/10/22 22:25:54 sos Exp $ */ #ifndef _NETINET_IN_H_ @@ -219,6 +219,7 @@ struct ip_opts { #define IP_RSVP_VIF_ON 17 /* set RSVP per-vif socket */ #define IP_RSVP_VIF_OFF 18 /* unset RSVP per-vif socket */ #define IP_PORTRANGE 19 /* int; range to choose for unspec port */ +#define IP_RECVIF 20 /* bool; receive reception if w/dgram */ #define IP_FW_ADD 50 /* add a firewall rule to chain */ #define IP_FW_DEL 51 /* delete a firewall rule from chain */ diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 723d4ecdbb09..67be78340796 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)in_pcb.h 8.1 (Berkeley) 6/10/93 - * $Id: in_pcb.h,v 1.13 1996/10/07 19:06:08 davidg Exp $ + * $Id: in_pcb.h,v 1.14 1996/10/30 06:13:10 peter Exp $ */ #ifndef _NETINET_IN_PCB_H_ @@ -78,11 +78,13 @@ struct inpcbinfo { #define INP_RECVOPTS 0x01 /* receive incoming IP options */ #define INP_RECVRETOPTS 0x02 /* receive IP options for reply */ #define INP_RECVDSTADDR 0x04 /* receive IP dst address */ -#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR) #define INP_HDRINCL 0x08 /* user supplies entire IP header */ #define INP_HIGHPORT 0x10 /* user wants "high" port binding */ #define INP_LOWPORT 0x20 /* user wants "low" port binding */ #define INP_ANONPORT 0x40 /* port chosen for user */ +#define INP_RECVIF 0x80 /* receive incoming interface */ +#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ + INP_RECVIF) #define INPLOOKUP_WILDCARD 1 diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index cfe1d4abf471..9c57dff56409 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 - * $Id: ip_input.c,v 1.49 1996/10/22 22:25:58 sos Exp $ + * $Id: ip_input.c,v 1.50 1996/10/25 17:57:45 fenner Exp $ * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ */ @@ -39,6 +39,8 @@ #include "opt_ipfw.h" +#include + #include #include #include @@ -53,6 +55,7 @@ #include #include +#include #include #include @@ -1313,6 +1316,63 @@ ip_forward(m, srcrt) icmp_error(mcopy, type, code, dest, destifp); } +void +ip_savecontrol(inp, mp, ip, m) + register struct inpcb *inp; + register struct mbuf **mp; + register struct ip *ip; + register struct mbuf *m; +{ + if (inp->inp_socket->so_options & SO_TIMESTAMP) { + struct timeval tv; + + microtime(&tv); + *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), + SCM_TIMESTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } + if (inp->inp_flags & INP_RECVDSTADDR) { + *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, + sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } +#ifdef notyet + /* XXX + * Moving these out of udp_input() made them even more broken + * than they already were. + */ + /* options were tossed already */ + if (inp->inp_flags & INP_RECVOPTS) { + *mp = sbcreatecontrol((caddr_t) opts_deleted_above, + sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } + /* ip_srcroute doesn't do what we want here, need to fix */ + if (inp->inp_flags & INP_RECVRETOPTS) { + *mp = sbcreatecontrol((caddr_t) ip_srcroute(), + sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } +#endif + if (inp->inp_flags & INP_RECVIF) { + struct sockaddr_dl sdl; + + sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data[0]); + sdl.sdl_family = AF_LINK; + sdl.sdl_index = m->m_pkthdr.rcvif ? + m->m_pkthdr.rcvif->if_index : 0; + sdl.sdl_nlen = sdl.sdl_alen = sdl.sdl_slen = 0; + *mp = sbcreatecontrol((caddr_t) &sdl, sdl.sdl_len, + IP_RECVIF, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } +} + int ip_rsvp_init(struct socket *so) { diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 85cd563c9f7a..8addbe65984c 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 - * $Id: ip_output.c,v 1.43 1996/10/07 19:21:46 wollman Exp $ + * $Id: ip_output.c,v 1.44 1996/10/22 22:26:02 sos Exp $ */ #define _IP_VHL @@ -628,6 +628,7 @@ ip_ctloutput(op, so, level, optname, mp) case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: + case IP_RECVIF: if (m == 0 || m->m_len != sizeof(int)) error = EINVAL; else { @@ -658,6 +659,10 @@ ip_ctloutput(op, so, level, optname, mp) case IP_RECVDSTADDR: OPTSET(INP_RECVDSTADDR); break; + + case IP_RECVIF: + OPTSET(INP_RECVIF); + break; } } break; @@ -728,6 +733,7 @@ ip_ctloutput(op, so, level, optname, mp) case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: + case IP_RECVIF: *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(int); switch (optname) { @@ -753,6 +759,10 @@ ip_ctloutput(op, so, level, optname, mp) case IP_RECVDSTADDR: optval = OPTBIT(INP_RECVDSTADDR); break; + + case IP_RECVIF: + optval = OPTBIT(INP_RECVIF); + break; } *mtod(m, int *) = optval; break; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 59b3df8795c7..6f36a03e694f 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ip_var.h 8.2 (Berkeley) 1/9/95 - * $Id: ip_var.h,v 1.23 1996/10/23 18:35:50 wollman Exp $ + * $Id: ip_var.h,v 1.24 1996/10/25 17:57:46 fenner Exp $ */ #ifndef _NETINET_IP_VAR_H_ @@ -177,6 +177,8 @@ extern int (*ip_mforward) __P((struct ip *, struct ifnet *, struct mbuf *, struct ip_moptions *)); int ip_output __P((struct mbuf *, struct mbuf *, struct route *, int, struct ip_moptions *)); +void ip_savecontrol __P((struct inpcb *, struct mbuf **, struct ip *, + struct mbuf *)); void ip_slowtimo __P((void)); struct mbuf * ip_srcroute __P((void)); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 21ef2f93aaea..b7c8af94d7be 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 - * $Id: raw_ip.c,v 1.36 1996/10/07 19:21:46 wollman Exp $ + * $Id: raw_ip.c,v 1.37 1996/10/25 17:57:48 fenner Exp $ */ #include @@ -107,7 +107,8 @@ rip_input(m, iphlen) { register struct ip *ip = mtod(m, struct ip *); register struct inpcb *inp; - struct socket *last = 0; + struct inpcb *last = 0; + struct mbuf *opts = 0; ripsrc.sin_addr = ip->ip_src; for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { @@ -122,23 +123,34 @@ rip_input(m, iphlen) if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); if (n) { - if (sbappendaddr(&last->so_rcv, + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, n); + if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, n, - (struct mbuf *)0) == 0) + opts) == 0) { /* should notify about lost packet */ m_freem(n); - else - sorwakeup(last); + if (opts) + m_freem(opts); + } else + sorwakeup(last->inp_socket); + opts = 0; } } - last = inp->inp_socket; + last = inp; } if (last) { - if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, - m, (struct mbuf *)0) == 0) + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, m); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&ripsrc, m, opts) == 0) { m_freem(m); - else - sorwakeup(last); + if (opts) + m_freem(opts); + } else + sorwakeup(last->inp_socket); } else { m_freem(m); ipstat.ips_noproto++; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 4c3c62f27ffc..1d7c3f5b2111 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 - * $Id: udp_usrreq.c,v 1.29 1996/10/07 19:06:12 davidg Exp $ + * $Id: udp_usrreq.c,v 1.30 1996/10/25 17:57:53 fenner Exp $ */ #include @@ -94,8 +94,6 @@ static void udp_detach __P((struct inpcb *)); static int udp_output __P((struct inpcb *, struct mbuf *, struct mbuf *, struct mbuf *)); static void udp_notify __P((struct inpcb *, int)); -static struct mbuf *udp_saveopt __P((caddr_t, int, int)); -static struct mbuf *udp_timestamp __P((void)); void udp_init() @@ -180,7 +178,7 @@ udp_input(m, iphlen) if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { - struct socket *last; + struct inpcb *last; /* * Deliver a multicast or broadcast datagram to *all* sockets * for which the local and remote addresses and ports match @@ -228,16 +226,22 @@ udp_input(m, iphlen) struct mbuf *n; if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { - if (sbappendaddr(&last->so_rcv, + if (last->inp_flags & INP_CONTROLOPTS + || last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, n); + if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&udp_in, - n, (struct mbuf *)0) == 0) { + n, opts) == 0) { m_freem(n); + if (opts) + m_freem(opts); udpstat.udps_fullsock++; } else - sorwakeup(last); + sorwakeup(last->inp_socket); + opts = 0; } } - last = inp->inp_socket; + last = inp; /* * Don't look for additional matches if this one does * not have either the SO_REUSEPORT or SO_REUSEADDR @@ -246,7 +250,7 @@ udp_input(m, iphlen) * port. It * assumes that an application will never * clear these options after setting them. */ - if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) + if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) break; } @@ -259,12 +263,16 @@ udp_input(m, iphlen) udpstat.udps_noportbcast++; goto bad; } - if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, - m, (struct mbuf *)0) == 0) { + if (last->inp_flags & INP_CONTROLOPTS + || last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, m); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&udp_in, + m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } - sorwakeup(last); + sorwakeup(last->inp_socket); return; } /* @@ -299,36 +307,8 @@ udp_input(m, iphlen) udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; if (inp->inp_flags & INP_CONTROLOPTS - || inp->inp_socket->so_options & SO_TIMESTAMP) { - struct mbuf **mp = &opts; - - if (inp->inp_socket->so_options & SO_TIMESTAMP) { - if (*mp = udp_timestamp()) - mp = &(*mp)->m_next; - } - if (inp->inp_flags & INP_RECVDSTADDR) { - *mp = udp_saveopt((caddr_t) &ip->ip_dst, - sizeof(struct in_addr), IP_RECVDSTADDR); - if (*mp) - mp = &(*mp)->m_next; - } -#ifdef notyet - /* options were tossed above */ - if (inp->inp_flags & INP_RECVOPTS) { - *mp = udp_saveopt((caddr_t) opts_deleted_above, - sizeof(struct in_addr), IP_RECVOPTS); - if (*mp) - mp = &(*mp)->m_next; - } - /* ip_srcroute doesn't do what we want here, need to fix */ - if (inp->inp_flags & INP_RECVRETOPTS) { - *mp = udp_saveopt((caddr_t) ip_srcroute(), - sizeof(struct in_addr), IP_RECVRETOPTS); - if (*mp) - mp = &(*mp)->m_next; - } -#endif - } + || inp->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(inp, &opts, ip, m); iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_pkthdr.len -= iphlen; @@ -346,57 +326,6 @@ udp_input(m, iphlen) m_freem(opts); } -/* - * Create a "control" mbuf containing the specified data - * with the specified type for presentation with a datagram. - */ -struct mbuf * -udp_saveopt(p, size, type) - caddr_t p; - register int size; - int type; -{ - register struct cmsghdr *cp; - struct mbuf *m; - - if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) - return ((struct mbuf *) NULL); - cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); - bcopy(p, CMSG_DATA(cp), size); - size += sizeof(*cp); - m->m_len = size; - cp->cmsg_len = size; - cp->cmsg_level = IPPROTO_IP; - cp->cmsg_type = type; - return (m); -} - -/* - * Create an mbuf with the SCM_TIMESTAMP socket option data (struct timeval) - * inside. This really isn't UDP specific; but there's not really a better - * place for it yet.. - */ -static struct mbuf * -udp_timestamp() -{ - register struct cmsghdr *cp; - struct mbuf *m; - struct timeval tv; - - MGET(m, M_DONTWAIT, MT_CONTROL); - if (m == 0) - return (struct mbuf *) 0; - - microtime(&tv); - cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); - cp->cmsg_len = - m->m_len = sizeof(*cp) + sizeof(struct timeval); - cp->cmsg_level = SOL_SOCKET; - cp->cmsg_type = SCM_TIMESTAMP; - (void) memcpy(CMSG_DATA(cp), &tv, sizeof(struct timeval)); - return (m); -} - /* * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status.