/*
- * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
extern int esp_udp_encap_port;
#endif /* IPSEC */
+#if NECP
+#include <net/necp.h>
+#endif /* NECP */
+
#define DBG_LAYER_IN_BEG NETDBG_CODE(DBG_NETUDP, 0)
#define DBG_LAYER_IN_END NETDBG_CODE(DBG_NETUDP, 2)
#define DBG_LAYER_OUT_BEG NETDBG_CODE(DBG_NETUDP, 1)
static int udp_getstat SYSCTL_HANDLER_ARGS;
struct udpstat udpstat; /* from udp_var.h */
-SYSCTL_PROC(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD | CTLFLAG_LOCKED,
+SYSCTL_PROC(_net_inet_udp, UDPCTL_STATS, stats,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
0, 0, udp_getstat, "S,udpstat",
"UDP statistics (struct udpstat, netinet/udp_var.h)");
struct ifnet *ifp = m->m_pkthdr.rcvif;
boolean_t cell = IFNET_IS_CELLULAR(ifp);
boolean_t wifi = (!cell && IFNET_IS_WIFI(ifp));
+ boolean_t wired = (!wifi && IFNET_IS_WIRED(ifp));
bzero(&udp_in, sizeof (udp_in));
udp_in.sin_len = sizeof (struct sockaddr_in);
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif /* INET6 */
- if (inp_restricted(inp, ifp))
- continue;
-
- if (IFNET_IS_CELLULAR(ifp) &&
- (inp->inp_flags & INP_NO_IFT_CELLULAR))
+ if (inp_restricted_recv(inp, ifp))
continue;
if ((inp->inp_moptions == NULL) &&
reuse_sock = (inp->inp_socket->so_options &
(SO_REUSEPORT|SO_REUSEADDR));
-#if IPSEC
+#if NECP
skipit = 0;
- /* check AH/ESP integrity. */
- if (ipsec_bypass == 0 &&
- ipsec4_in_reject_so(m, inp->inp_socket)) {
- IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
+ if (!necp_socket_is_allowed_to_send_recv_v4(inp, uh->uh_dport, uh->uh_sport, &ip->ip_dst, &ip->ip_src, ifp, NULL)) {
/* do not inject data to pcb */
skipit = 1;
}
if (skipit == 0)
-#endif /*IPSEC*/
+#endif /* NECP */
{
struct mbuf *n = NULL;
IF_UDP_STATINC(ifp, cleanup);
goto bad;
}
-#if IPSEC
- if (ipsec_bypass == 0 && inp != NULL) {
- if (ipsec4_in_reject_so(m, inp->inp_socket)) {
- IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
- udp_unlock(inp->inp_socket, 1, 0);
- IF_UDP_STATINC(ifp, badipsec);
- goto bad;
- }
+#if NECP
+ if (!necp_socket_is_allowed_to_send_recv_v4(inp, uh->uh_dport, uh->uh_sport, &ip->ip_dst, &ip->ip_src, ifp, NULL)) {
+ udp_unlock(inp->inp_socket, 1, 0);
+ IF_UDP_STATINC(ifp, badipsec);
+ goto bad;
}
-#endif /* IPSEC */
+#endif /* NECP */
/*
* Construct sockaddr format source address.
append_sa = (struct sockaddr *)&udp_in;
}
if (nstat_collect) {
- INP_ADD_STAT(inp, cell, wifi, rxpackets, 1);
- INP_ADD_STAT(inp, cell, wifi, rxbytes, m->m_pkthdr.len);
+ INP_ADD_STAT(inp, cell, wifi, wired, rxpackets, 1);
+ INP_ADD_STAT(inp, cell, wifi, wired, rxbytes, m->m_pkthdr.len);
}
so_recv_data_stat(inp->inp_socket, m, 0);
if (sbappendaddr(&inp->inp_socket->so_rcv, append_sa,
struct mbuf *opts = 0;
boolean_t cell = IFNET_IS_CELLULAR(ifp);
boolean_t wifi = (!cell && IFNET_IS_WIFI(ifp));
+ boolean_t wired = (!wifi && IFNET_IS_WIRED(ifp));
int ret = 0;
#if CONFIG_MACF_NET
#endif /* INET6 */
append_sa = (struct sockaddr *)pudp_in;
if (nstat_collect) {
- INP_ADD_STAT(last, cell, wifi, rxpackets, 1);
- INP_ADD_STAT(last, cell, wifi, rxbytes, n->m_pkthdr.len);
+ INP_ADD_STAT(last, cell, wifi, wired, rxpackets, 1);
+ INP_ADD_STAT(last, cell, wifi, wired, rxbytes,
+ n->m_pkthdr.len);
}
so_recv_data_stat(last->inp_socket, n, 0);
m_adj(n, off);
}
SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist,
- CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist,
"S,xinpcb", "List of active UDP sockets");
}
SYSCTL_PROC(_net_inet_udp, OID_AUTO, pcblist64,
- CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist64,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist64,
"S,xinpcb64", "List of active UDP sockets");
}
SYSCTL_PROC(_net_inet_udp, OID_AUTO, pcblist_n,
- CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist_n,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist_n,
"S,xinpcb_n", "List of active UDP sockets");
__private_extern__ void
-udp_get_ports_used(uint32_t ifindex, int protocol, uint32_t wildcardok,
+udp_get_ports_used(uint32_t ifindex, int protocol, uint32_t flags,
bitstr_t *bitfield)
{
- inpcb_get_ports_used(ifindex, protocol, wildcardok, bitfield, &udbinfo);
+ inpcb_get_ports_used(ifindex, protocol, flags, bitfield, &udbinfo);
}
__private_extern__ uint32_t
struct ifnet *outif = NULL;
struct flowadv *adv = &ipoa.ipoa_flowadv;
mbuf_svc_class_t msc = MBUF_SC_UNSPEC;
- struct ifnet *origoutifp;
+ struct ifnet *origoutifp = NULL;
int flowadv = 0;
/* Enable flow advisory only when connected */
outif = inp->inp_boundifp;
ipoa.ipoa_boundif = outif->if_index;
}
- if (inp->inp_flags & INP_NO_IFT_CELLULAR)
+ if (INP_NO_CELLULAR(inp))
ipoa.ipoa_flags |= IPOAF_NO_CELLULAR;
+ if (INP_NO_EXPENSIVE(inp))
+ ipoa.ipoa_flags |= IPOAF_NO_EXPENSIVE;
+ if (INP_AWDL_UNRESTRICTED(inp))
+ ipoa.ipoa_flags |= IPOAF_AWDL_UNRESTRICTED;
soopts |= IP_OUTARGS;
/*
IFA_REMREF(&ia->ia_ifa);
}
- origoutifp = inp->inp_last_outifp;
-
/*
* IP_PKTINFO option check. If a temporary scope or src address
* is provided, use it for this packet only and make sure we forget
KERNEL_DEBUG(DBG_LAYER_OUT_END, ui->ui_dport, ui->ui_sport,
ui->ui_src.s_addr, ui->ui_dst.s_addr, ui->ui_ulen);
+
+#if NECP
+ {
+ necp_kernel_policy_id policy_id;
+ if (!necp_socket_is_allowed_to_send_recv_v4(inp, lport, fport, &laddr, &faddr, NULL, &policy_id)) {
+ error = EHOSTUNREACH;
+ goto abort;
+ }
+ necp_mark_packet_from_socket(m, inp, policy_id);
+ }
+#endif /* NECP */
+
#if IPSEC
- if (ipsec_bypass == 0 && ipsec_setsocket(m, inp->inp_socket) != 0) {
+ if (inp->inp_sp != NULL && ipsec_setsocket(m, inp->inp_socket) != 0) {
error = ENOBUFS;
goto abort;
}
IMO_REMREF(mopts);
if (error == 0 && nstat_collect) {
- boolean_t cell, wifi;
+ boolean_t cell, wifi, wired;
if (ro.ro_rt != NULL) {
cell = IFNET_IS_CELLULAR(ro.ro_rt->rt_ifp);
wifi = (!cell && IFNET_IS_WIFI(ro.ro_rt->rt_ifp));
+ wired = (!wifi && IFNET_IS_WIRED(ro.ro_rt->rt_ifp));
} else {
- cell = wifi = FALSE;
+ cell = wifi = wired = FALSE;
}
- INP_ADD_STAT(inp, cell, wifi, txpackets, 1);
- INP_ADD_STAT(inp, cell, wifi, txbytes, len);
+ INP_ADD_STAT(inp, cell, wifi, wired, txpackets, 1);
+ INP_ADD_STAT(inp, cell, wifi, wired, txbytes, len);
}
if (flowadv && (adv->code == FADV_FLOW_CONTROLLED ||
}
/*
- * If output interface was cellular, and this socket is denied
- * access to it, generate an event.
+ * If output interface was cellular/expensive, and this socket is
+ * denied access to it, generate an event.
*/
if (error != 0 && (ipoa.ipoa_retflags & IPOARF_IFDENIED) &&
- (inp->inp_flags & INP_NO_IFT_CELLULAR))
+ (INP_NO_CELLULAR(inp) || INP_NO_EXPENSIVE(inp)))
soevent(so, (SO_FILT_HINT_LOCKED|SO_FILT_HINT_IFDENIED));
release:
return (EAFNOSUPPORT);
inp = sotoinpcb(so);
- if (inp == NULL || (inp->inp_flags2 & INP2_WANT_FLOW_DIVERT))
+ if (inp == NULL
+#if NECP
+ || (necp_socket_should_use_flow_divert(inp))
+#endif /* NECP */
+ )
return (inp == NULL ? EINVAL : EPROTOTYPE);
error = in_pcbbind(inp, nam, p);
return (error);
int error;
inp = sotoinpcb(so);
- if (inp == NULL || (inp->inp_flags2 & INP2_WANT_FLOW_DIVERT))
+ if (inp == NULL
+#if NECP
+ || (necp_socket_should_use_flow_divert(inp))
+#endif /* NECP */
+ )
return (inp == NULL ? EINVAL : EPROTOTYPE);
if (inp->inp_faddr.s_addr != INADDR_ANY)
return (EISCONN);
VERIFY(dst_se->se_addr->sa_family == af);
VERIFY(src_se == NULL || src_se->se_addr->sa_family == af);
+#if NECP
+ inp_update_necp_policy(inp, src_se ? src_se->se_addr : NULL, dst_se ? dst_se->se_addr : NULL, ifscope);
+#endif /* NECP */
+
/* bind socket to the specified interface, if requested */
if (ifscope != IFSCOPE_NONE &&
(error = inp_bindif(inp, ifscope, NULL)) != 0)
panic("%s: so=%p null inp\n", __func__, so);
/* NOTREACHED */
}
+
+ /*
+ * If this is a socket that does not want to wakeup the device
+ * for it's traffic, the application might be waiting for
+ * close to complete before going to sleep. Send a notification
+ * for this kind of sockets
+ */
+ if (so->so_options & SO_NOWAKEFROMSLEEP)
+ socket_post_kev_msg_closed(so);
+
in_pcbdetach(inp);
inp->inp_state = INPCB_STATE_DEAD;
return (0);
struct inpcb *inp;
inp = sotoinpcb(so);
- if (inp == NULL || (inp->inp_flags2 & INP2_WANT_FLOW_DIVERT))
+ if (inp == NULL
+#if NECP
+ || (necp_socket_should_use_flow_divert(inp))
+#endif /* NECP */
+ )
return (inp == NULL ? EINVAL : EPROTOTYPE);
if (inp->inp_faddr.s_addr == INADDR_ANY)
return (ENOTCONN);
struct inpcb *inp;
inp = sotoinpcb(so);
- if (inp == NULL || (inp->inp_flags2 & INP2_WANT_FLOW_DIVERT)) {
+ if (inp == NULL
+#if NECP
+ || (necp_socket_should_use_flow_divert(inp))
+#endif /* NECP */
+ ) {
if (m != NULL)
m_freem(m);
if (control != NULL)