/*
- * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <netkey/key.h>
#endif /* IPSEC */
+#include <os/log.h>
+
#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIP, 0)
#define DBG_LAYER_END NETDBG_CODE(DBG_NETIP, 2)
#define DBG_FNC_IP_INPUT NETDBG_CODE(DBG_NETIP, (2 << 8))
"Perform partial sum adjustment of trailing bytes at IP layer");
/*
- * XXX - Setting ip_checkinterface mostly implements the receive side of
- * the Strong ES model described in RFC 1122, but since the routing table
- * and transmit implementation do not implement the Strong ES model,
- * setting this to 1 results in an odd hybrid.
+ * ip_checkinterface controls the receive side of the models for multihoming
+ * that are discussed in RFC 1122.
+ *
+ * ip_checkinterface values are:
+ * IP_CHECKINTERFACE_WEAK_ES:
+ * This corresponds to the Weak End-System model where incoming packets from
+ * any interface are accepted provided the destination address of the incoming packet
+ * is assigned to some interface.
+ *
+ * IP_CHECKINTERFACE_HYBRID_ES:
+ * The Hybrid End-System model use the Strong End-System for tunnel interfaces
+ * (ipsec and utun) and the weak End-System model for other interfaces families.
+ * This prevents a rogue middle box to probe for signs of TCP connections
+ * that use the tunnel interface.
+ *
+ * IP_CHECKINTERFACE_STRONG_ES:
+ * The Strong model model requires the packet arrived on an interface that
+ * is assigned the destination address of the packet.
+ *
+ * Since the routing table and transmit implementation do not implement the Strong ES model,
+ * setting this to a value different from IP_CHECKINTERFACE_WEAK_ES may lead to unexpected results.
*
- * XXX - ip_checkinterface currently must be disabled if you use ipnat
+ * When forwarding is enabled, the system reverts to the Weak ES model as a router
+ * is expected by design to receive packets from several interfaces to the same address.
+ *
+ * XXX - ip_checkinterface currently must be set to IP_CHECKINTERFACE_WEAK_ES if you use ipnat
* to translate the destination address to another local interface.
*
- * XXX - ip_checkinterface must be disabled if you add IP aliases
+ * XXX - ip_checkinterface must be set to IP_CHECKINTERFACE_WEAK_ES if you add IP aliases
* to the loopback interface instead of the interface where the
* packets for those addresses are received.
*/
-static int ip_checkinterface = 0;
-SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW | CTLFLAG_LOCKED,
- &ip_checkinterface, 0, "Verify packet arrives on correct interface");
+#define IP_CHECKINTERFACE_WEAK_ES 0
+#define IP_CHECKINTERFACE_HYBRID_ES 1
+#define IP_CHECKINTERFACE_STRONG_ES 2
+
+static int ip_checkinterface = IP_CHECKINTERFACE_HYBRID_ES;
+
+static int sysctl_ip_checkinterface SYSCTL_HANDLER_ARGS;
+SYSCTL_PROC(_net_inet_ip, OID_AUTO, check_interface,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ 0, 0, sysctl_ip_checkinterface, "I", "Verify packet arrives on correct interface");
+
+#if (DEBUG || DEVELOPMENT)
+#define IP_CHECK_IF_DEBUG 1
+#else
+#define IP_CHECK_IF_DEBUG 0
+#endif /* (DEBUG || DEVELOPMENT) */
+static int ip_checkinterface_debug = IP_CHECK_IF_DEBUG;
+SYSCTL_INT(_net_inet_ip, OID_AUTO, checkinterface_debug, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &ip_checkinterface_debug, IP_CHECK_IF_DEBUG, "");
static int ip_chaining = 1;
SYSCTL_INT(_net_inet_ip, OID_AUTO, rx_chaining, CTLFLAG_RW | CTLFLAG_LOCKED,
} while (0)
#endif /* !__i386__ && !__x86_64__ */
+
+typedef enum ip_check_if_result {
+ IP_CHECK_IF_NONE = 0,
+ IP_CHECK_IF_OURS = 1,
+ IP_CHECK_IF_DROP = 2,
+ IP_CHECK_IF_FORWARD = 3
+} ip_check_if_result_t;
+
+static ip_check_if_result_t ip_input_check_interface(struct mbuf **, struct ip *, struct ifnet *);
+
/*
* GRE input handler function, settable via ip_gre_register_input() for PPTP.
*/
ipf_init();
+ PE_parse_boot_argn("ip_checkinterface", &i, sizeof(i));
+ switch (i) {
+ case IP_CHECKINTERFACE_WEAK_ES:
+ case IP_CHECKINTERFACE_HYBRID_ES:
+ case IP_CHECKINTERFACE_STRONG_ES:
+ ip_checkinterface = i;
+ break;
+ default:
+ break;
+ }
+
#if IPSEC
sadb_stat_mutex_grp_attr = lck_grp_attr_alloc_init();
sadb_stat_mutex_grp = lck_grp_alloc_init("sadb_stat",
/* Perform IP header alignment fixup (post-filters), if needed */
IP_HDR_ALIGNMENT_FIXUP(m, m->m_pkthdr.rcvif, return );
- /*
- * If there isn't a specific lock for the protocol
- * we're about to call, use the generic lock for AF_INET.
- * otherwise let the protocol deal with its own locking
- */
ip = mtod(m, struct ip *);
if (changed_header) {
ip->ip_off = ntohs(ip->ip_off);
}
+ /*
+ * If there isn't a specific lock for the protocol
+ * we're about to call, use the generic lock for AF_INET.
+ * otherwise let the protocol deal with its own locking
+ */
if ((pr_input = ip_protox[ip->ip_p]->pr_input) == NULL) {
m_freem(m);
} else if (!(ip_protox[ip->ip_p]->pr_flags & PR_PROTOLOCK)) {
ip = mtod(tmp_mbuf, struct ip *);
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
- while (tmp_mbuf) {
+ while (tmp_mbuf != NULL) {
nxt_mbuf = mbuf_nextpkt(tmp_mbuf);
mbuf_setnextpkt(tmp_mbuf, NULL);
{
struct mbuf *tmp_mbuf = m;
- while (tmp_mbuf) {
+ while (tmp_mbuf != NULL) {
ip_setdstifaddr_info(tmp_mbuf, ifindex, ia);
tmp_mbuf = mbuf_nextpkt(tmp_mbuf);
}
ip_input_adjust(m, ip, inifp);
}
- /* for consistency */
- m->m_pkthdr.pkt_proto = ip->ip_p;
-
/* for netstat route statistics */
src_ip = ip->ip_src;
len = m->m_pkthdr.len;
#endif
}
+/*
+ * Because the call to m_pullup() may freem the mbuf, the function frees the mbuf packet
+ * chain before it return IP_CHECK_IF_DROP
+ */
+static ip_check_if_result_t
+ip_input_check_interface(struct mbuf **mp, struct ip *ip, struct ifnet *inifp)
+{
+ struct mbuf *m = *mp;
+ struct in_ifaddr *ia = NULL;
+ struct in_ifaddr *best_ia = NULL;
+ struct ifnet *match_ifp = NULL;
+ ip_check_if_result_t result = IP_CHECK_IF_NONE;
+
+ /*
+ * Host broadcast and all network broadcast addresses are always a match
+ */
+ if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST ||
+ ip->ip_dst.s_addr == INADDR_ANY) {
+ ip_input_setdst_chain(m, inifp->if_index, NULL);
+ return IP_CHECK_IF_OURS;
+ }
+
+ /*
+ * Check for a match in the hash bucket.
+ */
+ lck_rw_lock_shared(in_ifaddr_rwlock);
+ TAILQ_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
+ if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) {
+ best_ia = ia;
+ match_ifp = best_ia->ia_ifp;
+
+ if (ia->ia_ifp == inifp || (inifp->if_flags & IFF_LOOPBACK) ||
+ (m->m_pkthdr.pkt_flags & PKTF_LOOP)) {
+ /*
+ * A locally originated packet or packet from the loopback
+ * interface is always an exact interface address match
+ */
+ match_ifp = inifp;
+ break;
+ }
+ /*
+ * Continue the loop in case there's a exact match with another
+ * interface
+ */
+ }
+ }
+ if (best_ia != NULL) {
+ if (match_ifp != inifp && ipforwarding == 0 &&
+ ((ip_checkinterface == IP_CHECKINTERFACE_HYBRID_ES &&
+ (match_ifp->if_family == IFNET_FAMILY_IPSEC ||
+ match_ifp->if_family == IFNET_FAMILY_UTUN)) ||
+ ip_checkinterface == IP_CHECKINTERFACE_STRONG_ES)) {
+ /*
+ * Drop when interface address check is strict and forwarding
+ * is disabled
+ */
+ result = IP_CHECK_IF_DROP;
+ } else {
+ result = IP_CHECK_IF_OURS;
+ ip_input_setdst_chain(m, 0, best_ia);
+ }
+ }
+ lck_rw_done(in_ifaddr_rwlock);
+
+ if (result == IP_CHECK_IF_NONE && (inifp->if_flags & IFF_BROADCAST)) {
+ /*
+ * Check for broadcast addresses.
+ *
+ * Only accept broadcast packets that arrive via the matching
+ * interface. Reception of forwarded directed broadcasts would be
+ * handled via ip_forward() and ether_frameout() with the loopback
+ * into the stack for SIMPLEX interfaces handled by ether_frameout().
+ */
+ struct ifaddr *ifa;
+
+ ifnet_lock_shared(inifp);
+ TAILQ_FOREACH(ifa, &inifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET) {
+ continue;
+ }
+ ia = ifatoia(ifa);
+ if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr ||
+ ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr) {
+ ip_input_setdst_chain(m, 0, ia);
+ result = IP_CHECK_IF_OURS;
+ match_ifp = inifp;
+ break;
+ }
+ }
+ ifnet_lock_done(inifp);
+ }
+
+ /* Allow DHCP/BootP responses through */
+ if (result == IP_CHECK_IF_NONE && (inifp->if_eflags & IFEF_AUTOCONFIGURING) &&
+ ip->ip_p == IPPROTO_UDP && (IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip)) {
+ struct udpiphdr *ui;
+
+ if (m->m_len < sizeof(struct udpiphdr)) {
+ if ((m = m_pullup(m, sizeof(struct udpiphdr))) == NULL) {
+ OSAddAtomic(1, &udpstat.udps_hdrops);
+ *mp = NULL;
+ return IP_CHECK_IF_DROP;
+ }
+ /*
+ * m_pullup can return a different mbuf
+ */
+ *mp = m;
+ ip = mtod(m, struct ip *);
+ }
+ ui = mtod(m, struct udpiphdr *);
+ if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) {
+ ASSERT(m->m_nextpkt == NULL);
+ ip_setdstifaddr_info(m, inifp->if_index, NULL);
+ result = IP_CHECK_IF_OURS;
+ match_ifp = inifp;
+ }
+ }
+
+ if (result == IP_CHECK_IF_NONE) {
+ if (ipforwarding == 0) {
+ result = IP_CHECK_IF_DROP;
+ } else {
+ result = IP_CHECK_IF_FORWARD;
+ ip_input_setdst_chain(m, inifp->if_index, NULL);
+ }
+ }
+
+ if (result == IP_CHECK_IF_OURS && match_ifp != inifp) {
+ ipstat.ips_rcv_if_weak_match++;
+
+ /* Logging is too noisy when forwarding is enabled */
+ if (ip_checkinterface_debug != 0 && ipforwarding == 0) {
+ char src_str[MAX_IPv4_STR_LEN];
+ char dst_str[MAX_IPv4_STR_LEN];
+
+ inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str));
+ inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str));
+ os_log_info(OS_LOG_DEFAULT,
+ "%s: weak ES interface match to %s for packet from %s to %s proto %u received via %s",
+ __func__, best_ia->ia_ifp->if_xname, src_str, dst_str, ip->ip_p, inifp->if_xname);
+ }
+ } else if (result == IP_CHECK_IF_DROP) {
+ if (ip_checkinterface_debug > 0) {
+ char src_str[MAX_IPv4_STR_LEN];
+ char dst_str[MAX_IPv4_STR_LEN];
+
+ inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str));
+ inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str));
+ os_log_info(OS_LOG_DEFAULT,
+ "%s: no interface match for packet from %s to %s proto %u received via %s",
+ __func__, src_str, dst_str, ip->ip_p, inifp->if_xname);
+ }
+ struct mbuf *tmp_mbuf = m;
+ while (tmp_mbuf != NULL) {
+ ipstat.ips_rcv_if_no_match++;
+ tmp_mbuf = tmp_mbuf->m_nextpkt;
+ }
+ m_freem_list(m);
+ *mp = NULL;
+ }
+
+ return result;
+}
+
static void
ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info,
int npkts_in_chain, int bytes_in_chain, struct ip_fw_in_args *args, int ours)
{
- unsigned int checkif;
struct mbuf *tmp_mbuf = NULL;
- struct in_ifaddr *ia = NULL;
- struct in_addr pkt_dst;
unsigned int hlen;
#if !IPFIREWALL
*/
tmp_mbuf = m;
if (TAILQ_EMPTY(&in_ifaddrhead)) {
- while (tmp_mbuf) {
+ while (tmp_mbuf != NULL) {
if (!(tmp_mbuf->m_flags & (M_MCAST | M_BCAST))) {
ip_setdstifaddr_info(tmp_mbuf, inifp->if_index,
NULL);
}
goto ours;
}
- /*
- * Cache the destination address of the packet; this may be
- * changed by use of 'ipfw fwd'.
- */
-#if IPFIREWALL
- pkt_dst = args->fwai_next_hop == NULL ?
- ip->ip_dst : args->fwai_next_hop->sin_addr;
-#else /* !IPFIREWALL */
- pkt_dst = ip->ip_dst;
-#endif /* !IPFIREWALL */
/*
* Enable a consistency check between the destination address
* to the loopback interface instead of the interface where
* the packets are received.
*/
- checkif = ip_checkinterface && (ipforwarding == 0) &&
- !(inifp->if_flags & IFF_LOOPBACK) &&
- !(m->m_pkthdr.pkt_flags & PKTF_LOOP)
-#if IPFIREWALL
- && (args->fwai_next_hop == NULL);
-#else /* !IPFIREWALL */
- ;
-#endif /* !IPFIREWALL */
+ if (!IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ ip_check_if_result_t ip_check_if_result = IP_CHECK_IF_NONE;
- /*
- * Check for exact addresses in the hash bucket.
- */
- lck_rw_lock_shared(in_ifaddr_rwlock);
- TAILQ_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
- /*
- * If the address matches, verify that the packet
- * arrived via the correct interface if checking is
- * enabled.
- */
- if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
- (!checkif || ia->ia_ifp == inifp)) {
- ip_input_setdst_chain(m, 0, ia);
- lck_rw_done(in_ifaddr_rwlock);
+ ip_check_if_result = ip_input_check_interface(&m, ip, inifp);
+ ASSERT(ip_check_if_result != IP_CHECK_IF_NONE);
+ if (ip_check_if_result == IP_CHECK_IF_OURS) {
goto ours;
+ } else if (ip_check_if_result == IP_CHECK_IF_DROP) {
+ return;
}
- }
- lck_rw_done(in_ifaddr_rwlock);
-
- /*
- * Check for broadcast addresses.
- *
- * Only accept broadcast packets that arrive via the matching
- * interface. Reception of forwarded directed broadcasts would be
- * handled via ip_forward() and ether_frameout() with the loopback
- * into the stack for SIMPLEX interfaces handled by ether_frameout().
- */
- if (inifp->if_flags & IFF_BROADCAST) {
- struct ifaddr *ifa;
-
- ifnet_lock_shared(inifp);
- TAILQ_FOREACH(ifa, &inifp->if_addrhead, ifa_link) {
- if (ifa->ifa_addr->sa_family != AF_INET) {
- continue;
- }
- ia = ifatoia(ifa);
- if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
- pkt_dst.s_addr || ia->ia_netbroadcast.s_addr ==
- pkt_dst.s_addr) {
- ip_input_setdst_chain(m, 0, ia);
- ifnet_lock_done(inifp);
- goto ours;
- }
- }
- ifnet_lock_done(inifp);
- }
-
- if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ } else {
struct in_multi *inm;
/*
* See if we belong to the destination multicast group on the
goto ours;
}
- if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST ||
- ip->ip_dst.s_addr == INADDR_ANY) {
- ip_input_setdst_chain(m, inifp->if_index, NULL);
- goto ours;
- }
-
- if (ip->ip_p == IPPROTO_UDP) {
- struct udpiphdr *ui;
- ui = mtod(m, struct udpiphdr *);
- if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) {
- goto ours;
- }
- }
-
tmp_mbuf = m;
struct mbuf *nxt_mbuf = NULL;
- while (tmp_mbuf) {
+ while (tmp_mbuf != NULL) {
nxt_mbuf = mbuf_nextpkt(tmp_mbuf);
/*
* Not for us; forward if possible and desirable.
KERNEL_DEBUG(DBG_LAYER_END, 0, 0, 0, 0, 0);
return;
ours:
+ ip = mtod(m, struct ip *); /* in case it changed */
/*
* If offset or IP_MF are set, must reassemble.
*/
ip_input(struct mbuf *m)
{
struct ip *ip;
- struct in_ifaddr *ia = NULL;
- unsigned int hlen, checkif;
+ unsigned int hlen;
u_short sum = 0;
- struct in_addr pkt_dst;
-#if IPFIREWALL
- int i;
- u_int32_t div_info = 0; /* packet divert/tee info */
-#endif
-#if IPFIREWALL || DUMMYNET
+#if DUMMYNET
struct ip_fw_args args;
struct m_tag *tag;
#endif
m_tag_delete(m, tag);
}
-#if DIAGNOSTIC
+#if DIAGNOSTIC
if (m == NULL || !(m->m_flags & M_PKTHDR)) {
panic("ip_input no HDR");
}
ip_input_adjust(m, ip, inifp);
}
- /* for consistency */
- m->m_pkthdr.pkt_proto = ip->ip_p;
-
#if DUMMYNET
check_with_pf:
#endif
goto ours;
}
- /*
- * Cache the destination address of the packet; this may be
- * changed by use of 'ipfw fwd'.
- */
-#if IPFIREWALL
- pkt_dst = args.fwa_next_hop == NULL ?
- ip->ip_dst : args.fwa_next_hop->sin_addr;
-#else /* !IPFIREWALL */
- pkt_dst = ip->ip_dst;
-#endif /* !IPFIREWALL */
-
/*
* Enable a consistency check between the destination address
* and the arrival interface for a unicast packet (the RFC 1122
* to the loopback interface instead of the interface where
* the packets are received.
*/
- checkif = ip_checkinterface && (ipforwarding == 0) &&
- !(inifp->if_flags & IFF_LOOPBACK) &&
- !(m->m_pkthdr.pkt_flags & PKTF_LOOP)
-#if IPFIREWALL
- && (args.fwa_next_hop == NULL);
-#else /* !IPFIREWALL */
- ;
-#endif /* !IPFIREWALL */
+ if (!IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ ip_check_if_result_t check_if_result = IP_CHECK_IF_NONE;
- /*
- * Check for exact addresses in the hash bucket.
- */
- lck_rw_lock_shared(in_ifaddr_rwlock);
- TAILQ_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
- /*
- * If the address matches, verify that the packet
- * arrived via the correct interface if checking is
- * enabled.
- */
- if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
- (!checkif || ia->ia_ifp == inifp)) {
- ip_setdstifaddr_info(m, 0, ia);
- lck_rw_done(in_ifaddr_rwlock);
+ check_if_result = ip_input_check_interface(&m, ip, inifp);
+ ASSERT(check_if_result != IP_CHECK_IF_NONE);
+ if (check_if_result == IP_CHECK_IF_OURS) {
goto ours;
+ } else if (check_if_result == IP_CHECK_IF_DROP) {
+ return;
}
- }
- lck_rw_done(in_ifaddr_rwlock);
-
- /*
- * Check for broadcast addresses.
- *
- * Only accept broadcast packets that arrive via the matching
- * interface. Reception of forwarded directed broadcasts would be
- * handled via ip_forward() and ether_frameout() with the loopback
- * into the stack for SIMPLEX interfaces handled by ether_frameout().
- */
- if (inifp->if_flags & IFF_BROADCAST) {
- struct ifaddr *ifa;
-
- ifnet_lock_shared(inifp);
- TAILQ_FOREACH(ifa, &inifp->if_addrhead, ifa_link) {
- if (ifa->ifa_addr->sa_family != AF_INET) {
- continue;
- }
- ia = ifatoia(ifa);
- if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
- pkt_dst.s_addr || ia->ia_netbroadcast.s_addr ==
- pkt_dst.s_addr) {
- ip_setdstifaddr_info(m, 0, ia);
- ifnet_lock_done(inifp);
- goto ours;
- }
- }
- ifnet_lock_done(inifp);
- }
-
- if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ } else {
struct in_multi *inm;
/*
* See if we belong to the destination multicast group on the
INM_REMREF(inm);
goto ours;
}
- if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST ||
- ip->ip_dst.s_addr == INADDR_ANY) {
- ip_setdstifaddr_info(m, inifp->if_index, NULL);
- goto ours;
- }
-
- /* Allow DHCP/BootP responses through */
- if ((inifp->if_eflags & IFEF_AUTOCONFIGURING) &&
- hlen == sizeof(struct ip) && ip->ip_p == IPPROTO_UDP) {
- struct udpiphdr *ui;
-
- if (m->m_len < sizeof(struct udpiphdr) &&
- (m = m_pullup(m, sizeof(struct udpiphdr))) == NULL) {
- OSAddAtomic(1, &udpstat.udps_hdrops);
- return;
- }
- ui = mtod(m, struct udpiphdr *);
- if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) {
- ip_setdstifaddr_info(m, inifp->if_index, NULL);
- goto ours;
- }
- ip = mtod(m, struct ip *); /* in case it changed */
- }
/*
* Not for us; forward if possible and desirable.
ASSERT(trailer >= 0);
if ((start != 0 && start != hlen) || trailer != 0) {
+ uint32_t datalen = ip->ip_len - hlen;
+
#if BYTE_ORDER != BIG_ENDIAN
if (start < hlen) {
HTONS(ip->ip_len);
}
#endif /* BYTE_ORDER != BIG_ENDIAN */
/* callee folds in sum */
- csum = m_adj_sum16(m, start, hlen,
- (ip->ip_len - hlen), csum);
+ csum = m_adj_sum16(m, start, hlen, datalen, csum);
if (hlen > start) {
swbytes += (hlen - start);
} else {
(m->m_pkthdr.pkt_flags & PKTF_LOOP)) {
/* loopback checksums are always OK */
m->m_pkthdr.csum_data = 0xffff;
- m->m_pkthdr.csum_flags &= ~CSUM_PARTIAL;
m->m_pkthdr.csum_flags =
CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
CSUM_IP_CHECKED | CSUM_IP_VALID;
struct in_addr *sin, dst;
u_int32_t ntime;
struct sockaddr_in ipaddr = {
- sizeof(ipaddr), AF_INET, 0, { 0 }, { 0, }
+ .sin_len = sizeof(ipaddr),
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr = { .s_addr = 0 },
+ .sin_zero = { 0, }
};
/* Expect 32-bit aligned data pointer on strict-align platforms */
#endif /* BYTE_ORDER != BIG_ENDIAN */
ip->ip_len -= sizeof(struct ip);
+
+ /*
+ * Given that we've just stripped IP options from the header,
+ * we need to adjust the start offset accordingly if this
+ * packet had gone thru partial checksum offload.
+ */
+ if ((m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PARTIAL)) ==
+ (CSUM_DATA_VALID | CSUM_PARTIAL)) {
+ if (m->m_pkthdr.csum_rx_start >= (sizeof(struct ip) + olen)) {
+ /* most common case */
+ m->m_pkthdr.csum_rx_start -= olen;
+ } else {
+ /* compute checksum in software instead */
+ m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID;
+ m->m_pkthdr.csum_data = 0;
+ ipstat.ips_adj_hwcsum_clr++;
+ }
+ }
}
u_char inetctlerrmap[PRC_NCMDS] = {
0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
EMSGSIZE, EHOSTUNREACH, 0, 0,
- 0, 0, 0, 0,
+ 0, 0, EHOSTUNREACH, 0,
ENOPROTOOPT, ECONNREFUSED
};
return SYSCTL_OUT(req, &net_perf, MIN(sizeof(net_perf), req->oldlen));
}
#endif /* (DEBUG || DEVELOPMENT) */
+
+static int
+sysctl_ip_checkinterface SYSCTL_HANDLER_ARGS
+{
+#pragma unused(arg1, arg2)
+ int error, i;
+
+ i = ip_checkinterface;
+ error = sysctl_handle_int(oidp, &i, 0, req);
+ if (error != 0 || req->newptr == USER_ADDR_NULL) {
+ return error;
+ }
+
+ switch (i) {
+ case IP_CHECKINTERFACE_WEAK_ES:
+ case IP_CHECKINTERFACE_HYBRID_ES:
+ case IP_CHECKINTERFACE_STRONG_ES:
+ if (ip_checkinterface != i) {
+ ip_checkinterface = i;
+ os_log(OS_LOG_DEFAULT, "%s: ip_checkinterface is now %d\n",
+ __func__, ip_checkinterface);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}