version 1.27, 1996/05/23 16:12:15 |
version 1.46, 1999/09/13 12:15:55 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/* |
/* |
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. Neither the name of the project nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
|
* without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
*/ |
|
|
|
/* |
* Copyright (c) 1982, 1986, 1988, 1993 |
* Copyright (c) 1982, 1986, 1988, 1993 |
* The Regents of the University of California. All rights reserved. |
* The Regents of the University of California. All rights reserved. |
* |
* |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
* |
* |
* @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 |
* @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 |
*/ |
*/ |
|
|
|
#include "opt_ipsec.h" |
|
#include "opt_mrouting.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#include <sys/mbuf.h> |
#include <sys/mbuf.h> |
|
|
#include <netinet/ip.h> |
#include <netinet/ip.h> |
#include <netinet/ip_var.h> |
#include <netinet/ip_var.h> |
#include <netinet/ip_mroute.h> |
#include <netinet/ip_mroute.h> |
|
#include <netinet/ip_icmp.h> |
#include <netinet/in_pcb.h> |
#include <netinet/in_pcb.h> |
#include <netinet/in_var.h> |
#include <netinet/in_var.h> |
|
|
#include <machine/stdarg.h> |
#include <machine/stdarg.h> |
|
|
|
#ifdef IPSEC |
|
#include <netinet6/ipsec.h> |
|
#endif /*IPSEC*/ |
|
|
|
extern u_char ip_protox[]; |
|
extern struct protosw inetsw[]; |
struct inpcbtable rawcbtable; |
struct inpcbtable rawcbtable; |
|
|
|
int rip_bind __P((struct inpcb *, struct mbuf *)); |
|
int rip_connect __P((struct inpcb *, struct mbuf *)); |
|
void rip_disconnect __P((struct inpcb *)); |
|
|
/* |
/* |
* Nominal space allocated to a raw ip socket. |
* Nominal space allocated to a raw ip socket. |
*/ |
*/ |
|
|
rip_init() |
rip_init() |
{ |
{ |
|
|
in_pcbinit(&rawcbtable, 1); |
in_pcbinit(&rawcbtable, 1, 1); |
} |
} |
|
|
struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; |
static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; |
|
|
/* |
/* |
* Setup generic address and protocol structures |
* Setup generic address and protocol structures |
* for raw_input routine, then pass them along with |
* for raw_input routine, then pass them along with |
Line 95 rip_input(m, va_alist) |
|
Line 139 rip_input(m, va_alist) |
|
va_dcl |
va_dcl |
#endif |
#endif |
{ |
{ |
|
int off, proto; |
register struct ip *ip = mtod(m, struct ip *); |
register struct ip *ip = mtod(m, struct ip *); |
register struct inpcb *inp; |
register struct inpcb *inp; |
struct socket *last = 0; |
struct inpcb *last = 0; |
|
struct mbuf *opts = 0; |
|
struct sockaddr_in ripsrc; |
|
va_list ap; |
|
|
|
va_start(ap, m); |
|
off = va_arg(ap, int); |
|
proto = va_arg(ap, int); |
|
va_end(ap); |
|
|
|
ripsrc.sin_family = AF_INET; |
|
ripsrc.sin_len = sizeof(struct sockaddr_in); |
ripsrc.sin_addr = ip->ip_src; |
ripsrc.sin_addr = ip->ip_src; |
|
ripsrc.sin_port = 0; |
|
bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); |
|
|
|
/* |
|
* XXX Compatibility: programs using raw IP expect ip_len |
|
* XXX to have the header length subtracted. |
|
*/ |
|
ip->ip_len -= ip->ip_hl << 2; |
|
|
for (inp = rawcbtable.inpt_queue.cqh_first; |
for (inp = rawcbtable.inpt_queue.cqh_first; |
inp != (struct inpcb *)&rawcbtable.inpt_queue; |
inp != (struct inpcb *)&rawcbtable.inpt_queue; |
inp = inp->inp_queue.cqe_next) { |
inp = inp->inp_queue.cqe_next) { |
if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) |
if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) |
continue; |
continue; |
if (inp->inp_laddr.s_addr != INADDR_ANY && |
if (!in_nullhost(inp->inp_laddr) && |
inp->inp_laddr.s_addr != ip->ip_dst.s_addr) |
!in_hosteq(inp->inp_laddr, ip->ip_dst)) |
continue; |
continue; |
if (inp->inp_faddr.s_addr != INADDR_ANY && |
if (!in_nullhost(inp->inp_faddr) && |
inp->inp_faddr.s_addr != ip->ip_src.s_addr) |
!in_hosteq(inp->inp_faddr, ip->ip_src)) |
continue; |
continue; |
if (last) { |
if (last) { |
struct mbuf *n; |
struct mbuf *n; |
if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { |
if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { |
if (sbappendaddr(&last->so_rcv, |
if (last->inp_flags & INP_CONTROLOPTS || |
sintosa(&ripsrc), n, |
last->inp_socket->so_options & SO_TIMESTAMP) |
(struct mbuf *)0) == 0) |
ip_savecontrol(last, &opts, ip, n); |
|
if (sbappendaddr(&last->inp_socket->so_rcv, |
|
sintosa(&ripsrc), n, opts) == 0) { |
/* should notify about lost packet */ |
/* should notify about lost packet */ |
m_freem(n); |
m_freem(n); |
else |
if (opts) |
sorwakeup(last); |
m_freem(opts); |
|
} else |
|
sorwakeup(last->inp_socket); |
|
opts = NULL; |
} |
} |
} |
} |
last = inp->inp_socket; |
last = inp; |
} |
} |
if (last) { |
if (last) { |
if (sbappendaddr(&last->so_rcv, sintosa(&ripsrc), m, |
if (last->inp_flags & INP_CONTROLOPTS || |
(struct mbuf *)0) == 0) |
last->inp_socket->so_options & SO_TIMESTAMP) |
|
ip_savecontrol(last, &opts, ip, m); |
|
if (sbappendaddr(&last->inp_socket->so_rcv, |
|
sintosa(&ripsrc), m, opts) == 0) { |
m_freem(m); |
m_freem(m); |
else |
if (opts) |
sorwakeup(last); |
m_freem(opts); |
|
} else |
|
sorwakeup(last->inp_socket); |
} else { |
} else { |
m_freem(m); |
if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { |
ipstat.ips_noproto++; |
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL,0,0); |
ipstat.ips_delivered--; |
ipstat.ips_noproto++; |
|
ipstat.ips_delivered--; |
|
} else |
|
m_freem(m); |
} |
} |
|
return; |
} |
} |
|
|
/* |
/* |
Line 162 rip_output(m, va_alist) |
|
Line 240 rip_output(m, va_alist) |
|
va_end(ap); |
va_end(ap); |
|
|
flags = |
flags = |
(inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; |
(inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST |
|
| IP_RETURNMTU; |
|
|
/* |
/* |
* If the user handed us a complete IP packet, use it. |
* If the user handed us a complete IP packet, use it. |
* Otherwise, allocate an mbuf for a header and fill it in. |
* Otherwise, allocate an mbuf for a header and fill it in. |
*/ |
*/ |
if ((inp->inp_flags & INP_HDRINCL) == 0) { |
if ((inp->inp_flags & INP_HDRINCL) == 0) { |
|
if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { |
|
m_freem(m); |
|
return (EMSGSIZE); |
|
} |
M_PREPEND(m, sizeof(struct ip), M_WAIT); |
M_PREPEND(m, sizeof(struct ip), M_WAIT); |
ip = mtod(m, struct ip *); |
ip = mtod(m, struct ip *); |
ip->ip_tos = 0; |
ip->ip_tos = 0; |
Line 180 rip_output(m, va_alist) |
|
Line 263 rip_output(m, va_alist) |
|
ip->ip_ttl = MAXTTL; |
ip->ip_ttl = MAXTTL; |
opts = inp->inp_options; |
opts = inp->inp_options; |
} else { |
} else { |
|
if (m->m_pkthdr.len > IP_MAXPACKET) { |
|
m_freem(m); |
|
return (EMSGSIZE); |
|
} |
ip = mtod(m, struct ip *); |
ip = mtod(m, struct ip *); |
|
if (m->m_pkthdr.len != ip->ip_len) { |
|
m_freem(m); |
|
return (EINVAL); |
|
} |
if (ip->ip_id == 0) |
if (ip->ip_id == 0) |
ip->ip_id = htons(ip_id++); |
ip->ip_id = htons(ip_id++); |
opts = NULL; |
opts = NULL; |
Line 188 rip_output(m, va_alist) |
|
Line 279 rip_output(m, va_alist) |
|
flags |= IP_RAWOUTPUT; |
flags |= IP_RAWOUTPUT; |
ipstat.ips_rawout++; |
ipstat.ips_rawout++; |
} |
} |
return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); |
#ifdef IPSEC |
|
m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; /*XXX*/ |
|
#endif /*IPSEC*/ |
|
return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu)); |
} |
} |
|
|
/* |
/* |
Line 202 rip_ctloutput(op, so, level, optname, m) |
|
Line 296 rip_ctloutput(op, so, level, optname, m) |
|
struct mbuf **m; |
struct mbuf **m; |
{ |
{ |
register struct inpcb *inp = sotoinpcb(so); |
register struct inpcb *inp = sotoinpcb(so); |
#ifdef MROUTING |
int error = 0; |
int error; |
|
#endif |
|
|
|
if (level != IPPROTO_IP) { |
if (level != IPPROTO_IP) { |
if (m != 0 && *m != 0) |
error = ENOPROTOOPT; |
(void)m_free(*m); |
if (op == PRCO_SETOPT && *m != 0) |
return (EINVAL); |
(void) m_free(*m); |
} |
} else switch (op) { |
|
|
switch (optname) { |
case PRCO_SETOPT: |
|
switch (optname) { |
case IP_HDRINCL: |
case IP_HDRINCL: |
if (op == PRCO_SETOPT || op == PRCO_GETOPT) { |
if (*m == 0 || (*m)->m_len < sizeof (int)) |
if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) |
error = EINVAL; |
return (EINVAL); |
else { |
if (op == PRCO_SETOPT) { |
|
if (*mtod(*m, int *)) |
if (*mtod(*m, int *)) |
inp->inp_flags |= INP_HDRINCL; |
inp->inp_flags |= INP_HDRINCL; |
else |
else |
inp->inp_flags &= ~INP_HDRINCL; |
inp->inp_flags &= ~INP_HDRINCL; |
(void)m_free(*m); |
|
} else { |
|
(*m)->m_len = sizeof (int); |
|
*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; |
|
} |
} |
return (0); |
if (*m != 0) |
|
(void) m_free(*m); |
|
break; |
|
|
|
#ifdef MROUTING |
|
case MRT_INIT: |
|
case MRT_DONE: |
|
case MRT_ADD_VIF: |
|
case MRT_DEL_VIF: |
|
case MRT_ADD_MFC: |
|
case MRT_DEL_MFC: |
|
case MRT_ASSERT: |
|
error = ip_mrouter_set(so, optname, m); |
|
break; |
|
#endif |
|
|
|
default: |
|
error = ip_ctloutput(op, so, level, optname, m); |
|
break; |
} |
} |
break; |
break; |
|
|
case MRT_INIT: |
case PRCO_GETOPT: |
case MRT_DONE: |
switch (optname) { |
case MRT_ADD_VIF: |
case IP_HDRINCL: |
case MRT_DEL_VIF: |
*m = m_get(M_WAIT, M_SOOPTS); |
case MRT_ADD_MFC: |
(*m)->m_len = sizeof (int); |
case MRT_DEL_MFC: |
*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; |
case MRT_VERSION: |
|
case MRT_ASSERT: |
|
#ifdef MROUTING |
|
switch (op) { |
|
case PRCO_SETOPT: |
|
error = ip_mrouter_set(optname, so, m); |
|
break; |
break; |
case PRCO_GETOPT: |
|
error = ip_mrouter_get(optname, so, m); |
#ifdef MROUTING |
|
case MRT_VERSION: |
|
case MRT_ASSERT: |
|
error = ip_mrouter_get(so, optname, m); |
break; |
break; |
|
#endif |
|
|
default: |
default: |
error = EINVAL; |
error = ip_ctloutput(op, so, level, optname, m); |
break; |
break; |
} |
} |
return (error); |
break; |
#else |
|
if (op == PRCO_SETOPT && *m) |
|
m_free(*m); |
|
return (EOPNOTSUPP); |
|
#endif |
|
} |
} |
return (ip_ctloutput(op, so, level, optname, m)); |
return (error); |
|
} |
|
|
|
int |
|
rip_bind(inp, nam) |
|
struct inpcb *inp; |
|
struct mbuf *nam; |
|
{ |
|
struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); |
|
|
|
if (nam->m_len != sizeof(*addr)) |
|
return (EINVAL); |
|
if (ifnet.tqh_first == 0) |
|
return (EADDRNOTAVAIL); |
|
if (addr->sin_family != AF_INET && |
|
addr->sin_family != AF_IMPLINK) |
|
return (EAFNOSUPPORT); |
|
if (!in_nullhost(addr->sin_addr) && |
|
ifa_ifwithaddr(sintosa(addr)) == 0) |
|
return (EADDRNOTAVAIL); |
|
inp->inp_laddr = addr->sin_addr; |
|
return (0); |
} |
} |
|
|
int |
int |
Line 285 rip_disconnect(inp) |
|
Line 405 rip_disconnect(inp) |
|
struct inpcb *inp; |
struct inpcb *inp; |
{ |
{ |
|
|
inp->inp_faddr.s_addr = INADDR_ANY; |
inp->inp_faddr = zeroin_addr; |
} |
} |
|
|
u_long rip_sendspace = RIPSNDQ; |
u_long rip_sendspace = RIPSNDQ; |
Line 312 rip_usrreq(so, req, m, nam, control, p) |
|
Line 432 rip_usrreq(so, req, m, nam, control, p) |
|
|
|
s = splsoftnet(); |
s = splsoftnet(); |
inp = sotoinpcb(so); |
inp = sotoinpcb(so); |
if (control && control->m_len) { |
#ifdef DIAGNOSTIC |
m_freem(control); |
if (req != PRU_SEND && req != PRU_SENDOOB && control) |
error = EINVAL; |
panic("rip_usrreq: unexpected control mbuf"); |
goto release; |
#endif |
} |
|
if (inp == 0 && req != PRU_ATTACH) { |
if (inp == 0 && req != PRU_ATTACH) { |
error = EINVAL; |
error = EINVAL; |
goto release; |
goto release; |
Line 343 rip_usrreq(so, req, m, nam, control, p) |
|
Line 462 rip_usrreq(so, req, m, nam, control, p) |
|
break; |
break; |
inp = sotoinpcb(so); |
inp = sotoinpcb(so); |
inp->inp_ip.ip_p = (long)nam; |
inp->inp_ip.ip_p = (long)nam; |
|
#ifdef IPSEC |
|
if ((error = ipsec_init_policy(&inp->inp_sp)) != 0) |
|
in_pcbdetach(inp); |
|
#endif /*IPSEC*/ |
break; |
break; |
|
|
case PRU_DETACH: |
case PRU_DETACH: |
Line 354 rip_usrreq(so, req, m, nam, control, p) |
|
Line 477 rip_usrreq(so, req, m, nam, control, p) |
|
break; |
break; |
|
|
case PRU_BIND: |
case PRU_BIND: |
{ |
error = rip_bind(inp, nam); |
struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); |
|
|
|
if (nam->m_len != sizeof(*addr)) { |
|
error = EINVAL; |
|
break; |
|
} |
|
if (ifnet.tqh_first == 0) { |
|
error = EADDRNOTAVAIL; |
|
break; |
|
} |
|
if (addr->sin_family != AF_INET && |
|
addr->sin_family != AF_IMPLINK) { |
|
error = EAFNOSUPPORT; |
|
break; |
|
} |
|
if (addr->sin_addr.s_addr != INADDR_ANY && |
|
ifa_ifwithaddr(sintosa(addr)) == 0) { |
|
error = EADDRNOTAVAIL; |
|
break; |
|
} |
|
inp->inp_laddr = addr->sin_addr; |
|
break; |
break; |
} |
|
|
|
case PRU_LISTEN: |
case PRU_LISTEN: |
error = EOPNOTSUPP; |
error = EOPNOTSUPP; |
Line 415 rip_usrreq(so, req, m, nam, control, p) |
|
Line 516 rip_usrreq(so, req, m, nam, control, p) |
|
* routine handles any massaging necessary. |
* routine handles any massaging necessary. |
*/ |
*/ |
case PRU_SEND: |
case PRU_SEND: |
{ |
if (control && control->m_len) { |
struct in_addr faddr; |
m_freem(control); |
|
m_freem(m); |
|
error = EINVAL; |
|
break; |
|
} |
|
{ |
if (nam) { |
if (nam) { |
if ((so->so_state & SS_ISCONNECTED) != 0) { |
if ((so->so_state & SS_ISCONNECTED) != 0) { |
m_freem(m); |
|
error = EISCONN; |
error = EISCONN; |
break; |
goto die; |
} |
} |
error = rip_connect(inp, nam); |
error = rip_connect(inp, nam); |
if (error) { |
if (error) { |
|
die: |
m_freem(m); |
m_freem(m); |
break; |
break; |
} |
} |
} else { |
} else { |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
m_freem(m); |
|
error = ENOTCONN; |
error = ENOTCONN; |
break; |
goto die; |
} |
} |
} |
} |
error = rip_output(m, inp); |
error = rip_output(m, inp); |
if (nam) |
if (nam) |
rip_disconnect(inp); |
rip_disconnect(inp); |
|
} |
break; |
break; |
} |
|
|
|
case PRU_SENSE: |
case PRU_SENSE: |
/* |
/* |
Line 454 rip_usrreq(so, req, m, nam, control, p) |
|
Line 558 rip_usrreq(so, req, m, nam, control, p) |
|
break; |
break; |
|
|
case PRU_SENDOOB: |
case PRU_SENDOOB: |
|
m_freem(control); |
m_freem(m); |
m_freem(m); |
error = EOPNOTSUPP; |
error = EOPNOTSUPP; |
break; |
break; |