/*
- * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
#include <pexpert/pexpert.h>
#include <net/if.h>
+#include <net/net_api_stats.h>
#include <net/route.h>
#define _IP_VHL
#include <netinet/in.h>
#include <netinet/in_systm.h>
+#include <netinet/in_tclass.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
* mbuf chain.
*/
void
-rip_input(m, iphlen)
- struct mbuf *m;
- int iphlen;
+rip_input(struct mbuf *m, int iphlen)
{
struct ip *ip = mtod(m, struct ip *);
struct inpcb *inp;
continue;
if (last) {
struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
-
+
skipit = 0;
-
+
#if NECP
- if (n && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0, &ip->ip_dst, &ip->ip_src, ifp, NULL)) {
+ if (n && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
+ &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
m_freem(n);
/* do not inject data to pcb */
skipit = 1;
int error = 0;
if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
(last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
- (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
+ (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
+ (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
ret = ip_savecontrol(last, &opts, ip, n);
if (ret != 0) {
m_freem(n);
} else {
if (error) {
/* should notify about lost packet */
- kprintf("rip_input can't append to socket\n");
+ ipstat.ips_raw_sappend_fail++;
}
}
opts = 0;
skipit = 0;
#if NECP
- if (last && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0, &ip->ip_dst, &ip->ip_src, ifp, NULL)) {
+ if (last && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
+ &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
m_freem(m);
OSAddAtomic(1, &ipstat.ips_delivered);
/* do not inject data to pcb */
if (last) {
if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
(last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
- (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
+ (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
+ (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
ret = ip_savecontrol(last, &opts, ip, m);
if (ret != 0) {
m_freem(m);
m_freem(opts);
- goto unlock;
+ goto unlock;
}
}
if (last->inp_flags & INP_STRIPHDR) {
(struct sockaddr *)&ripsrc, m, opts, NULL) != 0) {
sorwakeup(last->inp_socket);
} else {
- kprintf("rip_input(2) can't append to socket\n");
+ ipstat.ips_raw_sappend_fail++;
}
} else {
m_freem(m);
}
unlock:
/*
- * Keep the list locked because socket filter may force the socket lock
+ * Keep the list locked because socket filter may force the socket lock
* to be released when calling sbappendaddr() -- see rdar://7627704
*/
lck_rw_done(ripcbinfo.ipi_lock);
struct ip *ip;
struct inpcb *inp = sotoinpcb(so);
int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
- struct ip_out_args ipoa =
- { IFSCOPE_NONE, { 0 }, IPOAF_SELECT_SRCIF, 0 };
+ struct ip_out_args ipoa;
struct ip_moptions *imo;
int error = 0;
- mbuf_svc_class_t msc = MBUF_SC_UNSPEC;
+
+ bzero(&ipoa, sizeof(ipoa));
+ ipoa.ipoa_boundif = IFSCOPE_NONE;
+ ipoa.ipoa_flags = IPOAF_SELECT_SRCIF;
+
+ int sotc = SO_TC_UNSPEC;
+ int netsvctype = _NET_SERVICE_TYPE_UNSPEC;
+
if (control != NULL) {
- msc = mbuf_service_class_from_control(control);
+ sotc = so_tc_from_control(control, &netsvctype);
m_freem(control);
control = NULL;
}
+ if (sotc == SO_TC_UNSPEC) {
+ sotc = so->so_traffic_class;
+ netsvctype = so->so_netsvctype;
+ }
if (inp == NULL
#if NECP
ipoa.ipoa_flags |= IPOAF_NO_EXPENSIVE;
if (INP_AWDL_UNRESTRICTED(inp))
ipoa.ipoa_flags |= IPOAF_AWDL_UNRESTRICTED;
+ ipoa.ipoa_sotc = sotc;
+ ipoa.ipoa_netsvctype = netsvctype;
if (inp->inp_flowhash == 0)
inp->inp_flowhash = inp_calc_flowhash(inp);
m_freem(m);
return(EMSGSIZE);
}
- M_PREPEND(m, sizeof(struct ip), M_WAIT);
+ M_PREPEND(m, sizeof(struct ip), M_WAIT, 1);
if (m == NULL)
return ENOBUFS;
ip = mtod(m, struct ip *);
m_freem(m);
return EINVAL;
}
- if (ip->ip_id == 0)
+ if (ip->ip_id == 0 && !(rfc6864 && IP_OFF_IS_ATOMIC(ntohs(ip->ip_off))))
ip->ip_id = ip_randomid();
/* XXX prevent ip_output from overwriting header fields */
flags |= IP_RAWOUTPUT;
if (inp->inp_laddr.s_addr != INADDR_ANY)
ipoa.ipoa_flags |= IPOAF_BOUND_SRCADDR;
-
+
#if NECP
{
necp_kernel_policy_id policy_id;
- if (!necp_socket_is_allowed_to_send_recv_v4(inp, 0, 0, &ip->ip_src, &ip->ip_dst, NULL, &policy_id)) {
+ necp_kernel_policy_id skip_policy_id;
+ u_int32_t route_rule_id;
+
+ /*
+ * We need a route to perform NECP route rule checks
+ */
+ if (net_qos_policy_restricted != 0 &&
+ ROUTE_UNUSABLE(&inp->inp_route)) {
+ struct sockaddr_in to;
+ struct sockaddr_in from;
+ struct in_addr laddr = ip->ip_src;
+
+ ROUTE_RELEASE(&inp->inp_route);
+
+ bzero(&from, sizeof(struct sockaddr_in));
+ from.sin_family = AF_INET;
+ from.sin_len = sizeof(struct sockaddr_in);
+ from.sin_addr = laddr;
+
+ bzero(&to, sizeof(struct sockaddr_in));
+ to.sin_family = AF_INET;
+ to.sin_len = sizeof(struct sockaddr_in);
+ to.sin_addr.s_addr = ip->ip_dst.s_addr;
+
+ if ((error = in_pcbladdr(inp, (struct sockaddr *)&to,
+ &laddr, ipoa.ipoa_boundif, NULL, 1)) != 0) {
+ printf("%s in_pcbladdr(%p) error %d\n",
+ __func__, inp, error);
+ m_freem(m);
+ return (error);
+ }
+
+ inp_update_necp_policy(inp, (struct sockaddr *)&from,
+ (struct sockaddr *)&to, ipoa.ipoa_boundif);
+ inp->inp_policyresult.results.qos_marking_gencount = 0;
+ }
+
+ if (!necp_socket_is_allowed_to_send_recv_v4(inp, 0, 0,
+ &ip->ip_src, &ip->ip_dst, NULL, &policy_id, &route_rule_id, &skip_policy_id)) {
m_freem(m);
return(EHOSTUNREACH);
}
- necp_mark_packet_from_socket(m, inp, policy_id);
+ necp_mark_packet_from_socket(m, inp, policy_id, route_rule_id, skip_policy_id);
+
+ if (net_qos_policy_restricted != 0) {
+ struct ifnet *rt_ifp = NULL;
+
+ if (inp->inp_route.ro_rt != NULL)
+ rt_ifp = inp->inp_route.ro_rt->rt_ifp;
+
+ necp_socket_update_qos_marking(inp, inp->inp_route.ro_rt,
+ NULL, route_rule_id);
+ }
}
#endif /* NECP */
-
+ if ((so->so_flags1 & SOF1_QOSMARKING_ALLOWED))
+ ipoa.ipoa_flags |= IPOAF_QOSMARKING_ALLOWED;
+
#if IPSEC
if (inp->inp_sp != NULL && ipsec_setsocket(m, so) != 0) {
m_freem(m);
if (ROUTE_UNUSABLE(&inp->inp_route))
ROUTE_RELEASE(&inp->inp_route);
- set_packet_service_class(m, so, msc, 0);
+ set_packet_service_class(m, so, sotc, 0);
m->m_pkthdr.pkt_flowsrc = FLOWSRC_INPCB;
m->m_pkthdr.pkt_flowid = inp->inp_flowhash;
m->m_pkthdr.pkt_flags |= (PKTF_FLOW_ID | PKTF_FLOW_LOCALSRC |
PKTF_FLOW_RAWSOCK);
m->m_pkthdr.pkt_proto = inp->inp_ip_p;
+ m->m_pkthdr.tx_rawip_pid = so->last_pid;
+ m->m_pkthdr.tx_rawip_e_pid = so->e_pid;
+ if (so->so_flags & SOF_DELEGATED)
+ m->m_pkthdr.tx_rawip_e_pid = so->e_pid;
+ else
+ m->m_pkthdr.tx_rawip_e_pid = 0;
#if CONFIG_MACF_NET
mac_mbuf_label_associate_inpcb(inp, m);
* to pass the PCB cached route pointer directly to IP and
* the modules beneath it.
*/
+ // TODO: PASS DOWN ROUTE RULE ID
error = ip_output(m, inp->inp_options, &inp->inp_route, flags,
imo, &ipoa);
* route is unicast, update outif with that of the
* route interface used by IP.
*/
- if (rt != NULL && (outif = rt->rt_ifp) != inp->inp_last_outifp)
+ if (rt != NULL &&
+ (outif = rt->rt_ifp) != inp->inp_last_outifp) {
inp->inp_last_outifp = outif;
+ }
} else {
ROUTE_RELEASE(&inp->inp_route);
}
load_ipfw(void)
{
kern_return_t err;
-
+
ipfw_init();
-
+
#if DUMMYNET
if (!DUMMYNET_LOADED)
ip_dn_init();
#endif /* DUMMYNET */
err = 0;
-
+
return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
}
#endif /* IPFIREWALL */
* Raw IP socket option processing.
*/
int
-rip_ctloutput(so, sopt)
- struct socket *so;
- struct sockopt *sopt;
+rip_ctloutput(struct socket *so, struct sockopt *sopt)
{
struct inpcb *inp = sotoinpcb(so);
int error, optval;
rip_ctlinput(
int cmd,
struct sockaddr *sa,
- __unused void *vip)
+ __unused void *vip,
+ __unused struct ifnet *ifp)
{
- struct in_ifaddr *ia;
- struct ifnet *ifp;
- int err;
+ struct in_ifaddr *ia = NULL;
+ struct ifnet *iaifp = NULL;
+ int err = 0;
int flags, done = 0;
switch (cmd) {
lck_rw_done(in_ifaddr_rwlock);
flags = RTF_UP;
- ifp = ia->ia_ifa.ifa_ifp;
+ iaifp = ia->ia_ifa.ifa_ifp;
- if ((ifp->if_flags & IFF_LOOPBACK)
- || (ifp->if_flags & IFF_POINTOPOINT))
+ if ((iaifp->if_flags & IFF_LOOPBACK)
+ || (iaifp->if_flags & IFF_POINTOPOINT))
flags |= RTF_HOST;
err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
}
inp->inp_laddr = sin.sin_addr;
inp->inp_last_outifp = outif;
+
return (0);
}
if ((addr->sin_family != AF_INET) &&
(addr->sin_family != AF_IMPLINK))
return EAFNOSUPPORT;
+
+ if (!(so->so_flags1 & SOF1_CONNECT_COUNTED)) {
+ so->so_flags1 |= SOF1_CONNECT_COUNTED;
+ INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_inet_dgram_connected);
+ }
+
inp->inp_faddr = addr->sin_addr;
soisconnected(so);
}
/* note: rip_unlock is called from different protos instead of the generic socket_unlock,
- * it will handle the socket dealloc on last reference
+ * it will handle the socket dealloc on last reference
* */
int
rip_unlock(struct socket *so, int refcount, void *debug)
*/
gencnt = ripcbinfo.ipi_gencnt;
n = ripcbinfo.ipi_count;
-
+
bzero(&xig, sizeof(xig));
xig.xig_len = sizeof xig;
xig.xig_count = n;
*/
if (n == 0) {
lck_rw_done(ripcbinfo.ipi_lock);
- return 0;
+ return 0;
}
inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
lck_rw_done(ripcbinfo.ipi_lock);
return ENOMEM;
}
-
+
for (inp = ripcbinfo.ipi_listhead->lh_first, i = 0; inp && i < n;
inp = inp->inp_list.le_next) {
if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
+#if !CONFIG_EMBEDDED
static int
rip_pcblist64 SYSCTL_HANDLER_ARGS
CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
rip_pcblist64, "S,xinpcb64", "List of active raw IP sockets");
+#endif /* !CONFIG_EMBEDDED */
static int