/*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), return IPPROTO_DONE);
+ /* Expect 32-bit aligned data pointer on strict-align platforms */
+ MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
+
ifp = m->m_pkthdr.rcvif;
ip6 = mtod(m, struct ip6_hdr *);
-#if defined(NFAITH) && 0 < NFAITH
- if (faithprefix(&ip6->ip6_dst)) {
- /* XXX send icmp6 host/port unreach? */
- m_freem(m);
- return IPPROTO_DONE;
- }
-#endif
-
udpstat.udps_ipackets++;
plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
- uh = (struct udphdr *)((caddr_t)ip6 + off);
+ uh = (struct udphdr *)(void *)((caddr_t)ip6 + off);
ulen = ntohs((u_short)uh->uh_ulen);
if (plen != ulen) {
udpstat.udps_badlen++;
+
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->badlength, 1);
+
goto bad;
}
/* destination port of 0 is illegal, based on RFC768. */
- if (uh->uh_dport == 0)
+ if (uh->uh_dport == 0) {
+
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->port0, 1);
+
goto bad;
+ }
/*
* Checksum extended UDP header and data.
else {
if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
udpstat.udps_badsum++;
+
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->badchksum, 1);
+
goto bad;
}
}
if ((in6p->inp_vflag & INP_IPV6) == 0)
continue;
+ if (ip6_restrictrecvif && ifp != NULL &&
+ (ifp->if_eflags & IFEF_RESTRICTED_RECV) &&
+ !(in6p->in6p_flags & IN6P_RECV_ANYIF))
+ continue;
+
if (in_pcb_checkstate(in6p, WNT_ACQUIRE, 0) == WNT_STOPUSING)
continue;
- udp_lock(in6p->in6p_socket, 1, 0);
+ udp_lock(in6p->in6p_socket, 1, 0);
if (in_pcb_checkstate(in6p, WNT_RELEASE, 1) == WNT_STOPUSING) {
udp_unlock(in6p->in6p_socket, 1, 0);
struct sockaddr_in6 mcaddr;
int blocked;
- IM6O_LOCK(imo);
+ IM6O_LOCK(imo);
bzero(&mcaddr, sizeof(struct sockaddr_in6));
mcaddr.sin6_len = sizeof(struct sockaddr_in6);
mcaddr.sin6_family = AF_INET6;
blocked = im6o_mc_filter(imo, ifp,
(struct sockaddr *)&mcaddr,
(struct sockaddr *)&fromsa);
- IM6O_UNLOCK(imo);
+ IM6O_UNLOCK(imo);
if (blocked != MCAST_PASS) {
udp_unlock(in6p->in6p_socket, 1, 0);
continue;
*/
if (reuse_sock == 0 || ((m = n) == NULL))
break;
+
+ /*
+ * Expect 32-bit aligned data pointer on strict-align
+ * platforms.
+ */
+ MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
+
/*
* Recompute IP and UDP header pointers for new mbuf
*/
ip6 = mtod(m, struct ip6_hdr *);
- uh = (struct udphdr *)((caddr_t)ip6 + off);
+ uh = (struct udphdr *)(void *)((caddr_t)ip6 + off);
}
lck_rw_done(pcbinfo->mtx);
#ifndef __APPLE__
udpstat.udps_noportmcast++;
#endif
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->port_unreach, 1);
+
goto bad;
}
in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
&ip6->ip6_dst, uh->uh_dport, 1,
m->m_pkthdr.rcvif);
- if (in6p == 0) {
+ if (in6p == NULL) {
+
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->port_unreach, 1);
+
if (log_in_vain) {
char buf[INET6_ADDRSTRLEN];
#ifndef __APPLE__
udpstat.udps_noportmcast++;
#endif
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->badmcast, 1);
+
goto bad;
}
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
if (ipsec6_in_reject_so(m, in6p->in6p_socket)) {
IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
in_pcb_checkstate(in6p, WNT_RELEASE, 0);
+
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->badipsec, 1);
+
goto bad;
}
}
if (in_pcb_checkstate(in6p, WNT_RELEASE, 1) == WNT_STOPUSING) {
udp_unlock(in6p->in6p_socket, 1, 0);
+
+ if (ifp->if_udp_stat != NULL)
+ atomic_add_64(&ifp->if_udp_stat->cleanup, 1);
+
goto bad;
}
-
+
init_sin6(&udp_in6, m); /* general init */
udp_in6.sin6_port = uh->uh_sport;
- if ((in6p->in6p_flags & IN6P_CONTROLOPTS) != 0 ||
+ if ((in6p->in6p_flags & IN6P_CONTROLOPTS) != 0 ||
(in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
(in6p->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
ret = ip6_savecontrol(in6p, m, &opts);
* which may match an IPv4-mapped IPv6 address.
*/
inp->inp_ip_ttl = ip_defttl;
- nstat_udp_new_pcb(inp);
+ if (nstat_collect)
+ nstat_udp_new_pcb(inp);
return 0;
}
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
struct sockaddr_in6 *sin6_p;
- sin6_p = (struct sockaddr_in6 *)nam;
+ sin6_p = (struct sockaddr_in6 *)(void *)nam;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
inp->inp_vflag |= INP_IPV4;
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
struct sockaddr_in6 *sin6_p;
- sin6_p = (struct sockaddr_in6 *)nam;
+ sin6_p = (struct sockaddr_in6 *)(void *)nam;
if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
struct sockaddr_in sin;
inp->inp_vflag |= INP_IPV6;
}
soisconnected(so);
+ if (inp->inp_flowhash == 0)
+ inp->inp_flowhash = inp_calc_flowhash(inp);
}
return error;
}
return ENOTCONN;
in6_pcbdisconnect(inp);
+
+ /* reset flow-controlled state, just in case */
+ inp_reset_fc_state(inp);
+
inp->in6p_laddr = in6addr_any;
- inp->in6p_last_outif = 0;
+ inp->in6p_last_outifp = NULL;
so->so_state &= ~SS_ISCONNECTED; /* XXX */
return 0;
}
if (addr == 0)
hasv4addr = (inp->inp_vflag & INP_IPV4);
else {
- sin6 = (struct sockaddr_in6 *)addr;
+ sin6 = (struct sockaddr_in6 *)(void *)addr;
hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
? 1 : 0;
}