Hi,
As it was pointed out by dhill there are some rogue splnets in
the tcp_input that shouldn't be there really. The only reason
they're still there is to match overzealous splnets in bridge_
broadcast. bridge_ifenqueue is the only function call in there
that requires splnet protection since it's dealing with send
queues. Narrowing the range of the splnet protection allows us
to remove all splnet protection of the IPsec SPD and TDB code.
This as well removes the only pf_test call done under IPL_NET.
Below are essentially two diffs that are rather hard to separate.
I've tested the diff with the gif-to-ethernet IPsec bridge but
some additional IPsec and bridge testing won't hurt.
mpi@ has provided some feedback already, so I'm really looking
for OK's on this.
diff --git sys/net/if_bridge.c sys/net/if_bridge.c
index 41d7b67..0ca2710 100644
--- sys/net/if_bridge.c
+++ sys/net/if_bridge.c
@@ -969,12 +969,10 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct
sockaddr *sa,
return (ENOBUFS);
}
eh = mtod(m, struct ether_header *);
dst = (struct ether_addr *)&eh->ether_dhost[0];
- s = splnet();
-
/*
* If bridge is down, but original output interface is up,
* go ahead and send out that interface. Otherwise the packet
* is dropped below.
*/
@@ -1007,11 +1005,10 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct
sockaddr *sa,
*/
if ((mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED,
NULL)) != NULL) {
ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
m_freem(m);
- splx(s);
return (0);
}
#endif /* IPSEC */
bridge_span(sc, NULL, m);
@@ -1074,22 +1071,24 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct
sockaddr *sa,
m1->m_pkthdr.len = len;
}
mc = m1;
}
+ s = splnet();
error = bridge_ifenqueue(sc, dst_if, mc);
+ splx(s);
if (error)
continue;
}
if (!used)
m_freem(m);
- splx(s);
return (0);
}
sendunicast:
bridge_span(sc, NULL, m);
+ s = splnet();
if ((dst_if->if_flags & IFF_RUNNING) == 0) {
m_freem(m);
splx(s);
return (ENETDOWN);
}
@@ -1251,13 +1250,11 @@ bridgeintr_frame(struct bridge_softc *sc, struct mbuf
*m)
* If the packet is a multicast or broadcast OR if we don't
* know any better, forward it to all interfaces.
*/
if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
sc->sc_if.if_imcasts++;
- s = splnet();
bridge_broadcast(sc, src_if, &eh, m);
- splx(s);
return;
}
/*
* At this point, we're dealing with a unicast frame going to a
@@ -1496,13 +1493,11 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet
*ifp,
struct ether_header *eh, struct mbuf *m)
{
struct bridge_iflist *p;
struct mbuf *mc;
struct ifnet *dst_if;
- int len, used = 0;
-
- splassert(IPL_NET);
+ int len, s, used = 0;
TAILQ_FOREACH(p, &sc->sc_iflist, next) {
/*
* Don't retransmit out of the same interface where
* the packet was received from.
@@ -1587,11 +1582,13 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet
*ifp,
len += ETHER_VLAN_ENCAP_LEN;
#endif
if ((len - ETHER_HDR_LEN) > dst_if->if_mtu)
bridge_fragment(sc, dst_if, eh, mc);
else {
+ s = splnet();
bridge_ifenqueue(sc, dst_if, mc);
+ splx(s);
}
}
if (!used)
m_freem(m);
@@ -1643,11 +1640,11 @@ bridge_span(struct bridge_softc *sc, struct
ether_header *eh,
struct mbuf *morig)
{
struct bridge_iflist *p;
struct ifnet *ifp;
struct mbuf *mc, *m;
- int error;
+ int s, error;
if (TAILQ_EMPTY(&sc->sc_spanlist))
return;
m = m_copym2(morig, 0, M_COPYALL, M_NOWAIT);
@@ -1679,11 +1676,13 @@ bridge_span(struct bridge_softc *sc, struct
ether_header *eh,
if (mc == NULL) {
sc->sc_if.if_oerrors++;
continue;
}
+ s = splnet();
error = bridge_ifenqueue(sc, ifp, mc);
+ splx(s);
if (error)
continue;
}
m_freem(m);
}
diff --git sys/netinet/ip_input.c sys/netinet/ip_input.c
index 664afbf..221a6f4 100644
--- sys/netinet/ip_input.c
+++ sys/netinet/ip_input.c
@@ -243,11 +243,11 @@ ipv4_input(struct mbuf *m)
{
struct ip *ip;
int hlen, len;
in_addr_t pfrdr = 0;
#ifdef IPSEC
- int error, s;
+ int error;
struct tdb *tdb;
struct tdb_ident *tdbi;
struct m_tag *mtag;
#endif /* IPSEC */
@@ -452,20 +452,18 @@ ipv4_input(struct mbuf *m)
/*
* IPsec policy check for forwarded packets. Look at
* inner-most IPsec SA used.
*/
mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
- s = splnet();
if (mtag != NULL) {
tdbi = (struct tdb_ident *)(mtag + 1);
tdb = gettdb(tdbi->rdomain, tdbi->spi,
&tdbi->dst, tdbi->proto);
} else
tdb = NULL;
ipsp_spd_lookup(m, AF_INET, hlen, &error,
IPSP_DIRECTION_IN, tdb, NULL, 0);
- splx(s);
/* Error or otherwise drop-packet indication */
if (error) {
ipstat.ips_cantforward++;
goto bad;
@@ -495,11 +493,11 @@ ip_ours(struct mbuf *m)
struct ip *ip = mtod(m, struct ip *);
struct ipq *fp;
struct ipqent *ipqe;
int mff, hlen;
#ifdef IPSEC
- int error, s;
+ int error;
struct tdb *tdb;
struct tdb_ident *tdbi;
struct m_tag *mtag;
#endif /* IPSEC */
@@ -637,20 +635,18 @@ found:
* kinds of tunneling headers have been seen in-between the
* IPsec headers), and I don't think we lose much functionality
* that's needed in the real world (who uses bundles anyway ?).
*/
mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
- s = splnet();
if (mtag) {
tdbi = (struct tdb_ident *)(mtag + 1);
tdb = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst,
tdbi->proto);
} else
tdb = NULL;
ipsp_spd_lookup(m, AF_INET, hlen, &error, IPSP_DIRECTION_IN,
tdb, NULL, 0);
- splx(s);
/* Error or otherwise drop-packet indication. */
if (error) {
ipstat.ips_cantforward++;
goto bad;
diff --git sys/netinet/ip_output.c sys/netinet/ip_output.c
index e0e6b7d..088dd01 100644
--- sys/netinet/ip_output.c
+++ sys/netinet/ip_output.c
@@ -107,11 +107,10 @@ ip_output(struct mbuf *m0, ...)
struct tdb_ident *tdbi;
struct inpcb *inp;
struct tdb *tdb;
u_int32_t ipsecflowinfo;
- int s;
#if NPF > 0
struct ifnet *encif;
#endif
#endif /* IPSEC */
@@ -254,16 +253,10 @@ reroute:
#ifdef IPSEC
if (!ipsec_in_use && inp == NULL)
goto done_spd;
- /*
- * splnet is chosen over splsoftnet because we are not allowed to
- * lower the level, and udp_output calls us in splnet().
- */
- s = splnet();
-
/* Do we have any pending SAs to apply ? */
mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
if (mtag != NULL) {
#ifdef DIAGNOSTIC
if (mtag->m_tag_len != sizeof (struct tdb_ident))
@@ -280,12 +273,10 @@ reroute:
else
tdb = ipsp_spd_lookup(m, AF_INET, hlen, &error,
IPSP_DIRECTION_OUT, NULL, inp, ipsecflowinfo);
if (tdb == NULL) {
- splx(s);
-
if (error == 0) {
/*
* No IPsec processing required, we'll just send the
* packet out.
*/
@@ -316,21 +307,19 @@ reroute:
if (tdbi->spi == tdb->tdb_spi &&
tdbi->proto == tdb->tdb_sproto &&
tdbi->rdomain == tdb->tdb_rdomain &&
!bcmp(&tdbi->dst, &tdb->tdb_dst,
sizeof(union sockaddr_union))) {
- splx(s);
sproto = 0; /* mark as no-IPsec-needed */
goto done_spd;
}
}
/* We need to do IPsec */
bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
sspi = tdb->tdb_spi;
sproto = tdb->tdb_sproto;
- splx(s);
/*
* If it needs TCP/UDP hardware-checksumming, do the
* computation now.
*/
@@ -573,18 +562,15 @@ sendit:
#ifdef IPSEC
/*
* Check if the packet needs encapsulation.
*/
if (sproto != 0) {
- s = splnet();
-
tdb = gettdb(rtable_l2(m->m_pkthdr.rdomain),
sspi, &sdst, sproto);
if (tdb == NULL) {
DPRINTF(("ip_output: unknown TDB"));
error = EHOSTUNREACH;
- splx(s);
m_freem(m);
goto done;
}
/*
@@ -593,16 +579,14 @@ sendit:
#if NPF > 0
if ((encif = enc_getif(tdb->tdb_rdomain,
tdb->tdb_tap)) == NULL ||
pf_test(AF_INET, PF_OUT, encif, &m, NULL) != PF_PASS) {
error = EACCES;
- splx(s);
m_freem(m);
goto done;
}
if (m == NULL) {
- splx(s);
goto done;
}
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
/*
@@ -625,11 +609,10 @@ sendit:
transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET)
&&
(tdb->tdb_dst.sin.sin_addr.s_addr ==
ip->ip_dst.s_addr);
icmp_mtu = tdb->tdb_mtu;
- splx(s);
/* Find a host route to store the mtu in */
if (ro != NULL)
rt = ro->ro_rt;
/* but don't add a PMTU route for transport mode SAs */
@@ -665,11 +648,10 @@ sendit:
*/
m->m_flags &= ~(M_MCAST | M_BCAST);
/* Callee frees mbuf */
error = ipsp_process_packet(m, tdb, AF_INET, 0);
- splx(s);
return error; /* Nothing more to be done */
}
/*
* If we got here and IPsec crypto processing didn't happen, drop it.
diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c
index 4e39e7f..c44e796 100644
--- sys/netinet/tcp_input.c
+++ sys/netinet/tcp_input.c
@@ -376,11 +376,11 @@ tcp_input(struct mbuf *m, ...)
#endif /* INET6 */
#ifdef IPSEC
struct m_tag *mtag;
struct tdb_ident *tdbi;
struct tdb *tdb;
- int error, s;
+ int error;
#endif /* IPSEC */
int af;
#ifdef TCP_ECN
u_char iptos;
#endif
@@ -884,22 +884,20 @@ findpcb:
#endif
#ifdef IPSEC
/* Find most recent IPsec tag */
mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
- s = splnet();
if (mtag != NULL) {
tdbi = (struct tdb_ident *)(mtag + 1);
tdb = gettdb(tdbi->rdomain, tdbi->spi,
&tdbi->dst, tdbi->proto);
} else
tdb = NULL;
ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
tdb, inp, 0);
if (error) {
tcpstat.tcps_rcvnosec++;
- splx(s);
goto drop;
}
/* Latch SA */
if (inp->inp_tdb_in != tdb) {
@@ -907,11 +905,10 @@ findpcb:
tdb_add_inp(tdb, inp, 1);
if (inp->inp_ipo == NULL) {
inp->inp_ipo = ipsec_add_policy(inp, af,
IPSP_DIRECTION_OUT);
if (inp->inp_ipo == NULL) {
- splx(s);
goto drop;
}
}
if (inp->inp_ipo->ipo_dstid == NULL &&
tdb->tdb_srcid != NULL) {
@@ -934,11 +931,10 @@ findpcb:
TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in, inp,
inp_tdb_in_next);
inp->inp_tdb_in = NULL;
}
}
- splx(s);
#endif /* IPSEC */
/*
* Segment received on connection.
* Reset idle time and keep-alive timer.
@@ -967,11 +963,11 @@ findpcb:
if (opti.ts_present && opti.ts_ecr) {
int rtt_test;
/* subtract out the tcp timestamp modulator */
opti.ts_ecr -= tp->ts_modulate;
-
+
/* make sure ts_ecr is sensible */
rtt_test = tcp_now - opti.ts_ecr;
if (rtt_test < 0 || rtt_test > TCP_RTT_MAX)
opti.ts_ecr = 0;
}
diff --git sys/netinet/udp_usrreq.c sys/netinet/udp_usrreq.c
index 2b5623f..b1f2c5c 100644
--- sys/netinet/udp_usrreq.c
+++ sys/netinet/udp_usrreq.c
@@ -176,11 +176,11 @@ udp_input(struct mbuf *m, ...)
#endif /* INET6 */
#ifdef IPSEC
struct m_tag *mtag;
struct tdb_ident *tdbi;
struct tdb *tdb;
- int error, s;
+ int error;
u_int32_t ipsecflowinfo = 0;
#endif /* IPSEC */
va_start(ap, m);
iphlen = va_arg(ap, int);
@@ -598,22 +598,20 @@ udp_input(struct mbuf *m, ...)
m->m_pkthdr.pf.statekey = NULL;
#endif
#ifdef IPSEC
mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
- s = splnet();
if (mtag != NULL) {
tdbi = (struct tdb_ident *)(mtag + 1);
tdb = gettdb(tdbi->rdomain, tdbi->spi,
&tdbi->dst, tdbi->proto);
} else
tdb = NULL;
ipsp_spd_lookup(m, srcsa.sa.sa_family, iphlen, &error,
IPSP_DIRECTION_IN, tdb, inp, 0);
if (error) {
udpstat.udps_nosec++;
- splx(s);
goto bad;
}
/* Latch SA only if the socket is connected */
if (inp->inp_tdb_in != tdb &&
@@ -622,11 +620,10 @@ udp_input(struct mbuf *m, ...)
tdb_add_inp(tdb, inp, 1);
if (inp->inp_ipo == NULL) {
inp->inp_ipo = ipsec_add_policy(inp,
srcsa.sa.sa_family, IPSP_DIRECTION_OUT);
if (inp->inp_ipo == NULL) {
- splx(s);
goto bad;
}
}
if (inp->inp_ipo->ipo_dstid == NULL &&
tdb->tdb_srcid != NULL) {
@@ -653,11 +650,10 @@ udp_input(struct mbuf *m, ...)
}
/* create ipsec options while we know that tdb cannot be modified */
if (tdb)
ipsecflowinfo = tdb->tdb_spi;
- splx(s);
#endif /*IPSEC */
opts = NULL;
#ifdef INET6
if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS ||
diff --git sys/netinet6/ip6_forward.c sys/netinet6/ip6_forward.c
index 4e2e459..0444352 100644
--- sys/netinet6/ip6_forward.c
+++ sys/netinet6/ip6_forward.c
@@ -98,11 +98,10 @@ ip6_forward(struct mbuf *m, int srcrt)
struct m_tag *mtag;
union sockaddr_union sdst;
struct tdb_ident *tdbi;
u_int32_t sspi;
struct tdb *tdb;
- int s;
#if NPF > 0
struct ifnet *encif;
#endif
#endif /* IPSEC */
u_int rtableid = 0;
@@ -146,12 +145,10 @@ reroute:
#ifdef IPSEC
if (!ipsec_in_use)
goto done_spd;
- s = splnet();
-
/*
* Check if there was an outgoing SA bound to the flow
* from a transport protocol.
*/
@@ -172,12 +169,10 @@ reroute:
} else
tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
&error, IPSP_DIRECTION_OUT, NULL, NULL, 0);
if (tdb == NULL) {
- splx(s);
-
if (error == 0) {
/*
* No IPsec processing required, we'll just send the
* packet out.
*/
@@ -207,21 +202,19 @@ reroute:
if (tdbi->spi == tdb->tdb_spi &&
tdbi->proto == tdb->tdb_sproto &&
tdbi->rdomain == tdb->tdb_rdomain &&
!bcmp(&tdbi->dst, &tdb->tdb_dst,
sizeof(union sockaddr_union))) {
- splx(s);
sproto = 0; /* mark as no-IPsec-needed */
goto done_spd;
}
}
/* We need to do IPsec */
bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
sspi = tdb->tdb_spi;
sproto = tdb->tdb_sproto;
- splx(s);
}
/* Fall through to the routing/multicast handling code */
done_spd:
#endif /* IPSEC */
@@ -335,34 +328,28 @@ reroute:
* ipsp_process_packet will never come back to here.
* XXX ipsp_process_packet() calls ip6_output(), and there'll be no
* PMTU notification. is it okay?
*/
if (sproto != 0) {
- s = splnet();
-
tdb = gettdb(rtable_l2(m->m_pkthdr.rdomain),
sspi, &sdst, sproto);
if (tdb == NULL) {
- splx(s);
error = EHOSTUNREACH;
m_freem(m);
goto senderr; /*XXX*/
}
#if NPF > 0
if ((encif = enc_getif(tdb->tdb_rdomain,
tdb->tdb_tap)) == NULL ||
pf_test(AF_INET6, PF_FWD, encif, &m, NULL) != PF_PASS) {
- splx(s);
error = EHOSTUNREACH;
m_freem(m);
goto senderr;
}
- if (m == NULL) {
- splx(s);
+ if (m == NULL)
goto senderr;
- }
ip6 = mtod(m, struct ip6_hdr *);
/*
* PF_TAG_REROUTE handling or not...
* Packet is entering IPsec so the routing is
* already overruled by the IPsec policy.
@@ -374,11 +361,10 @@ reroute:
m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
/* Callee frees mbuf */
error = ipsp_process_packet(m, tdb, AF_INET6, 0);
- splx(s);
m_freem(mcopy);
goto freert;
}
#endif /* IPSEC */
diff --git sys/netinet6/ip6_output.c sys/netinet6/ip6_output.c
index d9a11ce..88ccf90 100644
--- sys/netinet6/ip6_output.c
+++ sys/netinet6/ip6_output.c
@@ -171,11 +171,10 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro,
struct m_tag *mtag;
union sockaddr_union sdst;
struct tdb_ident *tdbi;
u_int32_t sspi;
struct tdb *tdb;
- int s;
#if NPF > 0
struct ifnet *encif;
#endif
#endif /* IPSEC */
@@ -214,16 +213,10 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro,
#ifdef IPSEC
if (!ipsec_in_use && !inp)
goto done_spd;
/*
- * splnet is chosen over splsoftnet because we are not allowed to
- * lower the level, and udp6_output calls us in splnet(). XXX check
- */
- s = splnet();
-
- /*
* Check if there was an outgoing SA bound to the flow
* from a transport protocol.
*/
ip6 = mtod(m, struct ip6_hdr *);
@@ -243,12 +236,10 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro,
} else
tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
&error, IPSP_DIRECTION_OUT, NULL, inp, 0);
if (tdb == NULL) {
- splx(s);
-
if (error == 0) {
/*
* No IPsec processing required, we'll just send the
* packet out.
*/
@@ -278,21 +269,19 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro,
if (tdbi->spi == tdb->tdb_spi &&
tdbi->proto == tdb->tdb_sproto &&
tdbi->rdomain == tdb->tdb_rdomain &&
!bcmp(&tdbi->dst, &tdb->tdb_dst,
sizeof(union sockaddr_union))) {
- splx(s);
sproto = 0; /* mark as no-IPsec-needed */
goto done_spd;
}
}
/* We need to do IPsec */
bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
sspi = tdb->tdb_spi;
sproto = tdb->tdb_sproto;
- splx(s);
}
/* Fall through to the routing/multicast handling code */
done_spd:
#endif /* IPSEC */
@@ -495,39 +484,33 @@ reroute:
/*
* Check if the packet needs encapsulation.
* ipsp_process_packet will never come back to here.
*/
if (sproto != 0) {
- s = splnet();
-
/*
* XXX what should we do if ip6_hlim == 0 and the
* packet gets tunneled?
*/
tdb = gettdb(rtable_l2(m->m_pkthdr.rdomain),
sspi, &sdst, sproto);
if (tdb == NULL) {
- splx(s);
error = EHOSTUNREACH;
m_freem(m);
goto done;
}
#if NPF > 0
if ((encif = enc_getif(tdb->tdb_rdomain,
tdb->tdb_tap)) == NULL ||
pf_test(AF_INET6, PF_OUT, encif, &m, NULL) != PF_PASS) {
- splx(s);
error = EHOSTUNREACH;
m_freem(m);
goto done;
}
- if (m == NULL) {
- splx(s);
+ if (m == NULL)
goto done;
- }
ip6 = mtod(m, struct ip6_hdr *);
/*
* PF_TAG_REROUTE handling or not...
* Packet is entering IPsec so the routing is
* already overruled by the IPsec policy.
@@ -545,11 +528,10 @@ reroute:
* packet just because ip6_dst is different from what tdb has.
* XXX
*/
error = ipsp_process_packet(m, tdb, AF_INET6,
exthdrs.ip6e_rthdr ? 1 : 0);
- splx(s);
return error; /* Nothing more to be done */
}
#endif /* IPSEC */