-/* $FreeBSD: src/sys/netinet6/ip6_forward.c,v 1.4.2.4 2001/07/03 11:01:53 ume Exp $ */
+/* $FreeBSD: src/sys/netinet6/ip6_forward.c,v 1.16 2002/10/16 02:25:05 sam Exp $ */
/* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */
/*
#endif
#include <netkey/key.h>
extern int ipsec_bypass;
+extern lck_mtx_t *sadb_mutex;
+extern lck_mtx_t *ip6_mutex;
#endif /* IPSEC */
#include <netinet6/ip6_fw.h>
*/
void
-ip6_forward(m, srcrt)
+ip6_forward(m, srcrt, locked)
struct mbuf *m;
int srcrt;
+ int locked;
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
struct sockaddr_in6 *dst;
#if IPSEC
struct secpolicy *sp = NULL;
#endif
+ struct timeval timenow;
+
+ getmicrotime(&timenow);
+
#if IPSEC
/*
* Don't increment ip6s_cantforward because this is the check
* before forwarding packet actually.
*/
- if (ipsec_bypass == 0 && ipsec6_in_reject(m, NULL)) {
- ipsec6stat.in_polvio++;
- m_freem(m);
- return;
+ if (ipsec_bypass == 0) {
+ lck_mtx_lock(sadb_mutex);
+ if (ipsec6_in_reject(m, NULL)) {
+ ipsec6stat.in_polvio++;
+ lck_mtx_unlock(sadb_mutex);
+ m_freem(m);
+ return;
+ }
+ lck_mtx_unlock(sadb_mutex);
}
#endif /*IPSEC*/
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
ip6stat.ip6s_cantforward++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
- if (ip6_log_time + ip6_log_interval < time_second) {
- ip6_log_time = time_second;
+ if (ip6_log_time + ip6_log_interval < timenow.tv_sec) {
+ ip6_log_time = timenow.tv_sec;
log(LOG_DEBUG,
"cannot forward "
"from %s to %s nxt %d received on %s\n",
if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(m, ICMP6_TIME_EXCEEDED,
ICMP6_TIME_EXCEED_TRANSIT, 0);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
return;
}
ip6->ip6_hlim -= IPV6_HLIMDEC;
#if IPSEC
if (ipsec_bypass != 0)
goto skip_ipsec;
-
+ lck_mtx_lock(sadb_mutex);
/* get a security policy for this packet */
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
&error);
m_freem(mcopy);
#endif
}
+ lck_mtx_unlock(sadb_mutex);
m_freem(m);
return;
}
m_freem(mcopy);
#endif
}
+ lck_mtx_unlock(sadb_mutex);
m_freem(m);
return;
case IPSEC_POLICY_NONE:
/* no need to do IPsec. */
key_freesp(sp);
+ lck_mtx_unlock(sadb_mutex);
goto skip_ipsec;
case IPSEC_POLICY_IPSEC:
m_freem(mcopy);
#endif
}
+ lck_mtx_unlock(sadb_mutex);
m_freem(m);
return;
}
/* should be panic ?? */
printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
key_freesp(sp);
+ lck_mtx_unlock(sadb_mutex);
goto skip_ipsec;
}
state.ro = NULL; /* update at ipsec6_output_tunnel() */
state.dst = NULL; /* update at ipsec6_output_tunnel() */
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
error = ipsec6_output_tunnel(&state, sp, 0);
+ if (locked) {
+ lck_mtx_unlock(sadb_mutex);
+ lck_mtx_lock(ip6_mutex);
+ lck_mtx_lock(sadb_mutex);
+ }
m = state.m;
key_freesp(sp);
break;
default:
printf("ip6_output (ipsec): error code %d\n", error);
- /*fall through*/
+ /* fall through */
case ENOENT:
/* don't show these error codes to the user */
break;
m_freem(mcopy);
#endif
}
+ lck_mtx_unlock(sadb_mutex);
m_freem(m);
return;
}
}
+ lck_mtx_unlock(sadb_mutex);
skip_ipsec:
#endif /* IPSEC */
ip6stat.ip6s_noroute++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
if (mcopy) {
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
}
m_freem(m);
return;
ip6stat.ip6s_noroute++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
if (mcopy) {
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
}
m_freem(m);
return;
* for the reason that the destination is beyond the scope of the
* source address, discard the packet and return an icmp6 destination
* unreachable error with Code 2 (beyond scope of source address).
- * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
+ * [draft-ietf-ipngwg-icmp-v3-02.txt, Section 3.1]
*/
if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
- if (ip6_log_time + ip6_log_interval < time_second) {
- ip6_log_time = time_second;
+ if (ip6_log_time + ip6_log_interval < timenow.tv_sec) {
+ ip6_log_time = timenow.tv_sec;
log(LOG_DEBUG,
"cannot forward "
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
ip6->ip6_nxt,
if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
}
- if (mcopy)
+ if (mcopy) {
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
+ }
m_freem(m);
return;
}
#endif
mtu = rt->rt_ifp->if_mtu;
-#if IPSEC_IPV6FWD
+#if IPSEC
/*
* When we do IPsec tunnel ingress, we need to play
* with if_mtu value (decrement IPsec header size
* case, as we have the outgoing interface for
* encapsulated packet as "rt->rt_ifp".
*/
+ lck_mtx_lock(sadb_mutex);
sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
IP_FORWARDING, &ipsecerror);
if (sp) {
if (ipsechdrsiz < mtu)
mtu -= ipsechdrsiz;
}
-
+ lck_mtx_unlock(sadb_mutex);
/*
* if mtu becomes less than minimum MTU,
* tell minimum MTU (and I'll need to fragment it).
if (mtu < IPV6_MMTU)
mtu = IPV6_MMTU;
#endif
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
}
m_freem(m);
return;
* type/code is based on suggestion by Rich Draves.
* not sure if it is the best pick.
*/
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADDR, 0);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
m_freem(m);
return;
}
if (ip6_fw_enable && ip6_fw_chk_ptr) {
u_short port = 0;
/* If ipfw says divert, we have to just drop packet */
- if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) {
+ if (ip6_fw_chk_ptr(&ip6, rt->rt_ifp, &port, &m)) {
m_freem(m);
goto freecopy;
}
#endif
{
printf("ip6_forward: outgoing interface is loopback. "
- "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
- ip6_sprintf(&ip6->ip6_src),
- ip6_sprintf(&ip6->ip6_dst),
- ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
- if_name(rt->rt_ifp));
+ "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
+ ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
+ if_name(rt->rt_ifp));
}
/* we can just use rcvif in forwarding. */
in6_clearscope(&ip6->ip6_dst);
#endif
- error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
+ error = nd6_output(rt->rt_ifp, origifp, m, dst, rt, locked);
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
ip6stat.ip6s_cantforward++;
code = ICMP6_DST_UNREACH_ADDR;
break;
}
+ if (locked)
+ lck_mtx_unlock(ip6_mutex);
icmp6_error(mcopy, type, code, 0);
+ if (locked)
+ lck_mtx_lock(ip6_mutex);
return;
freecopy: