? netbsd.netinet.ip_pktinfo.patch Index: in.h =================================================================== RCS file: /src/cvs/cvsroot/netbsd/src/sys/netinet/in.h,v retrieving revision 1.83 diff -a -u -r1.83 in.h --- in.h 25 Jan 2008 21:12:14 -0000 1.83 +++ in.h 24 Jul 2008 17:08:57 -0000 @@ -282,6 +282,8 @@ #if 1 /*IPSEC*/ #define IP_IPSEC_POLICY 22 /* struct; get/set security policy */ #endif +#define IP_RECVPKTINFO 23 /* bool; recv if, dst addr */ +#define IP_PKTINFO 24 /* in_pktinfo; send if, src addr */ /* * Defaults and limits for options @@ -306,6 +308,15 @@ #define IP_PORTRANGE_HIGH 1 /* same as DEFAULT (FreeBSD compat) */ #define IP_PORTRANGE_LOW 2 /* use privileged range */ +/* + * Argument structure for IP_PKTINFO + */ +struct in_pktinfo { + int ipi_ifindex; /* send interface index (XXX: doesn't work) */ + struct in_addr ipi_spec_dst; /* local address for lookup rtentry (XXX: doesn't work) */ + struct in_addr ipi_addr; /* src IP address */ +}; + #if defined(_NETBSD_SOURCE) /* * Definitions for inet sysctl operations. Index: in_pcb.h =================================================================== RCS file: /src/cvs/cvsroot/netbsd/src/sys/netinet/in_pcb.h,v retrieving revision 1.45 diff -a -u -r1.45 in_pcb.h --- in_pcb.h 16 Dec 2007 18:39:57 -0000 1.45 +++ in_pcb.h 24 Jul 2008 17:08:57 -0000 @@ -108,8 +108,9 @@ /* XXX should move to an UDP control block */ #define INP_ESPINUDP 0x100 /* ESP over UDP for NAT-T */ #define INP_ESPINUDP_NON_IKE 0x200 /* ESP over UDP for NAT-T */ +#define INP_PKTINFO 0x800 /* receive with ip_pktinfo */ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ - INP_RECVIF) + INP_RECVIF|INP_PKTINFO) #define INP_ESPINUDP_ALL (INP_ESPINUDP|INP_ESPINUDP_NON_IKE) #define INP_NOHEADER 0x400 /* Kernel removes IP header * before feeding a packet Index: ip_input.c =================================================================== RCS file: /src/cvs/cvsroot/netbsd/src/sys/netinet/ip_input.c,v retrieving revision 1.272 diff -a -u -r1.272 ip_input.c --- ip_input.c 5 May 2008 17:11:17 -0000 1.272 +++ ip_input.c 24 Jul 2008 17:08:57 -0000 @@ -2097,6 +2097,18 @@ if (*mp) mp = &(*mp)->m_next; } + if (inp->inp_flags & INP_PKTINFO) { + struct in_pktinfo pinfo; + + pinfo.ipi_ifindex = (m->m_pkthdr.rcvif != NULL) ? + m->m_pkthdr.rcvif->if_index : 0; + pinfo.ipi_spec_dst = pinfo.ipi_addr = ip->ip_dst; + + *mp = sbcreatecontrol((void *) &pinfo, + sizeof(pinfo), IP_PKTINFO, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } } /* Index: ip_output.c =================================================================== RCS file: /src/cvs/cvsroot/netbsd/src/sys/netinet/ip_output.c,v retrieving revision 1.196 diff -a -u -r1.196 ip_output.c --- ip_output.c 28 Apr 2008 20:24:09 -0000 1.196 +++ ip_output.c 24 Jul 2008 17:08:57 -0000 @@ -1232,6 +1232,8 @@ case IP_RECVRETOPTS: case IP_RECVDSTADDR: case IP_RECVIF: + case IP_RECVPKTINFO: + case IP_PKTINFO: /* for compatibile linux */ if (m == NULL || m->m_len != sizeof(int)) error = EINVAL; else { @@ -1266,6 +1268,11 @@ case IP_RECVIF: OPTSET(INP_RECVIF); break; + + case IP_RECVPKTINFO: + case IP_PKTINFO: /* for compatibile linux */ + OPTSET(INP_PKTINFO); + break; } } break; @@ -1356,6 +1363,8 @@ case IP_RECVRETOPTS: case IP_RECVDSTADDR: case IP_RECVIF: + case IP_RECVPKTINFO: + case IP_PKTINFO: /* for compatible linux */ case IP_ERRORMTU: *mp = m = m_get(M_WAIT, MT_SOOPTS); MCLAIM(m, so->so_mowner); @@ -1391,6 +1400,11 @@ case IP_RECVIF: optval = OPTBIT(INP_RECVIF); break; + + case IP_RECVPKTINFO: + case IP_PKTINFO: /* for compatible linux */ + optval = OPTBIT(INP_PKTINFO); + break; } *mtod(m, int *) = optval; break; @@ -1548,6 +1562,106 @@ return (EINVAL); } +void +ip_initpktopts(struct ip_pktopts *pktopt) +{ + memset(pktopt, 0, sizeof(*pktopt)); +} + +int +ip_copypktopts(struct ip_pktopts *dst, struct ip_pktopts *src, int canwait) +{ + memcpy(dst, src, sizeof(*dst)); + return 0; +} + +void +ip_clearpktopts(struct ip_pktopts *pktopt, int optname) +{ + if (optname == -1 || optname == IP_PKTINFO) { + memset(&pktopt->ipo_pktinfo, 0, sizeof(pktopt->ipo_pktinfo)); + } +} + +int +ip_setpktopts(struct mbuf *control, struct ip_pktopts *opt, + struct ip_pktopts *stickyopt, int priv, int uproto) +{ + struct cmsghdr *cm = 0; + + if (control == NULL || opt == NULL) + return EINVAL; + + ip_initpktopts(opt); + if (stickyopt) { + int error; + if ((error = ip_copypktopts(opt, stickyopt, M_NOWAIT)) != 0) + return error; + } + + /* + * XXX: Currently, we assume all the optional information is stored + * in a single mbuf. + */ + if (control->m_next) + return (EINVAL); + + for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len), + control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { + int error; + + if (control->m_len < CMSG_LEN(0)) + return (EINVAL); + + cm = mtod(control, struct cmsghdr *); + if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len) + return (EINVAL); + if (cm->cmsg_level != IPPROTO_IP) + continue; + + error = ip_setpktopt(cm->cmsg_type, CMSG_DATA(cm), + cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto); + if (error) + return (error); + } + + return (0); + +} + +int +ip_setpktopt(int optname, u_char *buf, int len, struct ip_pktopts *pktopt, + int priv, int sticky, int cmsg, int uproto) +{ + if (!sticky && !cmsg) { +#ifdef DIAGNOSTIC + printf("ip_setpktopt: impossible case\n"); +#endif + return EINVAL; + } + + if (sticky && cmsg) { + switch (optname) { + case IP_PKTINFO: + return ENOPROTOOPT; + } + } + + switch (optname) { + case IP_PKTINFO: + { + struct in_pktinfo *p; + p = (struct in_pktinfo *)buf; + pktopt->ipo_pktinfo = *p; + } + break; + default: + return ENOPROTOOPT; + } + + return 0; +} + /* * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. */ Index: ip_var.h =================================================================== RCS file: /src/cvs/cvsroot/netbsd/src/sys/netinet/ip_var.h,v retrieving revision 1.87 diff -a -u -r1.87 ip_var.h --- ip_var.h 12 Apr 2008 05:58:22 -0000 1.87 +++ ip_var.h 24 Jul 2008 17:08:57 -0000 @@ -110,6 +110,14 @@ int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; +struct ip_pktopts { + /* + * XXX: each member should be a pointer. + * and NULL means not defined + */ + struct in_pktinfo ipo_pktinfo; /* Outgoing IF/address information */ +}; + /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. @@ -214,6 +222,15 @@ int ip_output(struct mbuf *, ...); int ip_fragment(struct mbuf *, struct ifnet *, u_long); int ip_pcbopts(struct mbuf **, struct mbuf *); + +int ip_pktopt(struct ip_pktopts **, struct mbuf *, struct socket *); +void ip_initpktopts(struct ip_pktopts *); +int ip_copypktopts(struct ip_pktopts *, struct ip_pktopts *, int); +void ip_clearpktopts(struct ip_pktopts *, int); +int ip_setpktopts(struct mbuf *, struct ip_pktopts *, + struct ip_pktopts *, int, int ); +int ip_setpktopt(int, u_char *, int, struct ip_pktopts *, int, int, int, int); + struct mbuf * ip_reass(struct ipqent *, struct ipq *, struct ipqhead *); struct in_ifaddr * Index: udp_usrreq.c =================================================================== RCS file: /src/cvs/cvsroot/netbsd/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.172 diff -a -u -r1.172 udp_usrreq.c --- udp_usrreq.c 4 May 2008 07:22:14 -0000 1.172 +++ udp_usrreq.c 24 Jul 2008 17:08:57 -0000 @@ -1275,41 +1275,57 @@ break; case PRU_SEND: - if (control && control->m_len) { - m_freem(control); - m_freem(m); - error = EINVAL; - break; - } - { - struct in_addr laddr; /* XXX */ + { + struct in_addr laddr; /* XXX */ + struct ip_pktopts opt; + + laddr.s_addr = 0; + if (nam || control) + laddr = inp->inp_laddr; /* XXX: save */ + + if (control) { + if ((error = ip_setpktopts(control, &opt, + NULL, 0, IPPROTO_UDP)) != 0) + goto die; + + if (opt.ipo_pktinfo.ipi_addr.s_addr) { /* XXX */ + struct in_ifaddr *ia; + LIST_FOREACH(ia, &IN_IFADDR_HASH(opt.ipo_pktinfo.ipi_addr.s_addr), ia_hash) { + if (in_hosteq(ia->ia_addr.sin_addr, opt.ipo_pktinfo.ipi_addr)) { + inp->inp_laddr = opt.ipo_pktinfo.ipi_addr; /* XXX */ + } + } + } + } - if (nam) { - laddr = inp->inp_laddr; /* XXX */ - if ((so->so_state & SS_ISCONNECTED) != 0) { - error = EISCONN; - goto die; + if (nam) { + if ((so->so_state & SS_ISCONNECTED) != 0) { + error = EISCONN; + goto die; + } + error = in_pcbconnect(inp, nam, l); /* would break inp->inp_laddr */ + if (error) + goto die; + } else { + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + goto die; + } } - error = in_pcbconnect(inp, nam, l); - if (error) - goto die; - } else { - if ((so->so_state & SS_ISCONNECTED) == 0) { - error = ENOTCONN; - goto die; + error = udp_output(m, inp); + m = NULL; + if (nam || control) + inp->inp_laddr = laddr; /* XXX: restore */ + if (nam) { + in_pcbdisconnect(inp); + in_pcbstate(inp, INP_BOUND); /* XXX */ } + die: + if (control) + m_freem(control); + if (m) + m_freem(m); } - error = udp_output(m, inp); - m = NULL; - if (nam) { - in_pcbdisconnect(inp); - inp->inp_laddr = laddr; /* XXX */ - in_pcbstate(inp, INP_BOUND); /* XXX */ - } - die: - if (m) - m_freem(m); - } break; case PRU_SENSE: