Module Name: src Committed By: christos Date: Mon Jan 1 00:51:36 UTC 2018
Modified Files: src/share/man/man4: ip.4 src/sys/netinet: in.h in_pcb.c in_pcb.h ip_input.c ip_output.c src/sys/sys: param.h Log Message: 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 To generate a diff of this commit: cvs rdiff -u -r1.40 -r1.41 src/share/man/man4/ip.4 cvs rdiff -u -r1.101 -r1.102 src/sys/netinet/in.h cvs rdiff -u -r1.180 -r1.181 src/sys/netinet/in_pcb.c cvs rdiff -u -r1.64 -r1.65 src/sys/netinet/in_pcb.h cvs rdiff -u -r1.363 -r1.364 src/sys/netinet/ip_input.c cvs rdiff -u -r1.288 -r1.289 src/sys/netinet/ip_output.c cvs rdiff -u -r1.554 -r1.555 src/sys/sys/param.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.40 src/share/man/man4/ip.4:1.41 --- src/share/man/man4/ip.4:1.40 Sun Aug 13 14:19:44 2017 +++ src/share/man/man4/ip.4 Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -.\" $NetBSD: ip.4,v 1.40 2017/08/13 18:19:44 wiz Exp $ +.\" $NetBSD: ip.4,v 1.41 2018/01/01 00:51:36 christos 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 @@ -96,8 +96,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 @@ -117,13 +117,24 @@ 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. +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 @@ -177,6 +188,18 @@ 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 @@ -197,12 +220,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 @@ -452,6 +469,24 @@ 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/sys/netinet/in.h diff -u src/sys/netinet/in.h:1.101 src/sys/netinet/in.h:1.102 --- src/sys/netinet/in.h:1.101 Thu Aug 10 00:31:58 2017 +++ src/sys/netinet/in.h Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.101 2017/08/10 04:31:58 ryo Exp $ */ +/* $NetBSD: in.h,v 1.102 2018/01/01 00:51:36 christos 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.180 src/sys/netinet/in_pcb.c:1.181 --- src/sys/netinet/in_pcb.c:1.180 Thu Dec 14 23:03:46 2017 +++ src/sys/netinet/in_pcb.c Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.c,v 1.180 2017/12/15 04:03:46 ozaki-r Exp $ */ +/* $NetBSD: in_pcb.c,v 1.181 2018/01/01 00:51:36 christos 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.180 2017/12/15 04:03:46 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.181 2018/01/01 00:51:36 christos 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.64 src/sys/netinet/in_pcb.h:1.65 --- src/sys/netinet/in_pcb.h:1.64 Thu Aug 10 00:31:58 2017 +++ src/sys/netinet/in_pcb.h Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.h,v 1.64 2017/08/10 04:31:58 ryo Exp $ */ +/* $NetBSD: in_pcb.h,v 1.65 2018/01/01 00:51:36 christos 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.363 src/sys/netinet/ip_input.c:1.364 --- src/sys/netinet/ip_input.c:1.363 Fri Nov 24 09:03:25 2017 +++ src/sys/netinet/ip_input.c Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.363 2017/11/24 14:03:25 roy Exp $ */ +/* $NetBSD: ip_input.c,v 1.364 2018/01/01 00:51:36 christos 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.363 2017/11/24 14:03:25 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.364 2018/01/01 00:51:36 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -1533,15 +1533,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(&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(&ipi, Index: src/sys/netinet/ip_output.c diff -u src/sys/netinet/ip_output.c:1.288 src/sys/netinet/ip_output.c:1.289 --- src/sys/netinet/ip_output.c:1.288 Fri Dec 22 06:22:37 2017 +++ src/sys/netinet/ip_output.c Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.288 2017/12/22 11:22:37 ozaki-r Exp $ */ +/* $NetBSD: ip_output.c,v 1.289 2018/01/01 00:51:36 christos 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.288 2017/12/22 11:22:37 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.289 2018/01/01 00:51:36 christos 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,35 @@ ip_ctloutput(int op, struct socket *so, error = sockopt_setint(sopt, optval); break; + case IP_PKTINFO: + /* XXX these tests fail until size gets propagated */ + /* It needs to be passed through from the caller */ + 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 +1475,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 +1508,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/param.h diff -u src/sys/sys/param.h:1.554 src/sys/sys/param.h:1.555 --- src/sys/sys/param.h:1.554 Wed Dec 6 03:25:47 2017 +++ src/sys/sys/param.h Sun Dec 31 19:51:36 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: param.h,v 1.554 2017/12/06 08:25:47 knakahara Exp $ */ +/* $NetBSD: param.h,v 1.555 2018/01/01 00:51:36 christos Exp $ */ /*- * Copyright (c) 1982, 1986, 1989, 1993 @@ -67,7 +67,7 @@ * 2.99.9 (299000900) */ -#define __NetBSD_Version__ 899000900 /* NetBSD 8.99.9 */ +#define __NetBSD_Version__ 899001000 /* NetBSD 8.99.10 */ #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \ (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)