Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/raw_ip.c
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
VNET_DEFINE(int, ip_defttl) = IPDEFTTL; | VNET_DEFINE(int, ip_defttl) = IPDEFTTL; | ||||
SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_VNET | CTLFLAG_RW, | SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_VNET | CTLFLAG_RW, | ||||
&VNET_NAME(ip_defttl), 0, | &VNET_NAME(ip_defttl), 0, | ||||
"Maximum TTL on IP packets"); | "Maximum TTL on IP packets"); | ||||
VNET_DEFINE(struct inpcbhead, ripcb); | |||||
VNET_DEFINE(struct inpcbinfo, ripcbinfo); | VNET_DEFINE(struct inpcbinfo, ripcbinfo); | ||||
#define V_ripcb VNET(ripcb) | |||||
#define V_ripcbinfo VNET(ripcbinfo) | #define V_ripcbinfo VNET(ripcbinfo) | ||||
/* | /* | ||||
* Control and data hooks for ipfw, dummynet, divert and so on. | * Control and data hooks for ipfw, dummynet, divert and so on. | ||||
* The data hooks are not used here but it is convenient | * The data hooks are not used here but it is convenient | ||||
* to keep them all in one place. | * to keep them all in one place. | ||||
*/ | */ | ||||
VNET_DEFINE(ip_fw_chk_ptr_t, ip_fw_chk_ptr) = NULL; | VNET_DEFINE(ip_fw_chk_ptr_t, ip_fw_chk_ptr) = NULL; | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#ifdef INET | #ifdef INET | ||||
static void | static void | ||||
rip_inshash(struct inpcb *inp) | rip_inshash(struct inpcb *inp) | ||||
{ | { | ||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | ||||
struct inpcbhead *pcbhash; | struct inpcbhead *pcbhash; | ||||
int hash; | int hash; | ||||
INP_INFO_WLOCK_ASSERT(pcbinfo); | INP_HASH_WLOCK_ASSERT(pcbinfo); | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
if (inp->inp_ip_p != 0 && | if (inp->inp_ip_p != 0 && | ||||
inp->inp_laddr.s_addr != INADDR_ANY && | inp->inp_laddr.s_addr != INADDR_ANY && | ||||
inp->inp_faddr.s_addr != INADDR_ANY) { | inp->inp_faddr.s_addr != INADDR_ANY) { | ||||
hash = INP_PCBHASH_RAW(inp->inp_ip_p, inp->inp_laddr.s_addr, | hash = INP_PCBHASH_RAW(inp->inp_ip_p, inp->inp_laddr.s_addr, | ||||
inp->inp_faddr.s_addr, pcbinfo->ipi_hashmask); | inp->inp_faddr.s_addr, pcbinfo->ipi_hashmask); | ||||
} else | } else | ||||
hash = 0; | hash = 0; | ||||
pcbhash = &pcbinfo->ipi_hashbase[hash]; | pcbhash = &pcbinfo->ipi_hashbase[hash]; | ||||
CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash); | CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash); | ||||
} | } | ||||
static void | static void | ||||
rip_delhash(struct inpcb *inp) | rip_delhash(struct inpcb *inp) | ||||
{ | { | ||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); | INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
CK_LIST_REMOVE(inp, inp_hash); | CK_LIST_REMOVE(inp, inp_hash); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
/* | /* | ||||
* Raw interface to IP protocol. | * Raw interface to IP protocol. | ||||
Show All 17 Lines | rip_inpcb_init(void *mem, int size, int flags) | ||||
INP_LOCK_INIT(inp, "inp", "rawinp"); | INP_LOCK_INIT(inp, "inp", "rawinp"); | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
rip_init(void) | rip_init(void) | ||||
{ | { | ||||
in_pcbinfo_init(&V_ripcbinfo, "rip", &V_ripcb, INP_PCBHASH_RAW_SIZE, | in_pcbinfo_init(&V_ripcbinfo, "rip", INP_PCBHASH_RAW_SIZE, 1, "ripcb", | ||||
1, "ripcb", rip_inpcb_init, IPI_HASHFIELDS_NONE); | rip_inpcb_init); | ||||
EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL, | EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL, | ||||
EVENTHANDLER_PRI_ANY); | EVENTHANDLER_PRI_ANY); | ||||
} | } | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
static void | static void | ||||
rip_destroy(void *unused __unused) | rip_destroy(void *unused __unused) | ||||
{ | { | ||||
in_pcbinfo_destroy(&V_ripcbinfo); | in_pcbinfo_destroy(&V_ripcbinfo); | ||||
} | } | ||||
VNET_SYSUNINIT(raw_ip, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, rip_destroy, NULL); | VNET_SYSUNINIT(raw_ip, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, rip_destroy, NULL); | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
static int | static int | ||||
rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n, | rip_append(struct inpcb *inp, struct ip *ip, struct mbuf *m, | ||||
struct sockaddr_in *ripsrc) | struct sockaddr_in *ripsrc) | ||||
{ | { | ||||
int policyfail = 0; | struct socket *so = inp->inp_socket; | ||||
struct mbuf *n, *opts = NULL; | |||||
INP_LOCK_ASSERT(last); | INP_LOCK_ASSERT(inp); | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
/* check AH/ESP integrity. */ | /* check AH/ESP integrity. */ | ||||
if (IPSEC_ENABLED(ipv4)) { | if (IPSEC_ENABLED(ipv4) && IPSEC_CHECK_POLICY(ipv4, m, inp) != 0) | ||||
if (IPSEC_CHECK_POLICY(ipv4, n, last) != 0) | return (0); | ||||
policyfail = 1; | |||||
} | |||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
#ifdef MAC | #ifdef MAC | ||||
if (!policyfail && mac_inpcb_check_deliver(last, n) != 0) | if (mac_inpcb_check_deliver(inp, m) != 0) | ||||
policyfail = 1; | return (0); | ||||
#endif | #endif | ||||
/* Check the minimum TTL for socket. */ | /* Check the minimum TTL for socket. */ | ||||
if (last->inp_ip_minttl && last->inp_ip_minttl > ip->ip_ttl) | if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) | ||||
policyfail = 1; | return (0); | ||||
if (!policyfail) { | |||||
struct mbuf *opts = NULL; | |||||
struct socket *so; | |||||
so = last->inp_socket; | if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) | ||||
if ((last->inp_flags & INP_CONTROLOPTS) || | return (0); | ||||
if ((inp->inp_flags & INP_CONTROLOPTS) || | |||||
(so->so_options & (SO_TIMESTAMP | SO_BINTIME))) | (so->so_options & (SO_TIMESTAMP | SO_BINTIME))) | ||||
ip_savecontrol(last, &opts, ip, n); | ip_savecontrol(inp, &opts, ip, n); | ||||
SOCKBUF_LOCK(&so->so_rcv); | SOCKBUF_LOCK(&so->so_rcv); | ||||
if (sbappendaddr_locked(&so->so_rcv, | if (sbappendaddr_locked(&so->so_rcv, | ||||
(struct sockaddr *)ripsrc, n, opts) == 0) { | (struct sockaddr *)ripsrc, n, opts) == 0) { | ||||
soroverflow_locked(so); | soroverflow_locked(so); | ||||
m_freem(n); | m_freem(n); | ||||
if (opts) | if (opts) | ||||
m_freem(opts); | m_freem(opts); | ||||
} else | return (0); | ||||
} | |||||
sorwakeup_locked(so); | sorwakeup_locked(so); | ||||
} else | |||||
m_freem(n); | return (1); | ||||
return (policyfail); | |||||
} | } | ||||
struct rip_inp_match_ctx { | |||||
struct ip *ip; | |||||
int proto; | |||||
}; | |||||
static bool | |||||
rip_inp_match1(const struct inpcb *inp, void *v) | |||||
{ | |||||
struct rip_inp_match_ctx *ctx = v; | |||||
if (inp->inp_ip_p != ctx->proto) | |||||
return (false); | |||||
#ifdef INET6 | |||||
/* XXX inp locking */ | |||||
if ((inp->inp_vflag & INP_IPV4) == 0) | |||||
return (false); | |||||
#endif | |||||
if (inp->inp_laddr.s_addr != ctx->ip->ip_dst.s_addr) | |||||
return (false); | |||||
if (inp->inp_faddr.s_addr != ctx->ip->ip_src.s_addr) | |||||
return (false); | |||||
return (true); | |||||
} | |||||
static bool | |||||
rip_inp_match2(const struct inpcb *inp, void *v) | |||||
{ | |||||
struct rip_inp_match_ctx *ctx = v; | |||||
if (inp->inp_ip_p && inp->inp_ip_p != ctx->proto) | |||||
return (false); | |||||
#ifdef INET6 | |||||
/* XXX inp locking */ | |||||
if ((inp->inp_vflag & INP_IPV4) == 0) | |||||
return (false); | |||||
#endif | |||||
if (!in_nullhost(inp->inp_laddr) && | |||||
!in_hosteq(inp->inp_laddr, ctx->ip->ip_dst)) | |||||
return (false); | |||||
if (!in_nullhost(inp->inp_faddr) && | |||||
!in_hosteq(inp->inp_faddr, ctx->ip->ip_src)) | |||||
return (false); | |||||
return (true); | |||||
} | |||||
/* | /* | ||||
* Setup generic address and protocol structures for raw_input routine, then | * Setup generic address and protocol structures for raw_input routine, then | ||||
* pass them along with mbuf chain. | * pass them along with mbuf chain. | ||||
*/ | */ | ||||
int | int | ||||
rip_input(struct mbuf **mp, int *offp, int proto) | rip_input(struct mbuf **mp, int *offp, int proto) | ||||
{ | { | ||||
struct rip_inp_match_ctx ctx = { | |||||
.ip = mtod(*mp, struct ip *), | |||||
.proto = proto, | |||||
}; | |||||
struct inpcb_iterator inpi = INP_ITERATOR(&V_ripcbinfo, | |||||
INPLOOKUP_RLOCKPCB, rip_inp_match1, &ctx); | |||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct mbuf *m = *mp; | struct mbuf *m = *mp; | ||||
struct ip *ip = mtod(m, struct ip *); | struct inpcb *inp; | ||||
struct inpcb *inp, *last; | |||||
struct sockaddr_in ripsrc; | struct sockaddr_in ripsrc; | ||||
int hash; | int appended; | ||||
NET_EPOCH_ASSERT(); | |||||
*mp = NULL; | *mp = NULL; | ||||
appended = 0; | |||||
bzero(&ripsrc, sizeof(ripsrc)); | bzero(&ripsrc, sizeof(ripsrc)); | ||||
ripsrc.sin_len = sizeof(ripsrc); | ripsrc.sin_len = sizeof(ripsrc); | ||||
ripsrc.sin_family = AF_INET; | ripsrc.sin_family = AF_INET; | ||||
ripsrc.sin_addr = ip->ip_src; | ripsrc.sin_addr = ctx.ip->ip_src; | ||||
last = NULL; | |||||
ifp = m->m_pkthdr.rcvif; | ifp = m->m_pkthdr.rcvif; | ||||
hash = INP_PCBHASH_RAW(proto, ip->ip_src.s_addr, | inpi.hash = INP_PCBHASH_RAW(proto, ctx.ip->ip_src.s_addr, | ||||
ip->ip_dst.s_addr, V_ripcbinfo.ipi_hashmask); | ctx.ip->ip_dst.s_addr, V_ripcbinfo.ipi_hashmask); | ||||
CK_LIST_FOREACH(inp, &V_ripcbinfo.ipi_hashbase[hash], inp_hash) { | while ((inp = inp_next(&inpi)) != NULL) { | ||||
if (inp->inp_ip_p != proto) | INP_RLOCK_ASSERT(inp); | ||||
continue; | if (jailed_without_vnet(inp->inp_cred) && | ||||
#ifdef INET6 | prison_check_ip4(inp->inp_cred, &ctx.ip->ip_dst) != 0) { | ||||
/* XXX inp locking */ | |||||
if ((inp->inp_vflag & INP_IPV4) == 0) | |||||
continue; | |||||
#endif | |||||
if (inp->inp_laddr.s_addr != ip->ip_dst.s_addr) | |||||
continue; | |||||
if (inp->inp_faddr.s_addr != ip->ip_src.s_addr) | |||||
continue; | |||||
if (last != NULL) { | |||||
struct mbuf *n; | |||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT); | |||||
if (n != NULL) | |||||
(void) rip_append(last, ip, n, &ripsrc); | |||||
/* XXX count dropped packet */ | |||||
INP_RUNLOCK(last); | |||||
last = NULL; | |||||
} | |||||
INP_RLOCK(inp); | |||||
if (__predict_false(inp->inp_flags2 & INP_FREED)) | |||||
goto skip_1; | |||||
if (jailed_without_vnet(inp->inp_cred)) { | |||||
/* | /* | ||||
* XXX: If faddr was bound to multicast group, | * XXX: If faddr was bound to multicast group, | ||||
* jailed raw socket will drop datagram. | * jailed raw socket will drop datagram. | ||||
*/ | */ | ||||
if (prison_check_ip4(inp->inp_cred, &ip->ip_dst) != 0) | |||||
goto skip_1; | |||||
} | |||||
last = inp; | |||||
continue; | continue; | ||||
skip_1: | |||||
INP_RUNLOCK(inp); | |||||
} | } | ||||
CK_LIST_FOREACH(inp, &V_ripcbinfo.ipi_hashbase[0], inp_hash) { | appended += rip_append(inp, ctx.ip, m, &ripsrc); | ||||
if (inp->inp_ip_p && inp->inp_ip_p != proto) | |||||
continue; | |||||
#ifdef INET6 | |||||
/* XXX inp locking */ | |||||
if ((inp->inp_vflag & INP_IPV4) == 0) | |||||
continue; | |||||
#endif | |||||
if (!in_nullhost(inp->inp_laddr) && | |||||
!in_hosteq(inp->inp_laddr, ip->ip_dst)) | |||||
continue; | |||||
if (!in_nullhost(inp->inp_faddr) && | |||||
!in_hosteq(inp->inp_faddr, ip->ip_src)) | |||||
continue; | |||||
if (last != NULL) { | |||||
struct mbuf *n; | |||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT); | |||||
if (n != NULL) | |||||
(void) rip_append(last, ip, n, &ripsrc); | |||||
/* XXX count dropped packet */ | |||||
INP_RUNLOCK(last); | |||||
last = NULL; | |||||
} | } | ||||
INP_RLOCK(inp); | |||||
if (__predict_false(inp->inp_flags2 & INP_FREED)) | inpi.hash = 0; | ||||
goto skip_2; | inpi.match = rip_inp_match2; | ||||
if (jailed_without_vnet(inp->inp_cred)) { | MPASS(inpi.inp == NULL); | ||||
while ((inp = inp_next(&inpi)) != NULL) { | |||||
INP_RLOCK_ASSERT(inp); | |||||
if (jailed_without_vnet(inp->inp_cred) && | |||||
!IN_MULTICAST(ntohl(ctx.ip->ip_dst.s_addr)) && | |||||
prison_check_ip4(inp->inp_cred, &ctx.ip->ip_dst) != 0) | |||||
/* | /* | ||||
* Allow raw socket in jail to receive multicast; | * Allow raw socket in jail to receive multicast; | ||||
* assume process had PRIV_NETINET_RAW at attach, | * assume process had PRIV_NETINET_RAW at attach, | ||||
* and fall through into normal filter path if so. | * and fall through into normal filter path if so. | ||||
*/ | */ | ||||
if (!IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && | continue; | ||||
prison_check_ip4(inp->inp_cred, &ip->ip_dst) != 0) | |||||
goto skip_2; | |||||
} | |||||
/* | /* | ||||
* If this raw socket has multicast state, and we | * If this raw socket has multicast state, and we | ||||
* have received a multicast, check if this socket | * have received a multicast, check if this socket | ||||
* should receive it, as multicast filtering is now | * should receive it, as multicast filtering is now | ||||
* the responsibility of the transport layer. | * the responsibility of the transport layer. | ||||
*/ | */ | ||||
if (inp->inp_moptions != NULL && | if (inp->inp_moptions != NULL && | ||||
IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { | IN_MULTICAST(ntohl(ctx.ip->ip_dst.s_addr))) { | ||||
/* | /* | ||||
* If the incoming datagram is for IGMP, allow it | * If the incoming datagram is for IGMP, allow it | ||||
* through unconditionally to the raw socket. | * through unconditionally to the raw socket. | ||||
* | * | ||||
* In the case of IGMPv2, we may not have explicitly | * In the case of IGMPv2, we may not have explicitly | ||||
* joined the group, and may have set IFF_ALLMULTI | * joined the group, and may have set IFF_ALLMULTI | ||||
* on the interface. imo_multi_filter() may discard | * on the interface. imo_multi_filter() may discard | ||||
* control traffic we actually need to see. | * control traffic we actually need to see. | ||||
* | * | ||||
* Userland multicast routing daemons should continue | * Userland multicast routing daemons should continue | ||||
* filter the control traffic appropriately. | * filter the control traffic appropriately. | ||||
*/ | */ | ||||
int blocked; | int blocked; | ||||
blocked = MCAST_PASS; | blocked = MCAST_PASS; | ||||
if (proto != IPPROTO_IGMP) { | if (proto != IPPROTO_IGMP) { | ||||
struct sockaddr_in group; | struct sockaddr_in group; | ||||
bzero(&group, sizeof(struct sockaddr_in)); | bzero(&group, sizeof(struct sockaddr_in)); | ||||
group.sin_len = sizeof(struct sockaddr_in); | group.sin_len = sizeof(struct sockaddr_in); | ||||
group.sin_family = AF_INET; | group.sin_family = AF_INET; | ||||
group.sin_addr = ip->ip_dst; | group.sin_addr = ctx.ip->ip_dst; | ||||
blocked = imo_multi_filter(inp->inp_moptions, | blocked = imo_multi_filter(inp->inp_moptions, | ||||
ifp, | ifp, | ||||
(struct sockaddr *)&group, | (struct sockaddr *)&group, | ||||
(struct sockaddr *)&ripsrc); | (struct sockaddr *)&ripsrc); | ||||
} | } | ||||
if (blocked != MCAST_PASS) { | if (blocked != MCAST_PASS) { | ||||
IPSTAT_INC(ips_notmember); | IPSTAT_INC(ips_notmember); | ||||
goto skip_2; | continue; | ||||
} | } | ||||
} | } | ||||
last = inp; | appended += rip_append(inp, ctx.ip, m, &ripsrc); | ||||
continue; | |||||
skip_2: | |||||
INP_RUNLOCK(inp); | |||||
} | } | ||||
if (last != NULL) { | if (appended == 0 && | ||||
if (rip_append(last, ip, m, &ripsrc) != 0) | inetsw[ip_protox[ctx.ip->ip_p]].pr_input == rip_input) { | ||||
IPSTAT_INC(ips_delivered); | |||||
INP_RUNLOCK(last); | |||||
} else { | |||||
if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { | |||||
IPSTAT_INC(ips_noproto); | IPSTAT_INC(ips_noproto); | ||||
IPSTAT_DEC(ips_delivered); | IPSTAT_DEC(ips_delivered); | ||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0); | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0); | ||||
} else { | } else | ||||
m_freem(m); | m_freem(m); | ||||
} | |||||
} | |||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
} | } | ||||
/* | /* | ||||
* Generate IP header and pass packet to ip_output. Tack on options user may | * Generate IP header and pass packet to ip_output. Tack on options user may | ||||
* have setup with control call. | * have setup with control call. | ||||
*/ | */ | ||||
int | int | ||||
▲ Show 20 Lines • Show All 446 Lines • ▼ Show 20 Lines | rip_attach(struct socket *so, int proto, struct thread *td) | ||||
error = priv_check(td, PRIV_NETINET_RAW); | error = priv_check(td, PRIV_NETINET_RAW); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
if (proto >= IPPROTO_MAX || proto < 0) | if (proto >= IPPROTO_MAX || proto < 0) | ||||
return EPROTONOSUPPORT; | return EPROTONOSUPPORT; | ||||
error = soreserve(so, rip_sendspace, rip_recvspace); | error = soreserve(so, rip_sendspace, rip_recvspace); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
INP_INFO_WLOCK(&V_ripcbinfo); | |||||
error = in_pcballoc(so, &V_ripcbinfo); | error = in_pcballoc(so, &V_ripcbinfo); | ||||
if (error) { | if (error) | ||||
INP_INFO_WUNLOCK(&V_ripcbinfo); | |||||
return (error); | return (error); | ||||
} | |||||
inp = (struct inpcb *)so->so_pcb; | inp = (struct inpcb *)so->so_pcb; | ||||
inp->inp_vflag |= INP_IPV4; | inp->inp_vflag |= INP_IPV4; | ||||
inp->inp_ip_p = proto; | inp->inp_ip_p = proto; | ||||
inp->inp_ip_ttl = V_ip_defttl; | inp->inp_ip_ttl = V_ip_defttl; | ||||
INP_HASH_WLOCK(&V_ripcbinfo); | |||||
rip_inshash(inp); | rip_inshash(inp); | ||||
INP_INFO_WUNLOCK(&V_ripcbinfo); | INP_HASH_WUNLOCK(&V_ripcbinfo); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
rip_detach(struct socket *so) | rip_detach(struct socket *so) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
KASSERT(inp != NULL, ("rip_detach: inp == NULL")); | KASSERT(inp != NULL, ("rip_detach: inp == NULL")); | ||||
KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, | KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, | ||||
("rip_detach: not closed")); | ("rip_detach: not closed")); | ||||
INP_INFO_WLOCK(&V_ripcbinfo); | |||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
INP_HASH_WLOCK(&V_ripcbinfo); | |||||
rip_delhash(inp); | rip_delhash(inp); | ||||
INP_HASH_WUNLOCK(&V_ripcbinfo); | |||||
if (so == V_ip_mrouter && ip_mrouter_done) | if (so == V_ip_mrouter && ip_mrouter_done) | ||||
ip_mrouter_done(); | ip_mrouter_done(); | ||||
if (ip_rsvp_force_done) | if (ip_rsvp_force_done) | ||||
ip_rsvp_force_done(so); | ip_rsvp_force_done(so); | ||||
if (so == V_ip_rsvpd) | if (so == V_ip_rsvpd) | ||||
ip_rsvp_done(); | ip_rsvp_done(); | ||||
in_pcbdetach(inp); | in_pcbdetach(inp); | ||||
in_pcbfree(inp); | in_pcbfree(inp); | ||||
INP_INFO_WUNLOCK(&V_ripcbinfo); | |||||
} | } | ||||
static void | static void | ||||
rip_dodisconnect(struct socket *so, struct inpcb *inp) | rip_dodisconnect(struct socket *so, struct inpcb *inp) | ||||
{ | { | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
pcbinfo = inp->inp_pcbinfo; | pcbinfo = inp->inp_pcbinfo; | ||||
INP_INFO_WLOCK(pcbinfo); | |||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
INP_HASH_WLOCK(pcbinfo); | |||||
rip_delhash(inp); | rip_delhash(inp); | ||||
inp->inp_faddr.s_addr = INADDR_ANY; | inp->inp_faddr.s_addr = INADDR_ANY; | ||||
rip_inshash(inp); | rip_inshash(inp); | ||||
INP_HASH_WUNLOCK(pcbinfo); | |||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
so->so_state &= ~SS_ISCONNECTED; | so->so_state &= ~SS_ISCONNECTED; | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
} | } | ||||
static void | static void | ||||
rip_abort(struct socket *so) | rip_abort(struct socket *so) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) | ||||
if (CK_STAILQ_EMPTY(&V_ifnet) || | if (CK_STAILQ_EMPTY(&V_ifnet) || | ||||
(addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || | (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || | ||||
(addr->sin_addr.s_addr && | (addr->sin_addr.s_addr && | ||||
(inp->inp_flags & INP_BINDANY) == 0 && | (inp->inp_flags & INP_BINDANY) == 0 && | ||||
ifa_ifwithaddr_check((struct sockaddr *)addr) == 0)) | ifa_ifwithaddr_check((struct sockaddr *)addr) == 0)) | ||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||
INP_INFO_WLOCK(&V_ripcbinfo); | |||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
INP_HASH_WLOCK(&V_ripcbinfo); | |||||
rip_delhash(inp); | rip_delhash(inp); | ||||
inp->inp_laddr = addr->sin_addr; | inp->inp_laddr = addr->sin_addr; | ||||
rip_inshash(inp); | rip_inshash(inp); | ||||
INP_HASH_WUNLOCK(&V_ripcbinfo); | |||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_WUNLOCK(&V_ripcbinfo); | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) | rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) | ||||
{ | { | ||||
struct sockaddr_in *addr = (struct sockaddr_in *)nam; | struct sockaddr_in *addr = (struct sockaddr_in *)nam; | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
if (nam->sa_len != sizeof(*addr)) | if (nam->sa_len != sizeof(*addr)) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (CK_STAILQ_EMPTY(&V_ifnet)) | if (CK_STAILQ_EMPTY(&V_ifnet)) | ||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||
if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) | if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) | ||||
return (EAFNOSUPPORT); | return (EAFNOSUPPORT); | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
KASSERT(inp != NULL, ("rip_connect: inp == NULL")); | KASSERT(inp != NULL, ("rip_connect: inp == NULL")); | ||||
INP_INFO_WLOCK(&V_ripcbinfo); | |||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
INP_HASH_WLOCK(&V_ripcbinfo); | |||||
rip_delhash(inp); | rip_delhash(inp); | ||||
inp->inp_faddr = addr->sin_addr; | inp->inp_faddr = addr->sin_addr; | ||||
rip_inshash(inp); | rip_inshash(inp); | ||||
INP_HASH_WUNLOCK(&V_ripcbinfo); | |||||
soisconnected(so); | soisconnected(so); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_WUNLOCK(&V_ripcbinfo); | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rip_shutdown(struct socket *so) | rip_shutdown(struct socket *so) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | release: | ||||
m_freem(m); | m_freem(m); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
static int | static int | ||||
rip_pcblist(SYSCTL_HANDLER_ARGS) | rip_pcblist(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct inpcb_iterator inpi = INP_ALL_ITERATOR(&V_ripcbinfo, | |||||
INPLOOKUP_RLOCKPCB); | |||||
struct xinpgen xig; | struct xinpgen xig; | ||||
struct epoch_tracker et; | |||||
struct inpcb *inp; | struct inpcb *inp; | ||||
int error; | int error; | ||||
if (req->newptr != 0) | if (req->newptr != 0) | ||||
return (EPERM); | return (EPERM); | ||||
if (req->oldptr == 0) { | if (req->oldptr == 0) { | ||||
int n; | int n; | ||||
Show All 11 Lines | rip_pcblist(SYSCTL_HANDLER_ARGS) | ||||
xig.xig_len = sizeof xig; | xig.xig_len = sizeof xig; | ||||
xig.xig_count = V_ripcbinfo.ipi_count; | xig.xig_count = V_ripcbinfo.ipi_count; | ||||
xig.xig_gen = V_ripcbinfo.ipi_gencnt; | xig.xig_gen = V_ripcbinfo.ipi_gencnt; | ||||
xig.xig_sogen = so_gencnt; | xig.xig_sogen = so_gencnt; | ||||
error = SYSCTL_OUT(req, &xig, sizeof xig); | error = SYSCTL_OUT(req, &xig, sizeof xig); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NET_EPOCH_ENTER(et); | while ((inp = inp_next(&inpi)) != NULL) { | ||||
for (inp = CK_LIST_FIRST(V_ripcbinfo.ipi_listhead); | |||||
inp != NULL; | |||||
inp = CK_LIST_NEXT(inp, inp_list)) { | |||||
INP_RLOCK(inp); | |||||
if (inp->inp_gencnt <= xig.xig_gen && | if (inp->inp_gencnt <= xig.xig_gen && | ||||
cr_canseeinpcb(req->td->td_ucred, inp) == 0) { | cr_canseeinpcb(req->td->td_ucred, inp) == 0) { | ||||
struct xinpcb xi; | struct xinpcb xi; | ||||
in_pcbtoxinpcb(inp, &xi); | in_pcbtoxinpcb(inp, &xi); | ||||
INP_RUNLOCK(inp); | |||||
error = SYSCTL_OUT(req, &xi, sizeof xi); | error = SYSCTL_OUT(req, &xi, sizeof xi); | ||||
if (error) | if (error) { | ||||
break; | |||||
} else | |||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
break; | |||||
} | } | ||||
NET_EPOCH_EXIT(et); | } | ||||
} | |||||
if (!error) { | if (!error) { | ||||
/* | /* | ||||
* Give the user an updated idea of our state. If the | * Give the user an updated idea of our state. If the | ||||
* generation differs from what we told her before, she knows | * generation differs from what we told her before, she knows | ||||
* that something happened while we were processing this | * that something happened while we were processing this | ||||
* request, and it might be necessary to retry. | * request, and it might be necessary to retry. | ||||
*/ | */ | ||||
Show All 31 Lines |