/* $NetBSD: raw_ip.c,v 1.187 2025/06/20 15:15:35 roy Exp $ */
/*
* 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
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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.
*
* @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
*/
if (last->inp_flags & INP_NOHEADER)
m_adj(n, hlen);
if (last->inp_flags & INP_CONTROLOPTS ||
SOOPT_TIMESTAMP(last->inp_socket->so_options))
ip_savecontrol(last, &opts, ip, n);
if (sbappendaddr(&last->inp_socket->so_rcv, sa, n, opts) == 0) {
soroverflow(last->inp_socket);
m_freem(n);
m_freem(opts);
} else {
sorwakeup(last->inp_socket);
}
}
/*
* Setup generic address and protocol structures
* for raw_input routine, then pass them along with
* mbuf chain.
*/
void
rip_input(struct mbuf *m, int off, int proto)
{
struct ip *ip = mtod(m, struct ip *);
struct inpcb *inp;
struct inpcb *last = NULL;
struct mbuf *n;
struct sockaddr_in ripsrc;
int hlen;
sockaddr_in_init(&ripsrc, &ip->ip_src, 0);
/*
* XXX Compatibility: programs using raw IP expect ip_len
* 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);
TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
if (inp->inp_af != AF_INET)
continue;
if (in4p_ip(inp).ip_p && in4p_ip(inp).ip_p != proto)
continue;
if (!in_nullhost(in4p_laddr(inp)) &&
!in_hosteq(in4p_laddr(inp), ip->ip_dst))
continue;
if (!in_nullhost(in4p_faddr(inp)) &&
!in_hosteq(in4p_faddr(inp), ip->ip_src))
continue;
if (last == NULL) {
;
}
#if defined(IPSEC)
else if (ipsec_used && ipsec_in_reject(m, last)) {
/* do not inject data into pcb */
}
#endif
else if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) {
rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, n);
}
last = inp;
}
#if defined(IPSEC)
if (ipsec_used && last != NULL && ipsec_in_reject(m, last)) {
m_freem(m);
IP_STATDEC(IP_STAT_DELIVERED);
/* do not inject data into pcb */
} else
#endif
if (last != NULL) {
rip_sbappendaddr(last, ip, sintosa(&ripsrc), hlen, m);
} else if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) {
net_stat_ref_t ips;
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;
int nmatch;
/*
* Generate IP header and pass packet to ip_output.
* Tack on options user may have setup with control call.
*/
int
rip_output(struct mbuf *m, struct inpcb *inp, struct mbuf *control,
struct lwp *l)
{
struct ip *ip;
struct mbuf *opts;
struct ip_pktopts pktopts;
kauth_cred_t cred;
int error, flags;
/*
* If the user handed us a complete IP packet, use it.
* Otherwise, allocate an mbuf for a header and fill it in.
*/
if ((inp->inp_flags & INP_HDRINCL) == 0) {
if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
error = EMSGSIZE;
goto release;
}
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
if (!m) {
error = ENOBUFS;
goto release;
}
ip = mtod(m, struct ip *);
ip->ip_tos = in4p_ip(inp).ip_tos;
ip->ip_off = htons(0);
ip->ip_p = in4p_ip(inp).ip_p;
ip->ip_len = htons(m->m_pkthdr.len);
ip->ip_src = pktopts.ippo_laddr.sin_addr;
ip->ip_dst = in4p_faddr(inp);
ip->ip_ttl = in4p_ip(inp).ip_ttl ? in4p_ip(inp).ip_ttl : MAXTTL;
opts = inp->inp_options;
} else {
if (m->m_pkthdr.len > IP_MAXPACKET) {
error = EMSGSIZE;
goto release;
}
if (m->m_pkthdr.len < sizeof(struct ip)) {
error = EINVAL;
goto release;
}
ip = mtod(m, struct ip *);
/*
* 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) {
error = ENOMEM;
goto release;
}
ip = mtod(m, struct ip *);
}
/* XXX userland passes ip_len and ip_off in host order */
if (m->m_pkthdr.len != ip->ip_len) {
error = EINVAL;
goto release;
}
HTONS(ip->ip_len);
HTONS(ip->ip_off);
/*
* IP output. Note: if IP_RETURNMTU flag is set, the MTU size
* will be stored in inp_errormtu.
*/
return ip_output(m, opts, &inp->inp_route, flags, pktopts.ippo_imo,
inp);
release:
m_freem(m);
return error;
}
/*
* Raw IP socket option processing.
*/
int
rip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
{
struct inpcb *inp = sotoinpcb(so);
int error = 0;
int optval;
if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
if (op == PRCO_GETOPT) {
optval = (inp->inp_flags & INP_NOHEADER) ? 1 : 0;
error = sockopt_set(sopt, &optval, sizeof(optval));
} else if (op == PRCO_SETOPT) {
error = sockopt_getint(sopt, &optval);
if (error)
goto out;
if (optval) {
inp->inp_flags &= ~INP_HDRINCL;
inp->inp_flags |= INP_NOHEADER;
} else
inp->inp_flags &= ~INP_NOHEADER;
}
goto out;
} else if (sopt->sopt_level != IPPROTO_IP)
return ip_ctloutput(op, so, sopt);
switch (op) {
case PRCO_SETOPT:
switch (sopt->sopt_name) {
case IP_HDRINCL:
error = sockopt_getint(sopt, &optval);
if (error)
break;
if (optval)
inp->inp_flags |= INP_HDRINCL;
else
inp->inp_flags &= ~INP_HDRINCL;
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:
case MRT_API_CONFIG:
case MRT_ADD_BW_UPCALL:
case MRT_DEL_BW_UPCALL:
error = ip_mrouter_set(so, sopt);
break;
#endif
default:
error = ip_ctloutput(op, so, sopt);
break;
}
break;
case PRCO_GETOPT:
switch (sopt->sopt_name) {
case IP_HDRINCL:
optval = inp->inp_flags & INP_HDRINCL;
error = sockopt_set(sopt, &optval, sizeof(optval));
break;
#ifdef MROUTING
case MRT_VERSION:
case MRT_ASSERT:
case MRT_API_SUPPORT:
case MRT_API_CONFIG:
error = ip_mrouter_get(so, sopt);
break;
#endif