Module Name: src Committed By: martin Date: Sun Mar 18 10:57:02 UTC 2018
Modified Files: src/share/man/man4 [netbsd-8]: ip.4 src/share/man/man9 [netbsd-8]: sockopt.9 src/sys/kern [netbsd-8]: uipc_socket.c uipc_syscalls.c src/sys/netinet [netbsd-8]: in.h in_pcb.c in_pcb.h ip_input.c ip_output.c src/sys/sys [netbsd-8]: socketvar.h Log Message: Pull up following revision(s) (requested by tih in ticket #639): sys/kern/uipc_socket.c: revision 1.258 sys/kern/uipc_socket.c: revision 1.259 sys/netinet/ip_input.c: revision 1.364 (via patch) sys/netinet/ip_output.c: revision 1.289 sys/netinet/in.h: revision 1.102 sys/netinet/in_pcb.c: revision 1.181 share/man/man9/sockopt.9: revision 1.11 sys/netinet/in_pcb.h: revision 1.65 sys/sys/socketvar.h: revision 1.146 sys/kern/uipc_syscalls.c: revision 1.189 sys/netinet/ip_output.c: revision 1.290 share/man/man4/ip.4: revision 1.41 share/man/man4/ip.4: revision 1.42 sys/kern/uipc_syscalls.c: revision 1.190 pass valsize for getsockopt like we do for setsockopt make sure that we have enough space, don't require the exact size (Tom Ivar Helbekkmo) 1) "#define ipi_spec_dst ipi_addr" in <netinet/in.h> 2) Change the IP_RECVPKTINFO option to control the generation of IP_PKTINFO control messages, the way it's done in Solaris. 3) Remove the superfluous IP_RECVPKTINFO control message. 4) Change the IP_PKTINFO option to do different things depending on the parameter it's supplied with: - If it's sizeof(int), assume it's being used as in Linux: - If it's non-zero, turn on the IP_RECVPKTINFO option. - If it's zero, turn off the IP_RECVPKTINFO option. - If it's sizeof(struct in_pktinfo), assume it's being used as in Solaris, to set a default for the source interface and/or source address for outgoing packets on the socket. 5) Return what Linux or Solaris compatible code expects, depending on data size, and just added a fallback to a Linux (and current NetBSD) compatible value if the size is unknown (as it is now), or, in the future, if the calling application specifies a receiving buffer that doesn't match either data item. From: Tom Ivar Helbekkmo new sentence-new line Remove comment now that the getsockopt code passes the size. Add a new sockopt member to keep track of the actual size of the option that should be returned to the caller in getsockopt(2). (Tom Ivar Helbekkmo) To generate a diff of this commit: cvs rdiff -u -r1.36.20.1 -r1.36.20.2 src/share/man/man4/ip.4 cvs rdiff -u -r1.10 -r1.10.4.1 src/share/man/man9/sockopt.9 cvs rdiff -u -r1.255 -r1.255.2.1 src/sys/kern/uipc_socket.c cvs rdiff -u -r1.186 -r1.186.6.1 src/sys/kern/uipc_syscalls.c cvs rdiff -u -r1.100.6.2 -r1.100.6.3 src/sys/netinet/in.h cvs rdiff -u -r1.178.4.2 -r1.178.4.3 src/sys/netinet/in_pcb.c cvs rdiff -u -r1.63.6.1 -r1.63.6.2 src/sys/netinet/in_pcb.h cvs rdiff -u -r1.355.2.5 -r1.355.2.6 src/sys/netinet/ip_input.c cvs rdiff -u -r1.279.2.6 -r1.279.2.7 src/sys/netinet/ip_output.c cvs rdiff -u -r1.144 -r1.144.6.1 src/sys/sys/socketvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man4/ip.4 diff -u src/share/man/man4/ip.4:1.36.20.1 src/share/man/man4/ip.4:1.36.20.2 --- src/share/man/man4/ip.4:1.36.20.1 Thu Dec 21 21:08:13 2017 +++ src/share/man/man4/ip.4 Sun Mar 18 10:57:02 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: ip.4,v 1.36.20.1 2017/12/21 21:08:13 snj Exp $ +.\" $NetBSD: ip.4,v 1.36.20.2 2018/03/18 10:57:02 martin Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)ip.4 8.2 (Berkeley) 11/30/93 .\" -.Dd August 10, 2017 +.Dd December 31, 2017 .Dt IP 4 .Os .Sh NAME @@ -111,8 +111,8 @@ setsockopt(s, IPPROTO_IP, IP_IPSEC_POLIC .Ed .Pp The -.Dv IP_PKTINFO -option can be used to turn on receiving of information about the source +.Dv IP_RECVPKTINFO +option can be used to turn on receiving of information about the destination address of the packet, and the interface index. The information is passed in a .Vt struct in_pktinfo @@ -132,13 +132,25 @@ cmsg_type = IP_PKTINFO .Pp For .Xr sendmsg 2 , -the source address or output interface can be specified by adding +the source address or output interface can be specified by adding an .Dv IP_PKTINFO -to the control part of the message on a +message to the control part of the message on a .Dv SOCK_DGRAM or .Dv SOCK_RAW socket. +Setting ipi_ifindex will cause the primary address of that interface +to be used; setting ipi_addr will directly choose that address. +The IP_PKTINFO cmsghdr structure from a received message may be +used unchanged, in which case the outgoing message will be sent +from the address the incoming message was received on. +.Pp +Setting the +.Dv IP_PKTINFO +option on a socket, with the same +.Vt struct in_pktinfo +structure, will set the default source address to be used until set +again, unless explicitly overridden on a per-packet basis, as above. .Pp The .Dv IP_PORTALGO @@ -199,6 +211,19 @@ cmsg_level = IPPROTO_IP cmsg_type = IP_RECVDSTADDR .Ed .Pp +For +.Xr sendmsg 2 , +the source address can be specified by adding +.Dv IP_SENDSRCADDR +to the control part of the message on a +.Dv SOCK_DGRAM +or +.Dv SOCK_RAW +socket. +The IP_RECVDSTADDR cmsghdr structure from a received message may +be used unchanged, in which case the outgoing message will be sent +from the address the incoming message was received on. +.Pp If the .Dv IP_RECVIF option is enabled on a @@ -219,12 +244,6 @@ cmsg_level = IPPROTO_IP cmsg_type = IP_RECVIF .Ed .Pp -The -.Dv IP_RECVPKTINFO -option is similar to the -.Dv IP_PKTINFO -one, only in this case the inbound information is returned. -.Pp If the .Dv IP_RECVTTL option is enabled on a @@ -491,6 +510,25 @@ An unknown socket option name was given. The IP option field was improperly formed; an option field was shorter than the minimum value or longer than the option buffer provided. .El +.Sh COMPATIBILITY +The +.Dv IP_RECVPKTINFO +option is used because it is directly compatible with Solaris, AIX, etc., +and the +.Dv IP_PKTINFO +option is intended to be used in their manner, to set the default source +address for outgoing packets on a +.Dv SOCK_DGRAM +or +.Dv SOCK_RAW +socket. +For compatibility with Linux, however, if you attempt to set the +.Dv IP_PKTINFO +option, using an integer parameter as a boolean value, this will +transparently manipulate the +.Dv IP_RECVPKTINFO +option instead. +Source code compatbility with both environments is thus maintained. .Sh SEE ALSO .Xr getsockopt 2 , .Xr recv 2 , Index: src/share/man/man9/sockopt.9 diff -u src/share/man/man9/sockopt.9:1.10 src/share/man/man9/sockopt.9:1.10.4.1 --- src/share/man/man9/sockopt.9:1.10 Mon Jan 16 12:54:25 2017 +++ src/share/man/man9/sockopt.9 Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: sockopt.9,v 1.10 2017/01/16 12:54:25 njoly Exp $ +.\" $NetBSD: sockopt.9,v 1.10.4.1 2018/03/18 10:57:01 martin Exp $ .\" .\" Copyright (c) 2008 Iain Hibbert .\" All rights reserved. @@ -23,7 +23,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd September 4, 2009 +.Dd January 3, 2018 .Dt SOCKOPT 9 .Os .Sh NAME @@ -57,6 +57,7 @@ struct sockopt { int sopt_level; /* option level */ int sopt_name; /* option name */ size_t sopt_size; /* data length */ + size_t sopt_retsize; /* returned data length */ void * sopt_data; /* data pointer */ uint8_t sopt_buf[sizeof(int)]; /* internal storage */ }; @@ -133,7 +134,7 @@ context using which will not fail. .It Fn sockopt_setint "sopt" "value" Common case of set sockopt integer value. -The sockpt structure must contain an int sized data field or be previously +The sockopt structure must contain an int sized data field or be previously unset, in which case the data pointer will be set to the internal storage. .El .Sh CODE REFERENCES Index: src/sys/kern/uipc_socket.c diff -u src/sys/kern/uipc_socket.c:1.255 src/sys/kern/uipc_socket.c:1.255.2.1 --- src/sys/kern/uipc_socket.c:1.255 Sat May 27 21:02:56 2017 +++ src/sys/kern/uipc_socket.c Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket.c,v 1.255 2017/05/27 21:02:56 bouyer Exp $ */ +/* $NetBSD: uipc_socket.c,v 1.255.2.1 2018/03/18 10:57:01 martin Exp $ */ /*- * Copyright (c) 2002, 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -71,7 +71,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.255 2017/05/27 21:02:56 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.255.2.1 2018/03/18 10:57:01 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -2109,8 +2109,12 @@ sockopt_set(struct sockopt *sopt, const return error; } - KASSERT(sopt->sopt_size == len); + if (sopt->sopt_size < len) + return EINVAL; + memcpy(sopt->sopt_data, buf, len); + sopt->sopt_retsize = len; + return 0; } @@ -2169,9 +2173,12 @@ sockopt_setmbuf(struct sockopt *sopt, st return error; } - KASSERT(sopt->sopt_size == len); + if (sopt->sopt_size < len) + return EINVAL; + m_copydata(m, 0, len, sopt->sopt_data); m_freem(m); + sopt->sopt_retsize = len; return 0; } Index: src/sys/kern/uipc_syscalls.c diff -u src/sys/kern/uipc_syscalls.c:1.186 src/sys/kern/uipc_syscalls.c:1.186.6.1 --- src/sys/kern/uipc_syscalls.c:1.186 Fri Feb 3 16:06:45 2017 +++ src/sys/kern/uipc_syscalls.c Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_syscalls.c,v 1.186 2017/02/03 16:06:45 christos Exp $ */ +/* $NetBSD: uipc_syscalls.c,v 1.186.6.1 2018/03/18 10:57:01 martin Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls.c,v 1.186 2017/02/03 16:06:45 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls.c,v 1.186.6.1 2018/03/18 10:57:01 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_pipe.h" @@ -1235,7 +1235,10 @@ sys_getsockopt(struct lwp *l, const stru if ((error = fd_getsock1(SCARG(uap, s), &so, &fp)) != 0) return (error); - sockopt_init(&sopt, SCARG(uap, level), SCARG(uap, name), 0); + if (valsize > MCLBYTES) + return EINVAL; + + sockopt_init(&sopt, SCARG(uap, level), SCARG(uap, name), valsize); if (fp->f_flag & FNOSIGPIPE) so->so_options |= SO_NOSIGPIPE; @@ -1246,7 +1249,7 @@ sys_getsockopt(struct lwp *l, const stru goto out; if (valsize > 0) { - len = min(valsize, sopt.sopt_size); + len = min(valsize, sopt.sopt_retsize); error = copyout(sopt.sopt_data, SCARG(uap, val), len); if (error) goto out; Index: src/sys/netinet/in.h diff -u src/sys/netinet/in.h:1.100.6.2 src/sys/netinet/in.h:1.100.6.3 --- src/sys/netinet/in.h:1.100.6.2 Sun Feb 11 21:17:34 2018 +++ src/sys/netinet/in.h Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.100.6.2 2018/02/11 21:17:34 snj Exp $ */ +/* $NetBSD: in.h,v 1.100.6.3 2018/03/18 10:57:01 martin Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -289,8 +289,10 @@ struct ip_opts { #define IP_IPSEC_POLICY 22 /* struct; get/set security policy */ #define IP_RECVTTL 23 /* bool; receive IP TTL w/dgram */ #define IP_MINTTL 24 /* minimum TTL for packet or drop */ -#define IP_PKTINFO 25 /* int; send interface and src addr */ -#define IP_RECVPKTINFO 26 /* int; send interface and dst addr */ +#define IP_PKTINFO 25 /* struct; set default src if/addr */ +#define IP_RECVPKTINFO 26 /* int; receive dst if/addr w/dgram */ + +#define IP_SENDSRCADDR IP_RECVDSTADDR /* FreeBSD compatibility */ /* * Information sent in the control message of a datagram socket for @@ -301,6 +303,8 @@ struct in_pktinfo { unsigned int ipi_ifindex; /* interface index */ }; +#define ipi_spec_dst ipi_addr /* Solaris/Linux compatibility */ + /* * Defaults and limits for options */ Index: src/sys/netinet/in_pcb.c diff -u src/sys/netinet/in_pcb.c:1.178.4.2 src/sys/netinet/in_pcb.c:1.178.4.3 --- src/sys/netinet/in_pcb.c:1.178.4.2 Tue Jan 2 10:20:34 2018 +++ src/sys/netinet/in_pcb.c Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.c,v 1.178.4.2 2018/01/02 10:20:34 snj Exp $ */ +/* $NetBSD: in_pcb.c,v 1.178.4.3 2018/03/18 10:57:01 martin Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -93,7 +93,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.178.4.2 2018/01/02 10:20:34 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.178.4.3 2018/03/18 10:57:01 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -204,6 +204,7 @@ in_pcballoc(struct socket *so, void *v) inp->inp_errormtu = -1; inp->inp_portalgo = PORTALGO_DEFAULT; inp->inp_bindportonsend = false; + inp->inp_prefsrcip.s_addr = INADDR_ANY; #if defined(IPSEC) if (ipsec_enabled) { int error = ipsec_init_pcbpolicy(so, &inp->inp_sp); Index: src/sys/netinet/in_pcb.h diff -u src/sys/netinet/in_pcb.h:1.63.6.1 src/sys/netinet/in_pcb.h:1.63.6.2 --- src/sys/netinet/in_pcb.h:1.63.6.1 Thu Dec 21 21:08:13 2017 +++ src/sys/netinet/in_pcb.h Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.h,v 1.63.6.1 2017/12/21 21:08:13 snj Exp $ */ +/* $NetBSD: in_pcb.h,v 1.63.6.2 2018/03/18 10:57:01 martin Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -95,6 +95,7 @@ struct inpcb { int inp_errormtu; /* MTU of last xmit status = EMSGSIZE */ uint8_t inp_ip_minttl; bool inp_bindportonsend; + struct in_addr inp_prefsrcip; /* preferred src IP when wild */ }; #define inp_faddr inp_ip.ip_dst @@ -121,11 +122,9 @@ struct inpcb { * Cancels INP_HDRINCL. */ #define INP_RECVTTL 0x0800 /* receive incoming IP TTL */ -#define INP_PKTINFO 0x1000 /* receive dst packet info */ -#define INP_RECVPKTINFO 0x2000 /* receive dst packet info */ +#define INP_RECVPKTINFO 0x1000 /* receive IP dst if/addr */ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ - INP_RECVIF|INP_RECVTTL|INP_RECVPKTINFO|\ - INP_PKTINFO) + INP_RECVIF|INP_RECVTTL|INP_RECVPKTINFO) #define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) #define inp_lock(inp) solock((inp)->inp_socket) Index: src/sys/netinet/ip_input.c diff -u src/sys/netinet/ip_input.c:1.355.2.5 src/sys/netinet/ip_input.c:1.355.2.6 --- src/sys/netinet/ip_input.c:1.355.2.5 Mon Feb 26 13:32:01 2018 +++ src/sys/netinet/ip_input.c Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.355.2.5 2018/02/26 13:32:01 martin Exp $ */ +/* $NetBSD: ip_input.c,v 1.355.2.6 2018/03/18 10:57:01 martin Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.355.2.5 2018/02/26 13:32:01 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.355.2.6 2018/03/18 10:57:01 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -1546,15 +1546,6 @@ ip_savecontrol(struct inpcb *inp, struct } if (inpflags & INP_RECVPKTINFO) { struct in_pktinfo ipi; - ipi.ipi_addr = ip->ip_src; - ipi.ipi_ifindex = ifp->if_index; - *mp = sbcreatecontrol((void *) &ipi, - sizeof(ipi), IP_RECVPKTINFO, IPPROTO_IP); - if (*mp) - mp = &(*mp)->m_next; - } - if (inpflags & INP_PKTINFO) { - struct in_pktinfo ipi; ipi.ipi_addr = ip->ip_dst; ipi.ipi_ifindex = ifp->if_index; *mp = sbcreatecontrol((void *) &ipi, Index: src/sys/netinet/ip_output.c diff -u src/sys/netinet/ip_output.c:1.279.2.6 src/sys/netinet/ip_output.c:1.279.2.7 --- src/sys/netinet/ip_output.c:1.279.2.6 Mon Feb 19 18:39:43 2018 +++ src/sys/netinet/ip_output.c Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.279.2.6 2018/02/19 18:39:43 snj Exp $ */ +/* $NetBSD: ip_output.c,v 1.279.2.7 2018/03/18 10:57:01 martin Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.279.2.6 2018/02/19 18:39:43 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.279.2.7 2018/03/18 10:57:01 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -1081,6 +1081,7 @@ ip_ctloutput(int op, struct socket *so, struct ip *ip = &inp->inp_ip; int inpflags = inp->inp_flags; int optval = 0, error = 0; + struct in_pktinfo pktinfo; KASSERT(solocked(so)); @@ -1103,7 +1104,6 @@ ip_ctloutput(int op, struct socket *so, case IP_TOS: case IP_TTL: case IP_MINTTL: - case IP_PKTINFO: case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: @@ -1135,10 +1135,6 @@ ip_ctloutput(int op, struct socket *so, else \ inpflags &= ~bit; - case IP_PKTINFO: - OPTSET(INP_PKTINFO); - break; - case IP_RECVOPTS: OPTSET(INP_RECVOPTS); break; @@ -1163,6 +1159,45 @@ ip_ctloutput(int op, struct socket *so, OPTSET(INP_RECVTTL); break; } + break; + case IP_PKTINFO: + error = sockopt_getint(sopt, &optval); + if (!error) { + /* Linux compatibility */ + OPTSET(INP_RECVPKTINFO); + break; + } + error = sockopt_get(sopt, &pktinfo, sizeof(pktinfo)); + if (error) + break; + + if (pktinfo.ipi_ifindex == 0) { + inp->inp_prefsrcip = pktinfo.ipi_addr; + break; + } + + /* Solaris compatibility */ + struct ifnet *ifp; + struct in_ifaddr *ia; + int s; + + /* pick up primary address */ + s = pserialize_read_enter(); + ifp = if_byindex(pktinfo.ipi_ifindex); + if (ifp == NULL) { + pserialize_read_exit(s); + error = EADDRNOTAVAIL; + break; + } + ia = in_get_ia_from_ifp(ifp); + if (ia == NULL) { + pserialize_read_exit(s); + error = EADDRNOTAVAIL; + break; + } + inp->inp_prefsrcip = IA_SIN(ia)->sin_addr; + pserialize_read_exit(s); + break; break; #undef OPTSET @@ -1239,7 +1274,6 @@ ip_ctloutput(int op, struct socket *so, } break; } - case IP_PKTINFO: case IP_TOS: case IP_TTL: case IP_MINTTL: @@ -1269,10 +1303,6 @@ ip_ctloutput(int op, struct socket *so, #define OPTBIT(bit) (inpflags & bit ? 1 : 0) - case IP_PKTINFO: - optval = OPTBIT(INP_PKTINFO); - break; - case IP_RECVOPTS: optval = OPTBIT(INP_RECVOPTS); break; @@ -1300,6 +1330,33 @@ ip_ctloutput(int op, struct socket *so, error = sockopt_setint(sopt, optval); break; + case IP_PKTINFO: + switch (sopt->sopt_size) { + case sizeof(int): + /* Linux compatibility */ + optval = OPTBIT(INP_RECVPKTINFO); + error = sockopt_setint(sopt, optval); + break; + case sizeof(struct in_pktinfo): + /* Solaris compatibility */ + pktinfo.ipi_ifindex = 0; + pktinfo.ipi_addr = inp->inp_prefsrcip; + error = sockopt_set(sopt, &pktinfo, + sizeof(pktinfo)); + break; + default: + /* + * While size is stuck at 0, and, later, if + * the caller doesn't use an exactly sized + * recipient for the data, default to Linux + * compatibility + */ + optval = OPTBIT(INP_RECVPKTINFO); + error = sockopt_setint(sopt, optval); + break; + } + break; + #if 0 /* defined(IPSEC) */ case IP_IPSEC_POLICY: { @@ -1416,11 +1473,14 @@ ip_setpktopts(struct mbuf *control, stru struct inpcb *inp, kauth_cred_t cred) { struct cmsghdr *cm; - struct in_pktinfo *pktinfo; + struct in_pktinfo pktinfo; int error; pktopts->ippo_imo = inp->inp_moptions; - sockaddr_in_init(&pktopts->ippo_laddr, &inp->inp_laddr, 0); + + struct in_addr *ia = in_nullhost(inp->inp_prefsrcip) ? &inp->inp_laddr : + &inp->inp_prefsrcip; + sockaddr_in_init(&pktopts->ippo_laddr, ia, 0); if (control == NULL) return 0; @@ -1446,13 +1506,23 @@ ip_setpktopts(struct mbuf *control, stru switch (cm->cmsg_type) { case IP_PKTINFO: - if (cm->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo))) + if (cm->cmsg_len != CMSG_LEN(sizeof(pktinfo))) return EINVAL; - - pktinfo = (struct in_pktinfo *)CMSG_DATA(cm); - error = ip_pktinfo_prepare(pktinfo, pktopts, flags, + memcpy(&pktinfo, CMSG_DATA(cm), sizeof(pktinfo)); + error = ip_pktinfo_prepare(&pktinfo, pktopts, flags, cred); - if (error != 0) + if (error) + return error; + break; + case IP_SENDSRCADDR: /* FreeBSD compatibility */ + if (cm->cmsg_len != CMSG_LEN(sizeof(struct in_addr))) + return EINVAL; + pktinfo.ipi_ifindex = 0; + pktinfo.ipi_addr = + ((struct in_pktinfo *)CMSG_DATA(cm))->ipi_addr; + error = ip_pktinfo_prepare(&pktinfo, pktopts, flags, + cred); + if (error) return error; break; default: Index: src/sys/sys/socketvar.h diff -u src/sys/sys/socketvar.h:1.144 src/sys/sys/socketvar.h:1.144.6.1 --- src/sys/sys/socketvar.h:1.144 Fri Feb 3 16:06:45 2017 +++ src/sys/sys/socketvar.h Sun Mar 18 10:57:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: socketvar.h,v 1.144 2017/02/03 16:06:45 christos Exp $ */ +/* $NetBSD: socketvar.h,v 1.144.6.1 2018/03/18 10:57:01 martin Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -224,6 +224,7 @@ struct sockopt { int sopt_level; /* option level */ int sopt_name; /* option name */ size_t sopt_size; /* data length */ + size_t sopt_retsize; /* returned data length */ void * sopt_data; /* data pointer */ uint8_t sopt_buf[sizeof(int)]; /* internal storage */ };