#if IPSEC
#include <netinet6/ipsec.h>
#include <netinet6/esp.h>
+#include <netkey/key.h>
extern int ipsec_bypass;
extern int esp_udp_encap_port;
#endif /* IPSEC */
goto bad;
}
- /* free the extra copy of mbuf or skipped by IPSec */
+ /* free the extra copy of mbuf or skipped by IPsec */
if (m != NULL) {
m_freem(m);
}
#if IPSEC
/*
* UDP to port 4500 with a payload where the first four bytes are
- * not zero is a UDP encapsulated IPSec packet. Packets where
+ * not zero is a UDP encapsulated IPsec packet. Packets where
* the payload is one byte and that byte is 0xFF are NAT keepalive
- * packets. Decapsulate the ESP packet and carry on with IPSec input
+ * packets. Decapsulate the ESP packet and carry on with IPsec input
* or discard the NAT keep-alive.
*/
if (ipsec_bypass == 0 && (esp_udp_encap_port & 0xFFFF) != 0 &&
- uh->uh_dport == ntohs((u_short)esp_udp_encap_port)) {
- int payload_len = len - sizeof(struct udphdr) > 4 ? 4 :
- len - sizeof(struct udphdr);
-
- if (m->m_len < iphlen + sizeof(struct udphdr) + payload_len) {
- if ((m = m_pullup(m, iphlen + sizeof(struct udphdr) +
- payload_len)) == NULL) {
- udpstat.udps_hdrops++;
+ (uh->uh_dport == ntohs((u_short)esp_udp_encap_port) ||
+ uh->uh_sport == ntohs((u_short)esp_udp_encap_port))) {
+ /*
+ * Check if ESP or keepalive:
+ * 1. If the destination port of the incoming packet is 4500.
+ * 2. If the source port of the incoming packet is 4500,
+ * then check the SADB to match IP address and port.
+ */
+ bool check_esp = true;
+ if (uh->uh_dport != ntohs((u_short)esp_udp_encap_port)) {
+ check_esp = key_checksa_present(AF_INET, (caddr_t)&ip->ip_dst,
+ (caddr_t)&ip->ip_src, uh->uh_dport,
+ uh->uh_sport);
+ }
+
+ if (check_esp) {
+ int payload_len = len - sizeof(struct udphdr) > 4 ? 4 :
+ len - sizeof(struct udphdr);
+
+ if (m->m_len < iphlen + sizeof(struct udphdr) + payload_len) {
+ if ((m = m_pullup(m, iphlen + sizeof(struct udphdr) +
+ payload_len)) == NULL) {
+ udpstat.udps_hdrops++;
+ KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END,
+ 0, 0, 0, 0, 0);
+ return;
+ }
+ /*
+ * Expect 32-bit aligned data pointer on strict-align
+ * platforms.
+ */
+ MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
+
+ ip = mtod(m, struct ip *);
+ uh = (struct udphdr *)(void *)((caddr_t)ip + iphlen);
+ }
+ /* Check for NAT keepalive packet */
+ if (payload_len == 1 && *(u_int8_t *)
+ ((caddr_t)uh + sizeof(struct udphdr)) == 0xFF) {
+ m_freem(m);
KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END,
0, 0, 0, 0, 0);
return;
+ } else if (payload_len == 4 && *(u_int32_t *)(void *)
+ ((caddr_t)uh + sizeof(struct udphdr)) != 0) {
+ /* UDP encapsulated IPsec packet to pass through NAT */
+ KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END,
+ 0, 0, 0, 0, 0);
+ /* preserve the udp header */
+ esp4_input(m, iphlen + sizeof(struct udphdr));
+ return;
}
- /*
- * Expect 32-bit aligned data pointer on strict-align
- * platforms.
- */
- MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
-
- ip = mtod(m, struct ip *);
- uh = (struct udphdr *)(void *)((caddr_t)ip + iphlen);
- }
- /* Check for NAT keepalive packet */
- if (payload_len == 1 && *(u_int8_t *)
- ((caddr_t)uh + sizeof(struct udphdr)) == 0xFF) {
- m_freem(m);
- KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END,
- 0, 0, 0, 0, 0);
- return;
- } else if (payload_len == 4 && *(u_int32_t *)(void *)
- ((caddr_t)uh + sizeof(struct udphdr)) != 0) {
- /* UDP encapsulated IPSec packet to pass through NAT */
- KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END,
- 0, 0, 0, 0, 0);
- /* preserve the udp header */
- esp4_input(m, iphlen + sizeof(struct udphdr));
- return;
}
}
#endif /* IPSEC */
int netsvctype = _NET_SERVICE_TYPE_UNSPEC;
struct ifnet *origoutifp = NULL;
int flowadv = 0;
+ int tos = IPTOS_UNSPEC;
/* Enable flow advisory only when connected */
flowadv = (so->so_state & SS_ISCONNECTED) ? 1 : 0;
#endif
if (control != NULL) {
+ tos = so_tos_from_control(control);
sotc = so_tc_from_control(control, &netsvctype);
VERIFY(outif == NULL);
error = udp_check_pktinfo(control, &outif, &pi_laddr);
if (INP_NO_EXPENSIVE(inp)) {
ipoa.ipoa_flags |= IPOAF_NO_EXPENSIVE;
}
+ if (INP_NO_CONSTRAINED(inp)) {
+ ipoa.ipoa_flags |= IPOAF_NO_CONSTRAINED;
+ }
if (INP_AWDL_UNRESTRICTED(inp)) {
ipoa.ipoa_flags |= IPOAF_AWDL_UNRESTRICTED;
}
}
((struct ip *)ui)->ip_len = sizeof(struct udpiphdr) + len;
((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
- ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
+ if (tos != IPTOS_UNSPEC) {
+ ((struct ip *)ui)->ip_tos = (uint8_t)(tos & IPTOS_MASK);
+ } else {
+ ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
+ }
udpstat.udps_opackets++;
KERNEL_DEBUG(DBG_LAYER_OUT_END, ui->ui_dport, ui->ui_sport,
VERIFY(inp->inp_sndinprog_cnt > 0);
if (--inp->inp_sndinprog_cnt == 0) {
inp->inp_flags &= ~(INP_FC_FEEDBACK);
+ if (inp->inp_sndingprog_waiters > 0) {
+ wakeup(&inp->inp_sndinprog_cnt);
+ }
}
/* Synchronize PCB cached route */
* denied access to it, generate an event.
*/
if (error != 0 && (ipoa.ipoa_retflags & IPOARF_IFDENIED) &&
- (INP_NO_CELLULAR(inp) || INP_NO_EXPENSIVE(inp))) {
+ (INP_NO_CELLULAR(inp) || INP_NO_EXPENSIVE(inp) || INP_NO_CONSTRAINED(inp))) {
soevent(so, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
}