Return to raw_ip.c CVS log | Up to [cvs.NetBSD.org] / src / sys / netinet |
Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. |
version 1.36, 1997/01/11 05:21:13 | version 1.107, 2008/04/24 11:38:38 | ||
---|---|---|---|
|
|
||
/* $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. | ||
* | * | ||
|
|
||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | * documentation and/or other materials provided with the distribution. | ||
* 3. All advertising materials mentioning features or use of this software | * 3. Neither the name of the University nor the names of its contributors | ||
* must display the following acknowledgement: | |||
* This product includes software developed by the University of | |||
* California, Berkeley and its contributors. | |||
* 4. Neither the name of the University nor the names of its contributors | |||
* may be used to endorse or promote products derived from this software | * may be used to endorse or promote products derived from this software | ||
* without specific prior written permission. | * without specific prior written permission. | ||
* | * | ||
|
|
||
* 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 <sys/cdefs.h> | |||
__KERNEL_RCSID(0, "$NetBSD$"); | |||
#include "opt_inet.h" | |||
#include "opt_ipsec.h" | |||
#include "opt_mrouting.h" | |||
#include <sys/param.h> | #include <sys/param.h> | ||
#include <sys/sysctl.h> | |||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||
#include <sys/socket.h> | #include <sys/socket.h> | ||
|
|
||
#include <sys/errno.h> | #include <sys/errno.h> | ||
#include <sys/systm.h> | #include <sys/systm.h> | ||
#include <sys/proc.h> | #include <sys/proc.h> | ||
#include <sys/kauth.h> | |||
#include <net/if.h> | #include <net/if.h> | ||
#include <net/route.h> | #include <net/route.h> | ||
|
|
||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||
#include <netinet/ip_private.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_proto.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> | |||
#include <netinet6/ipsec_private.h> | |||
#endif /* IPSEC */ | |||
#ifdef FAST_IPSEC | |||
#include <netipsec/ipsec.h> | |||
#include <netipsec/ipsec_var.h> | |||
#include <netipsec/ipsec_private.h> | |||
#endif /* FAST_IPSEC */ | |||
struct inpcbtable rawcbtable; | struct inpcbtable rawcbtable; | ||
int rip_bind __P((struct inpcb *, struct mbuf *)); | int rip_pcbnotify(struct inpcbtable *, struct in_addr, | ||
int rip_connect __P((struct inpcb *, struct mbuf *)); | struct in_addr, int, int, void (*)(struct inpcb *, int)); | ||
void rip_disconnect __P((struct inpcb *)); | int rip_bind(struct inpcb *, struct mbuf *); | ||
int rip_connect(struct inpcb *, struct mbuf *); | |||
void rip_disconnect(struct inpcb *); | |||
/* | /* | ||
* Nominal space allocated to a raw ip socket. | * Nominal space allocated to a raw ip socket. | ||
|
|
||
* Initialize raw connection block q. | * Initialize raw connection block q. | ||
*/ | */ | ||
void | void | ||
rip_init() | rip_init(void) | ||
{ | { | ||
in_pcbinit(&rawcbtable, 1, 1); | in_pcbinit(&rawcbtable, 1, 1); | ||
} | } | ||
static void | |||
rip_sbappendaddr(struct inpcb *last, struct ip *ip, const struct sockaddr *sa, | |||
int hlen, struct mbuf *opts, struct mbuf *n) | |||
{ | |||
if (last->inp_flags & INP_NOHEADER) | |||
m_adj(n, hlen); | |||
if (last->inp_flags & INP_CONTROLOPTS || | |||
last->inp_socket->so_options & SO_TIMESTAMP) | |||
ip_savecontrol(last, &opts, ip, n); | |||
if (sbappendaddr(&last->inp_socket->so_rcv, sa, n, opts) == 0) { | |||
/* should notify about lost packet */ | |||
m_freem(n); | |||
if (opts) | |||
m_freem(opts); | |||
} else | |||
sorwakeup(last->inp_socket); | |||
} | |||
/* | /* | ||
* 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 | ||
* mbuf chain. | * mbuf chain. | ||
*/ | */ | ||
void | void | ||
#if __STDC__ | |||
rip_input(struct mbuf *m, ...) | rip_input(struct mbuf *m, ...) | ||
#else | |||
rip_input(m, va_alist) | |||
struct mbuf *m; | |||
va_dcl | |||
#endif | |||
{ | { | ||
register struct ip *ip = mtod(m, struct ip *); | int hlen, proto; | ||
register struct inpcb *inp; | struct ip *ip = mtod(m, struct ip *); | ||
struct inpcb *last = 0; | struct inpcb_hdr *inph; | ||
struct mbuf *opts = 0; | struct inpcb *inp; | ||
struct inpcb *last = NULL; | |||
struct mbuf *n, *opts = NULL; | |||
struct sockaddr_in ripsrc; | struct sockaddr_in ripsrc; | ||
va_list ap; | |||
ripsrc.sin_family = AF_INET; | va_start(ap, m); | ||
ripsrc.sin_len = sizeof(struct sockaddr_in); | (void)va_arg(ap, int); /* ignore value, advance ap */ | ||
ripsrc.sin_addr = ip->ip_src; | proto = va_arg(ap, int); | ||
ripsrc.sin_port = 0; | va_end(ap); | ||
bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); | |||
sockaddr_in_init(&ripsrc, &ip->ip_src, 0); | |||
for (inp = rawcbtable.inpt_queue.cqh_first; | |||
inp != (struct inpcb *)&rawcbtable.inpt_queue; | /* | ||
inp = inp->inp_queue.cqe_next) { | * XXX Compatibility: programs using raw IP expect ip_len | ||
if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) | * XXX to have the header length subtracted, and in host order. | ||
* XXX ip_off is also expected to be host order. | |||
*/ | |||
hlen = ip->ip_hl << 2; | |||
ip->ip_len = ntohs(ip->ip_len) - hlen; | |||
NTOHS(ip->ip_off); | |||
CIRCLEQ_FOREACH(inph, &rawcbtable.inpt_queue, inph_queue) { | |||
inp = (struct inpcb *)inph; | |||
if (inp->inp_af != AF_INET) | |||
continue; | |||
if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) | |||
continue; | continue; | ||
if (!in_nullhost(inp->inp_laddr) && | if (!in_nullhost(inp->inp_laddr) && | ||
!in_hosteq(inp->inp_laddr, ip->ip_dst)) | !in_hosteq(inp->inp_laddr, ip->ip_dst)) | ||
|
|
||
if (!in_nullhost(inp->inp_faddr) && | if (!in_nullhost(inp->inp_faddr) && | ||
!in_hosteq(inp->inp_faddr, ip->ip_src)) | !in_hosteq(inp->inp_faddr, ip->ip_src)) | ||
continue; | continue; | ||
if (last) { | if (last == NULL) | ||
struct mbuf *n; | ; | ||
if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { | #if defined(IPSEC) || defined(FAST_IPSEC) | ||
if (last->inp_flags & INP_CONTROLOPTS || | /* check AH/ESP integrity. */ | ||
last->inp_socket->so_options & SO_TIMESTAMP) | else if (ipsec4_in_reject_so(m, last->inp_socket)) { | ||
ip_savecontrol(last, &opts, ip, n); | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); | ||
if (sbappendaddr(&last->inp_socket->so_rcv, | /* do not inject data to pcb */ | ||
sintosa(&ripsrc), n, opts) == 0) { | } | ||
/* should notify about lost packet */ | #endif /*IPSEC*/ | ||
m_freem(n); | else if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) { | ||
if (opts) | rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, opts, | ||
m_freem(opts); | n); | ||
} else | opts = NULL; | ||
sorwakeup(last->inp_socket); | |||
} | |||
} | } | ||
last = inp; | last = inp; | ||
} | } | ||
if (last) { | #if defined(IPSEC) || defined(FAST_IPSEC) | ||
if (last->inp_flags & INP_CONTROLOPTS || | /* check AH/ESP integrity. */ | ||
last->inp_socket->so_options & SO_TIMESTAMP) | if (last != NULL && ipsec4_in_reject_so(m, last->inp_socket)) { | ||
ip_savecontrol(last, &opts, ip, m); | m_freem(m); | ||
if (sbappendaddr(&last->inp_socket->so_rcv, | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); | ||
sintosa(&ripsrc), m, opts) == 0) { | IP_STATDEC(IP_STAT_DELIVERED); | ||
m_freem(m); | /* do not inject data to pcb */ | ||
if (opts) | } else | ||
m_freem(opts); | #endif /*IPSEC*/ | ||
} else | if (last != NULL) | ||
sorwakeup(last->inp_socket); | rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, opts, m); | ||
} else { | else if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { | ||
uint64_t *ips; | |||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, | |||
0, 0); | |||
ips = IP_STAT_GETREF(); | |||
ips[IP_STAT_NOPROTO]++; | |||
ips[IP_STAT_DELIVERED]--; | |||
IP_STAT_PUTREF(); | |||
} else | |||
m_freem(m); | m_freem(m); | ||
ipstat.ips_noproto++; | return; | ||
ipstat.ips_delivered--; | } | ||
int | |||
rip_pcbnotify(struct inpcbtable *table, | |||
struct in_addr faddr, struct in_addr laddr, int proto, int errno, | |||
void (*notify)(struct inpcb *, int)) | |||
{ | |||
struct inpcb *inp, *ninp; | |||
int nmatch; | |||
nmatch = 0; | |||
for (inp = (struct inpcb *)CIRCLEQ_FIRST(&table->inpt_queue); | |||
inp != (struct inpcb *)&table->inpt_queue; | |||
inp = ninp) { | |||
ninp = (struct inpcb *)inp->inp_queue.cqe_next; | |||
if (inp->inp_af != AF_INET) | |||
continue; | |||
if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) | |||
continue; | |||
if (in_hosteq(inp->inp_faddr, faddr) && | |||
in_hosteq(inp->inp_laddr, laddr)) { | |||
(*notify)(inp, errno); | |||
nmatch++; | |||
} | |||
} | } | ||
return nmatch; | |||
} | |||
void * | |||
rip_ctlinput(int cmd, const struct sockaddr *sa, void *v) | |||
{ | |||
struct ip *ip = v; | |||
void (*notify)(struct inpcb *, int) = in_rtchange; | |||
int errno; | |||
if (sa->sa_family != AF_INET || | |||
sa->sa_len != sizeof(struct sockaddr_in)) | |||
return NULL; | |||
if ((unsigned)cmd >= PRC_NCMDS) | |||
return NULL; | |||
errno = inetctlerrmap[cmd]; | |||
if (PRC_IS_REDIRECT(cmd)) | |||
notify = in_rtchange, ip = 0; | |||
else if (cmd == PRC_HOSTDEAD) | |||
ip = 0; | |||
else if (errno == 0) | |||
return NULL; | |||
if (ip) { | |||
rip_pcbnotify(&rawcbtable, satocsin(sa)->sin_addr, | |||
ip->ip_src, ip->ip_p, errno, notify); | |||
/* XXX mapped address case */ | |||
} else | |||
in_pcbnotifyall(&rawcbtable, satocsin(sa)->sin_addr, errno, | |||
notify); | |||
return NULL; | |||
} | } | ||
/* | /* | ||
|
|
||
* Tack on options user may have setup with control call. | * Tack on options user may have setup with control call. | ||
*/ | */ | ||
int | int | ||
#if __STDC__ | |||
rip_output(struct mbuf *m, ...) | rip_output(struct mbuf *m, ...) | ||
#else | |||
rip_output(m, va_alist) | |||
struct mbuf *m; | |||
va_dcl | |||
#endif | |||
{ | { | ||
register struct inpcb *inp; | struct inpcb *inp; | ||
register struct ip *ip; | struct ip *ip; | ||
struct mbuf *opts; | struct mbuf *opts; | ||
int flags; | int flags; | ||
va_list ap; | va_list ap; | ||
|
|
||
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. | ||
|
|
||
m_freem(m); | m_freem(m); | ||
return (EMSGSIZE); | return (EMSGSIZE); | ||
} | } | ||
M_PREPEND(m, sizeof(struct ip), M_WAIT); | M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); | ||
if (!m) | |||
return (ENOBUFS); | |||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||
ip->ip_tos = 0; | ip->ip_tos = 0; | ||
ip->ip_off = 0; | ip->ip_off = htons(0); | ||
ip->ip_p = inp->inp_ip.ip_p; | ip->ip_p = inp->inp_ip.ip_p; | ||
ip->ip_len = m->m_pkthdr.len; | ip->ip_len = htons(m->m_pkthdr.len); | ||
ip->ip_src = inp->inp_laddr; | ip->ip_src = inp->inp_laddr; | ||
ip->ip_dst = inp->inp_faddr; | ip->ip_dst = inp->inp_faddr; | ||
ip->ip_ttl = MAXTTL; | ip->ip_ttl = MAXTTL; | ||
|
|
||
return (EMSGSIZE); | return (EMSGSIZE); | ||
} | } | ||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||
if (ip->ip_id == 0) | |||
ip->ip_id = htons(ip_id++); | /* | ||
* If the mbuf is read-only, we need to allocate | |||
* a new mbuf for the header, since we need to | |||
* modify the header. | |||
*/ | |||
if (M_READONLY(m)) { | |||
int hlen = ip->ip_hl << 2; | |||
m = m_copyup(m, hlen, (max_linkhdr + 3) & ~3); | |||
if (m == NULL) | |||
return (ENOMEM); /* XXX */ | |||
ip = mtod(m, struct ip *); | |||
} | |||
/* XXX userland passes ip_len and ip_off in host order */ | |||
if (m->m_pkthdr.len != ip->ip_len) { | |||
m_freem(m); | |||
return (EINVAL); | |||
} | |||
HTONS(ip->ip_len); | |||
HTONS(ip->ip_off); | |||
if (ip->ip_id != 0 || m->m_pkthdr.len < IP_MINFRAGSIZE) | |||
flags |= IP_NOIPNEWID; | |||
opts = NULL; | opts = NULL; | ||
/* XXX prevent ip_output from overwriting header fields */ | /* XXX prevent ip_output from overwriting header fields */ | ||
flags |= IP_RAWOUTPUT; | flags |= IP_RAWOUTPUT; | ||
ipstat.ips_rawout++; | IP_STATINC(IP_STAT_RAWOUT); | ||
} | } | ||
return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); | return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, | ||
inp->inp_socket, &inp->inp_errormtu)); | |||
} | } | ||
/* | /* | ||
* Raw IP socket option processing. | * Raw IP socket option processing. | ||
*/ | */ | ||
int | int | ||
rip_ctloutput(op, so, level, optname, m) | rip_ctloutput(int op, struct socket *so, int level, int optname, | ||
int op; | struct mbuf **m) | ||
struct socket *so; | |||
int level, optname; | |||
struct mbuf **m; | |||
{ | { | ||
register struct inpcb *inp = sotoinpcb(so); | struct inpcb *inp = sotoinpcb(so); | ||
int error = 0; | int error = 0; | ||
if (level != IPPROTO_IP) { | if (level == SOL_SOCKET && optname == SO_NOHEADER) { | ||
error = ENOPROTOOPT; | if (op == PRCO_GETOPT) { | ||
if (op == PRCO_SETOPT && *m != 0) | *m = m_intopt(so, | ||
(void) m_free(*m); | (inp->inp_flags & INP_NOHEADER) ? 1 : 0); | ||
} else switch (op) { | return 0; | ||
} else if (*m == NULL || (*m)->m_len != sizeof(int)) | |||
error = EINVAL; | |||
else if (*mtod(*m, int *)) { | |||
inp->inp_flags &= ~INP_HDRINCL; | |||
inp->inp_flags |= INP_NOHEADER; | |||
} else | |||
inp->inp_flags &= ~INP_NOHEADER; | |||
goto free_m; | |||
} else if (level != IPPROTO_IP) | |||
return ip_ctloutput(op, so, level, optname, m); | |||
switch (op) { | |||
case PRCO_SETOPT: | case PRCO_SETOPT: | ||
switch (optname) { | switch (optname) { | ||
case IP_HDRINCL: | case IP_HDRINCL: | ||
if (*m == 0 || (*m)->m_len < sizeof (int)) | if (*m == NULL || (*m)->m_len != sizeof(int)) | ||
error = EINVAL; | error = EINVAL; | ||
else { | else 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; | goto free_m; | ||
} | |||
if (*m != 0) | |||
(void) m_free(*m); | |||
break; | |||
#ifdef MROUTING | #ifdef MROUTING | ||
case MRT_INIT: | case MRT_INIT: | ||
|
|
||
case MRT_ADD_MFC: | case MRT_ADD_MFC: | ||
case MRT_DEL_MFC: | case MRT_DEL_MFC: | ||
case MRT_ASSERT: | case MRT_ASSERT: | ||
case MRT_API_CONFIG: | |||
case MRT_ADD_BW_UPCALL: | |||
case MRT_DEL_BW_UPCALL: | |||
error = ip_mrouter_set(so, optname, m); | error = ip_mrouter_set(so, optname, m); | ||
break; | break; | ||
#endif | #endif | ||
|
|
||
case PRCO_GETOPT: | case PRCO_GETOPT: | ||
switch (optname) { | switch (optname) { | ||
case IP_HDRINCL: | case IP_HDRINCL: | ||
*m = m_get(M_WAIT, M_SOOPTS); | *m = m_intopt(so, inp->inp_flags & INP_HDRINCL ? 1 : 0); | ||
(*m)->m_len = sizeof (int); | |||
*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; | |||
break; | break; | ||
#ifdef MROUTING | #ifdef MROUTING | ||
case MRT_VERSION: | case MRT_VERSION: | ||
case MRT_ASSERT: | case MRT_ASSERT: | ||
case MRT_API_SUPPORT: | |||
case MRT_API_CONFIG: | |||
error = ip_mrouter_get(so, optname, m); | error = ip_mrouter_get(so, optname, m); | ||
break; | break; | ||
#endif | #endif | ||
|
|
||
} | } | ||
break; | break; | ||
} | } | ||
return (error); | return error; | ||
free_m: | |||
if (op == PRCO_SETOPT && *m != NULL) | |||
(void)m_free(*m); | |||
return error; | |||
} | } | ||
int | int | ||
rip_bind(inp, nam) | rip_bind(struct inpcb *inp, struct mbuf *nam) | ||
struct inpcb *inp; | |||
struct mbuf *nam; | |||
{ | { | ||
struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); | struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); | ||
if (nam->m_len != sizeof(*addr)) | if (nam->m_len != sizeof(*addr)) | ||
return (EINVAL); | return (EINVAL); | ||
if (ifnet.tqh_first == 0) | if (TAILQ_FIRST(&ifnet) == 0) | ||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||
if (addr->sin_family != AF_INET && | if (addr->sin_family != AF_INET && | ||
addr->sin_family != AF_IMPLINK) | addr->sin_family != AF_IMPLINK) | ||
|
|
||
} | } | ||
int | int | ||
rip_connect(inp, nam) | rip_connect(struct inpcb *inp, struct mbuf *nam) | ||
struct inpcb *inp; | |||
struct mbuf *nam; | |||
{ | { | ||
struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); | struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); | ||
if (nam->m_len != sizeof(*addr)) | if (nam->m_len != sizeof(*addr)) | ||
return (EINVAL); | return (EINVAL); | ||
if (ifnet.tqh_first == 0) | if (TAILQ_FIRST(&ifnet) == 0) | ||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||
if (addr->sin_family != AF_INET && | if (addr->sin_family != AF_INET && | ||
addr->sin_family != AF_IMPLINK) | addr->sin_family != AF_IMPLINK) | ||
|
|
||
} | } | ||
void | void | ||
rip_disconnect(inp) | rip_disconnect(struct inpcb *inp) | ||
struct inpcb *inp; | |||
{ | { | ||
inp->inp_faddr = zeroin_addr; | inp->inp_faddr = zeroin_addr; | ||
|
|
||
/*ARGSUSED*/ | /*ARGSUSED*/ | ||
int | int | ||
rip_usrreq(so, req, m, nam, control, p) | rip_usrreq(struct socket *so, int req, | ||
register struct socket *so; | struct mbuf *m, struct mbuf *nam, struct mbuf *control, struct lwp *l) | ||
int req; | |||
struct mbuf *m, *nam, *control; | |||
struct proc *p; | |||
{ | { | ||
register struct inpcb *inp; | struct inpcb *inp; | ||
int s; | int s; | ||
register int error = 0; | int error = 0; | ||
#ifdef MROUTING | #ifdef MROUTING | ||
extern struct socket *ip_mrouter; | extern struct socket *ip_mrouter; | ||
#endif | #endif | ||
if (req == PRU_CONTROL) | if (req == PRU_CONTROL) | ||
return (in_control(so, (long)m, (caddr_t)nam, | return (in_control(so, (long)m, (void *)nam, | ||
(struct ifnet *)control, p)); | (struct ifnet *)control, l)); | ||
s = splsoftnet(); | s = splsoftnet(); | ||
if (req == PRU_PURGEIF) { | |||
mutex_enter(softnet_lock); | |||
in_pcbpurgeif0(&rawcbtable, (struct ifnet *)control); | |||
in_purgeif((struct ifnet *)control); | |||
in_pcbpurgeif(&rawcbtable, (struct ifnet *)control); | |||
mutex_exit(softnet_lock); | |||
splx(s); | |||
return (0); | |||
} | |||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||
if (req != PRU_SEND && req != PRU_SENDOOB && control) | if (req != PRU_SEND && req != PRU_SENDOOB && control) | ||
|
|
||
switch (req) { | switch (req) { | ||
case PRU_ATTACH: | case PRU_ATTACH: | ||
sosetlock(so); | |||
if (inp != 0) { | if (inp != 0) { | ||
error = EISCONN; | error = EISCONN; | ||
break; | break; | ||
} | } | ||
if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { | |||
if (l == NULL) { | |||
error = EACCES; | error = EACCES; | ||
break; | break; | ||
} | } | ||
/* XXX: raw socket permissions are checked in socreate() */ | |||
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { | if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { | ||
error = soreserve(so, rip_sendspace, rip_recvspace); | error = soreserve(so, rip_sendspace, rip_recvspace); | ||
if (error) | if (error) | ||
|
|
||
splx(s); | splx(s); | ||
return (error); | return (error); | ||
} | } | ||
SYSCTL_SETUP(sysctl_net_inet_raw_setup, "sysctl net.inet.raw subtree setup") | |||
{ | |||
sysctl_createv(clog, 0, NULL, NULL, | |||
CTLFLAG_PERMANENT, | |||
CTLTYPE_NODE, "net", NULL, | |||
NULL, 0, NULL, 0, | |||
CTL_NET, CTL_EOL); | |||
sysctl_createv(clog, 0, NULL, NULL, | |||
CTLFLAG_PERMANENT, | |||
CTLTYPE_NODE, "inet", NULL, | |||
NULL, 0, NULL, 0, | |||
CTL_NET, PF_INET, CTL_EOL); | |||
sysctl_createv(clog, 0, NULL, NULL, | |||
CTLFLAG_PERMANENT, | |||
CTLTYPE_NODE, "raw", | |||
SYSCTL_DESCR("Raw IPv4 settings"), | |||
NULL, 0, NULL, 0, | |||
CTL_NET, PF_INET, IPPROTO_RAW, CTL_EOL); | |||
sysctl_createv(clog, 0, NULL, NULL, | |||
CTLFLAG_PERMANENT, | |||
CTLTYPE_STRUCT, "pcblist", | |||
SYSCTL_DESCR("Raw IPv4 control block list"), | |||
sysctl_inpcblist, 0, &rawcbtable, 0, | |||
CTL_NET, PF_INET, IPPROTO_RAW, | |||
CTL_CREATE, CTL_EOL); | |||
} |