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
This commit is contained in:
christos 2018-01-01 00:51:36 +00:00
parent fe1f2b747b
commit 645664bc7b
7 changed files with 157 additions and 55 deletions

View File

@ -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_POLICY, buf, ipsec_get_policylen(buf));
.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; or
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 ,

View File

@ -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
*/

View File

@ -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);

View File

@ -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)

View File

@ -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"
@ -1532,15 +1532,6 @@ ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip,
}
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;

View File

@ -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 sockopt *sopt)
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, struct sockopt *sopt)
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, struct sockopt *sopt)
else \
inpflags &= ~bit;
case IP_PKTINFO:
OPTSET(INP_PKTINFO);
break;
case IP_RECVOPTS:
OPTSET(INP_RECVOPTS);
break;
@ -1164,6 +1160,45 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
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
case IP_MULTICAST_IF:
@ -1239,7 +1274,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
}
break;
}
case IP_PKTINFO:
case IP_TOS:
case IP_TTL:
case IP_MINTTL:
@ -1269,10 +1303,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
#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, struct sockopt *sopt)
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, struct ip_pktopts *pktopts, int *flags,
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, struct ip_pktopts *pktopts, int *flags,
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:

View File

@ -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__)