]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/raw_ip.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / netinet / raw_ip.c
CommitLineData
1c79356b 1/*
a39ff7e2 2 * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39037602 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39037602 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1982, 1986, 1988, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
61 */
2d21ac55
A
62/*
63 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
64 * support for mandatory and extensible security protections. This notice
65 * is included in support of clause 2.2 (b) of the Apple Public License,
66 * Version 2.0.
67 */
1c79356b
A
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/kernel.h>
72#include <sys/malloc.h>
73#include <sys/mbuf.h>
316670eb 74#include <sys/mcache.h>
1c79356b 75#include <sys/proc.h>
91447636 76#include <sys/domain.h>
1c79356b
A
77#include <sys/protosw.h>
78#include <sys/socket.h>
79#include <sys/socketvar.h>
80#include <sys/sysctl.h>
2d21ac55
A
81#include <libkern/OSAtomic.h>
82#include <kern/zalloc.h>
1c79356b 83
2d21ac55 84#include <pexpert/pexpert.h>
1c79356b
A
85
86#include <net/if.h>
5ba3f43e 87#include <net/net_api_stats.h>
1c79356b
A
88#include <net/route.h>
89
90#define _IP_VHL
91#include <netinet/in.h>
92#include <netinet/in_systm.h>
39037602 93#include <netinet/in_tclass.h>
1c79356b 94#include <netinet/ip.h>
1c79356b
A
95#include <netinet/in_pcb.h>
96#include <netinet/in_var.h>
97#include <netinet/ip_var.h>
1c79356b 98
b0d623f7
A
99#if INET6
100#include <netinet6/in6_pcb.h>
101#endif /* INET6 */
102
1c79356b
A
103#include <netinet/ip_fw.h>
104
105#if IPSEC
106#include <netinet6/ipsec.h>
107#endif /*IPSEC*/
108
1c79356b
A
109#if DUMMYNET
110#include <netinet/ip_dummynet.h>
111#endif
9bccf70c 112
2d21ac55
A
113#if CONFIG_MACF_NET
114#include <security/mac_framework.h>
115#endif /* MAC_NET */
116
117int load_ipfw(void);
118int rip_detach(struct socket *);
119int rip_abort(struct socket *);
120int rip_disconnect(struct socket *);
121int rip_bind(struct socket *, struct sockaddr *, struct proc *);
122int rip_connect(struct socket *, struct sockaddr *, struct proc *);
123int rip_shutdown(struct socket *);
1c79356b 124
9bccf70c
A
125struct inpcbhead ripcb;
126struct inpcbinfo ripcbinfo;
1c79356b 127
91447636 128/* control hooks for ipfw and dummynet */
4a3eedf9 129#if IPFIREWALL
91447636 130ip_fw_ctl_t *ip_fw_ctl_ptr;
316670eb 131#endif /* IPFIREWALL */
91447636
A
132#if DUMMYNET
133ip_dn_ctl_t *ip_dn_ctl_ptr;
134#endif /* DUMMYNET */
135
1c79356b
A
136/*
137 * Nominal space allocated to a raw ip socket.
138 */
139#define RIPSNDQ 8192
140#define RIPRCVQ 8192
141
142/*
143 * Raw interface to IP protocol.
144 */
145
146/*
147 * Initialize raw connection block q.
148 */
149void
39236c6e 150rip_init(struct protosw *pp, struct domain *dp)
1c79356b 151{
39236c6e
A
152#pragma unused(dp)
153 static int rip_initialized = 0;
154 struct inpcbinfo *pcbinfo;
155
156 VERIFY((pp->pr_flags & (PR_INITIALIZED|PR_ATTACHED)) == PR_ATTACHED);
157
158 if (rip_initialized)
159 return;
160 rip_initialized = 1;
91447636 161
1c79356b 162 LIST_INIT(&ripcb);
39236c6e 163 ripcbinfo.ipi_listhead = &ripcb;
1c79356b
A
164 /*
165 * XXX We don't use the hash list for raw IP, but it's easier
166 * to allocate a one entry hash list than it is to check all
39236c6e 167 * over the place for ipi_hashbase == NULL.
1c79356b 168 */
39236c6e
A
169 ripcbinfo.ipi_hashbase = hashinit(1, M_PCB, &ripcbinfo.ipi_hashmask);
170 ripcbinfo.ipi_porthashbase = hashinit(1, M_PCB, &ripcbinfo.ipi_porthashmask);
1c79356b 171
39236c6e
A
172 ripcbinfo.ipi_zone = zinit(sizeof(struct inpcb),
173 (4096 * sizeof(struct inpcb)), 4096, "ripzone");
1c79356b 174
91447636
A
175 pcbinfo = &ripcbinfo;
176 /*
177 * allocate lock group attribute and group for udp pcb mutexes
178 */
39236c6e
A
179 pcbinfo->ipi_lock_grp_attr = lck_grp_attr_alloc_init();
180 pcbinfo->ipi_lock_grp = lck_grp_alloc_init("ripcb", pcbinfo->ipi_lock_grp_attr);
91447636 181
91447636
A
182 /*
183 * allocate the lock attribute for udp pcb mutexes
184 */
39236c6e
A
185 pcbinfo->ipi_lock_attr = lck_attr_alloc_init();
186 if ((pcbinfo->ipi_lock = lck_rw_alloc_init(pcbinfo->ipi_lock_grp,
187 pcbinfo->ipi_lock_attr)) == NULL) {
188 panic("%s: unable to allocate PCB lock\n", __func__);
189 /* NOTREACHED */
190 }
91447636 191
39236c6e 192 in_pcbinfo_attach(&ripcbinfo);
1c79356b
A
193}
194
2d21ac55 195static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET , 0, {0}, {0,0,0,0,0,0,0,0,} };
1c79356b
A
196/*
197 * Setup generic address and protocol structures
198 * for raw_input routine, then pass them along with
199 * mbuf chain.
200 */
201void
39037602 202rip_input(struct mbuf *m, int iphlen)
1c79356b 203{
39236c6e
A
204 struct ip *ip = mtod(m, struct ip *);
205 struct inpcb *inp;
1c79356b
A
206 struct inpcb *last = 0;
207 struct mbuf *opts = 0;
6d2010ae 208 int skipit = 0, ret = 0;
39236c6e 209 struct ifnet *ifp = m->m_pkthdr.rcvif;
1c79356b 210
316670eb
A
211 /* Expect 32-bit aligned data pointer on strict-align platforms */
212 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
213
1c79356b 214 ripsrc.sin_addr = ip->ip_src;
39236c6e 215 lck_rw_lock_shared(ripcbinfo.ipi_lock);
1c79356b 216 LIST_FOREACH(inp, &ripcb, inp_list) {
9bccf70c
A
217#if INET6
218 if ((inp->inp_vflag & INP_IPV4) == 0)
1c79356b 219 continue;
9bccf70c
A
220#endif
221 if (inp->inp_ip_p && (inp->inp_ip_p != ip->ip_p))
1c79356b
A
222 continue;
223 if (inp->inp_laddr.s_addr &&
224 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
225 continue;
226 if (inp->inp_faddr.s_addr &&
227 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
228 continue;
fe8ab488 229 if (inp_restricted_recv(inp, ifp))
39236c6e 230 continue;
1c79356b
A
231 if (last) {
232 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
3e170ce0 233
6d2010ae 234 skipit = 0;
3e170ce0 235
fe8ab488 236#if NECP
3e170ce0 237 if (n && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
d9a64523 238 &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
fe8ab488
A
239 m_freem(n);
240 /* do not inject data to pcb */
241 skipit = 1;
242 }
243#endif /* NECP */
2d21ac55
A
244#if CONFIG_MACF_NET
245 if (n && skipit == 0) {
246 if (mac_inpcb_check_deliver(last, n, AF_INET,
6d2010ae
A
247 SOCK_RAW) != 0) {
248 m_freem(n);
2d21ac55 249 skipit = 1;
6d2010ae 250 }
2d21ac55
A
251 }
252#endif
91447636
A
253 if (n && skipit == 0) {
254 int error = 0;
6d2010ae
A
255 if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
256 (last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
d9a64523
A
257 (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
258 (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
6d2010ae
A
259 ret = ip_savecontrol(last, &opts, ip, n);
260 if (ret != 0) {
261 m_freem(n);
262 m_freem(opts);
263 last = inp;
264 continue;
265 }
266 }
9bccf70c
A
267 if (last->inp_flags & INP_STRIPHDR) {
268 n->m_len -= iphlen;
269 n->m_pkthdr.len -= iphlen;
270 n->m_data += iphlen;
271 }
6d2010ae 272 so_recv_data_stat(last->inp_socket, m, 0);
1c79356b
A
273 if (sbappendaddr(&last->inp_socket->so_rcv,
274 (struct sockaddr *)&ripsrc, n,
91447636 275 opts, &error) != 0) {
9bccf70c 276 sorwakeup(last->inp_socket);
6d2010ae 277 } else {
91447636
A
278 if (error) {
279 /* should notify about lost packet */
39037602 280 ipstat.ips_raw_sappend_fail++;
91447636
A
281 }
282 }
1c79356b
A
283 opts = 0;
284 }
285 }
286 last = inp;
287 }
6d2010ae
A
288
289 skipit = 0;
fe8ab488 290#if NECP
3e170ce0 291 if (last && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
d9a64523 292 &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
fe8ab488
A
293 m_freem(m);
294 OSAddAtomic(1, &ipstat.ips_delivered);
295 /* do not inject data to pcb */
296 skipit = 1;
297 }
298#endif /* NECP */
2d21ac55
A
299#if CONFIG_MACF_NET
300 if (last && skipit == 0) {
6d2010ae 301 if (mac_inpcb_check_deliver(last, m, AF_INET, SOCK_RAW) != 0) {
2d21ac55 302 skipit = 1;
6d2010ae
A
303 m_freem(m);
304 }
2d21ac55
A
305 }
306#endif
91447636
A
307 if (skipit == 0) {
308 if (last) {
6d2010ae
A
309 if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
310 (last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
d9a64523
A
311 (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
312 (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
6d2010ae
A
313 ret = ip_savecontrol(last, &opts, ip, m);
314 if (ret != 0) {
315 m_freem(m);
316 m_freem(opts);
39037602 317 goto unlock;
6d2010ae
A
318 }
319 }
91447636
A
320 if (last->inp_flags & INP_STRIPHDR) {
321 m->m_len -= iphlen;
322 m->m_pkthdr.len -= iphlen;
323 m->m_data += iphlen;
324 }
6d2010ae 325 so_recv_data_stat(last->inp_socket, m, 0);
91447636
A
326 if (sbappendaddr(&last->inp_socket->so_rcv,
327 (struct sockaddr *)&ripsrc, m, opts, NULL) != 0) {
328 sorwakeup(last->inp_socket);
329 } else {
39037602 330 ipstat.ips_raw_sappend_fail++;
91447636
A
331 }
332 } else {
1c79356b 333 m_freem(m);
b0d623f7
A
334 OSAddAtomic(1, &ipstat.ips_noproto);
335 OSAddAtomic(-1, &ipstat.ips_delivered);
91447636 336 }
9bccf70c 337 }
6d2010ae
A
338unlock:
339 /*
39037602 340 * Keep the list locked because socket filter may force the socket lock
6d2010ae
A
341 * to be released when calling sbappendaddr() -- see rdar://7627704
342 */
39236c6e 343 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b
A
344}
345
346/*
347 * Generate IP header and pass packet to ip_output.
348 * Tack on options user may have setup with control call.
349 */
350int
d41d1dae
A
351rip_output(
352 struct mbuf *m,
353 struct socket *so,
354 u_int32_t dst,
355 struct mbuf *control)
1c79356b 356{
39236c6e
A
357 struct ip *ip;
358 struct inpcb *inp = sotoinpcb(so);
1c79356b 359 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
a39ff7e2 360 struct ip_out_args ipoa;
6d2010ae 361 struct ip_moptions *imo;
d1ecb069 362 int error = 0;
a39ff7e2
A
363
364 bzero(&ipoa, sizeof(ipoa));
365 ipoa.ipoa_boundif = IFSCOPE_NONE;
366 ipoa.ipoa_flags = IPOAF_SELECT_SRCIF;
367
39037602
A
368 int sotc = SO_TC_UNSPEC;
369 int netsvctype = _NET_SERVICE_TYPE_UNSPEC;
c910b4d9 370
a39ff7e2 371
d41d1dae 372 if (control != NULL) {
39037602 373 sotc = so_tc_from_control(control, &netsvctype);
d41d1dae
A
374
375 m_freem(control);
39236c6e
A
376 control = NULL;
377 }
39037602
A
378 if (sotc == SO_TC_UNSPEC) {
379 sotc = so->so_traffic_class;
380 netsvctype = so->so_netsvctype;
381 }
39236c6e 382
fe8ab488
A
383 if (inp == NULL
384#if NECP
385 || (necp_socket_should_use_flow_divert(inp))
386#endif /* NECP */
387 ) {
39236c6e
A
388 if (m != NULL)
389 m_freem(m);
390 VERIFY(control == NULL);
391 return (inp == NULL ? EINVAL : EPROTOTYPE);
d41d1dae 392 }
316670eb 393
c910b4d9 394 flags |= IP_OUTARGS;
316670eb
A
395 /* If socket was bound to an ifindex, tell ip_output about it */
396 if (inp->inp_flags & INP_BOUND_IF) {
397 ipoa.ipoa_boundif = inp->inp_boundifp->if_index;
398 ipoa.ipoa_flags |= IPOAF_BOUND_IF;
399 }
fe8ab488 400 if (INP_NO_CELLULAR(inp))
316670eb 401 ipoa.ipoa_flags |= IPOAF_NO_CELLULAR;
fe8ab488
A
402 if (INP_NO_EXPENSIVE(inp))
403 ipoa.ipoa_flags |= IPOAF_NO_EXPENSIVE;
404 if (INP_AWDL_UNRESTRICTED(inp))
405 ipoa.ipoa_flags |= IPOAF_AWDL_UNRESTRICTED;
39037602
A
406 ipoa.ipoa_sotc = sotc;
407 ipoa.ipoa_netsvctype = netsvctype;
316670eb
A
408
409 if (inp->inp_flowhash == 0)
410 inp->inp_flowhash = inp_calc_flowhash(inp);
1c79356b
A
411
412 /*
413 * If the user handed us a complete IP packet, use it.
414 * Otherwise, allocate an mbuf for a header and fill it in.
415 */
416 if ((inp->inp_flags & INP_HDRINCL) == 0) {
417 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
418 m_freem(m);
419 return(EMSGSIZE);
420 }
3e170ce0 421 M_PREPEND(m, sizeof(struct ip), M_WAIT, 1);
b0d623f7
A
422 if (m == NULL)
423 return ENOBUFS;
1c79356b 424 ip = mtod(m, struct ip *);
9bccf70c 425 ip->ip_tos = inp->inp_ip_tos;
1c79356b
A
426 ip->ip_off = 0;
427 ip->ip_p = inp->inp_ip_p;
428 ip->ip_len = m->m_pkthdr.len;
429 ip->ip_src = inp->inp_laddr;
430 ip->ip_dst.s_addr = dst;
9bccf70c 431 ip->ip_ttl = inp->inp_ip_ttl;
1c79356b
A
432 } else {
433 if (m->m_pkthdr.len > IP_MAXPACKET) {
434 m_freem(m);
435 return(EMSGSIZE);
436 }
437 ip = mtod(m, struct ip *);
438 /* don't allow both user specified and setsockopt options,
439 and don't allow packet length sizes that will crash */
9bccf70c 440 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
1c79356b
A
441 && inp->inp_options)
442 || (ip->ip_len > m->m_pkthdr.len)
443 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
444 m_freem(m);
445 return EINVAL;
446 }
5ba3f43e 447 if (ip->ip_id == 0 && !(rfc6864 && IP_OFF_IS_ATOMIC(ntohs(ip->ip_off))))
9bccf70c 448 ip->ip_id = ip_randomid();
1c79356b
A
449 /* XXX prevent ip_output from overwriting header fields */
450 flags |= IP_RAWOUTPUT;
b0d623f7 451 OSAddAtomic(1, &ipstat.ips_rawout);
1c79356b
A
452 }
453
316670eb
A
454 if (inp->inp_laddr.s_addr != INADDR_ANY)
455 ipoa.ipoa_flags |= IPOAF_BOUND_SRCADDR;
3e170ce0 456
fe8ab488
A
457#if NECP
458 {
459 necp_kernel_policy_id policy_id;
d9a64523 460 necp_kernel_policy_id skip_policy_id;
3e170ce0 461 u_int32_t route_rule_id;
39037602
A
462
463 /*
464 * We need a route to perform NECP route rule checks
465 */
466 if (net_qos_policy_restricted != 0 &&
467 ROUTE_UNUSABLE(&inp->inp_route)) {
468 struct sockaddr_in to;
469 struct sockaddr_in from;
470 struct in_addr laddr = ip->ip_src;
471
472 ROUTE_RELEASE(&inp->inp_route);
473
474 bzero(&from, sizeof(struct sockaddr_in));
475 from.sin_family = AF_INET;
476 from.sin_len = sizeof(struct sockaddr_in);
477 from.sin_addr = laddr;
478
479 bzero(&to, sizeof(struct sockaddr_in));
480 to.sin_family = AF_INET;
481 to.sin_len = sizeof(struct sockaddr_in);
482 to.sin_addr.s_addr = ip->ip_dst.s_addr;
483
484 if ((error = in_pcbladdr(inp, (struct sockaddr *)&to,
485 &laddr, ipoa.ipoa_boundif, NULL, 1)) != 0) {
486 printf("%s in_pcbladdr(%p) error %d\n",
487 __func__, inp, error);
488 m_freem(m);
489 return (error);
490 }
491
492 inp_update_necp_policy(inp, (struct sockaddr *)&from,
493 (struct sockaddr *)&to, ipoa.ipoa_boundif);
494 inp->inp_policyresult.results.qos_marking_gencount = 0;
495 }
496
3e170ce0 497 if (!necp_socket_is_allowed_to_send_recv_v4(inp, 0, 0,
d9a64523 498 &ip->ip_src, &ip->ip_dst, NULL, &policy_id, &route_rule_id, &skip_policy_id)) {
fe8ab488
A
499 m_freem(m);
500 return(EHOSTUNREACH);
501 }
316670eb 502
d9a64523 503 necp_mark_packet_from_socket(m, inp, policy_id, route_rule_id, skip_policy_id);
39037602
A
504
505 if (net_qos_policy_restricted != 0) {
506 struct ifnet *rt_ifp = NULL;
507
508 if (inp->inp_route.ro_rt != NULL)
509 rt_ifp = inp->inp_route.ro_rt->rt_ifp;
510
39037602
A
511 necp_socket_update_qos_marking(inp, inp->inp_route.ro_rt,
512 NULL, route_rule_id);
513 }
fe8ab488
A
514 }
515#endif /* NECP */
39037602
A
516 if ((so->so_flags1 & SOF1_QOSMARKING_ALLOWED))
517 ipoa.ipoa_flags |= IPOAF_QOSMARKING_ALLOWED;
3e170ce0 518
1c79356b 519#if IPSEC
fe8ab488 520 if (inp->inp_sp != NULL && ipsec_setsocket(m, so) != 0) {
9bccf70c
A
521 m_freem(m);
522 return ENOBUFS;
523 }
1c79356b
A
524#endif /*IPSEC*/
525
39236c6e
A
526 if (ROUTE_UNUSABLE(&inp->inp_route))
527 ROUTE_RELEASE(&inp->inp_route);
91447636 528
39037602 529 set_packet_service_class(m, so, sotc, 0);
39236c6e
A
530 m->m_pkthdr.pkt_flowsrc = FLOWSRC_INPCB;
531 m->m_pkthdr.pkt_flowid = inp->inp_flowhash;
532 m->m_pkthdr.pkt_flags |= (PKTF_FLOW_ID | PKTF_FLOW_LOCALSRC |
533 PKTF_FLOW_RAWSOCK);
534 m->m_pkthdr.pkt_proto = inp->inp_ip_p;
d9a64523
A
535 m->m_pkthdr.tx_rawip_pid = so->last_pid;
536 m->m_pkthdr.tx_rawip_e_pid = so->e_pid;
537 if (so->so_flags & SOF_DELEGATED)
538 m->m_pkthdr.tx_rawip_e_pid = so->e_pid;
539 else
540 m->m_pkthdr.tx_rawip_e_pid = 0;
d1ecb069 541
2d21ac55
A
542#if CONFIG_MACF_NET
543 mac_mbuf_label_associate_inpcb(inp, m);
544#endif
545
6d2010ae
A
546 imo = inp->inp_moptions;
547 if (imo != NULL)
548 IMO_ADDREF(imo);
b0d623f7
A
549 /*
550 * The domain lock is held across ip_output, so it is okay
551 * to pass the PCB cached route pointer directly to IP and
552 * the modules beneath it.
553 */
3e170ce0 554 // TODO: PASS DOWN ROUTE RULE ID
d1ecb069 555 error = ip_output(m, inp->inp_options, &inp->inp_route, flags,
6d2010ae 556 imo, &ipoa);
d1ecb069 557
6d2010ae
A
558 if (imo != NULL)
559 IMO_REMREF(imo);
560
561 if (inp->inp_route.ro_rt != NULL) {
562 struct rtentry *rt = inp->inp_route.ro_rt;
316670eb 563 struct ifnet *outif;
6d2010ae
A
564
565 if ((rt->rt_flags & (RTF_MULTICAST|RTF_BROADCAST)) ||
566 inp->inp_socket == NULL ||
567 !(inp->inp_socket->so_state & SS_ISCONNECTED)) {
568 rt = NULL; /* unusable */
569 }
570 /*
571 * Always discard the cached route for unconnected
572 * socket or if it is a multicast route.
573 */
39236c6e
A
574 if (rt == NULL)
575 ROUTE_RELEASE(&inp->inp_route);
576
6d2010ae
A
577 /*
578 * If this is a connected socket and the destination
316670eb
A
579 * route is unicast, update outif with that of the
580 * route interface used by IP.
6d2010ae 581 */
5ba3f43e
A
582 if (rt != NULL &&
583 (outif = rt->rt_ifp) != inp->inp_last_outifp) {
316670eb 584 inp->inp_last_outifp = outif;
5ba3f43e 585 }
39236c6e
A
586 } else {
587 ROUTE_RELEASE(&inp->inp_route);
d1ecb069 588 }
d1ecb069 589
39236c6e 590 /*
fe8ab488
A
591 * If output interface was cellular/expensive, and this socket is
592 * denied access to it, generate an event.
39236c6e
A
593 */
594 if (error != 0 && (ipoa.ipoa_retflags & IPOARF_IFDENIED) &&
fe8ab488 595 (INP_NO_CELLULAR(inp) || INP_NO_EXPENSIVE(inp)))
39236c6e
A
596 soevent(so, (SO_FILT_HINT_LOCKED|SO_FILT_HINT_IFDENIED));
597
d1ecb069 598 return (error);
1c79356b
A
599}
600
2d21ac55
A
601#if IPFIREWALL
602int
603load_ipfw(void)
55e303ae
A
604{
605 kern_return_t err;
39037602 606
91447636 607 ipfw_init();
39037602 608
91447636
A
609#if DUMMYNET
610 if (!DUMMYNET_LOADED)
611 ip_dn_init();
612#endif /* DUMMYNET */
613 err = 0;
39037602 614
55e303ae
A
615 return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
616}
2d21ac55 617#endif /* IPFIREWALL */
55e303ae 618
1c79356b
A
619/*
620 * Raw IP socket option processing.
621 */
622int
39037602 623rip_ctloutput(struct socket *so, struct sockopt *sopt)
1c79356b
A
624{
625 struct inpcb *inp = sotoinpcb(so);
626 int error, optval;
627
316670eb
A
628 /* Allow <SOL_SOCKET,SO_FLUSH> at this level */
629 if (sopt->sopt_level != IPPROTO_IP &&
630 !(sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_FLUSH))
1c79356b
A
631 return (EINVAL);
632
633 error = 0;
634
635 switch (sopt->sopt_dir) {
636 case SOPT_GET:
637 switch (sopt->sopt_name) {
638 case IP_HDRINCL:
639 optval = inp->inp_flags & INP_HDRINCL;
640 error = sooptcopyout(sopt, &optval, sizeof optval);
641 break;
642
316670eb
A
643 case IP_STRIPHDR:
644 optval = inp->inp_flags & INP_STRIPHDR;
645 error = sooptcopyout(sopt, &optval, sizeof optval);
646 break;
1c79356b 647
2d21ac55 648#if IPFIREWALL
9bccf70c 649 case IP_FW_ADD:
1c79356b 650 case IP_FW_GET:
9bccf70c
A
651 case IP_OLD_FW_ADD:
652 case IP_OLD_FW_GET:
1c79356b 653 if (ip_fw_ctl_ptr == 0)
55e303ae
A
654 error = load_ipfw();
655 if (ip_fw_ctl_ptr && error == 0)
1c79356b 656 error = ip_fw_ctl_ptr(sopt);
55e303ae
A
657 else
658 error = ENOPROTOOPT;
1c79356b 659 break;
b0d623f7 660#endif /* IPFIREWALL */
1c79356b 661
1c79356b
A
662#if DUMMYNET
663 case IP_DUMMYNET_GET:
316670eb
A
664 if (!DUMMYNET_LOADED)
665 ip_dn_init();
91447636 666 if (DUMMYNET_LOADED)
1c79356b 667 error = ip_dn_ctl_ptr(sopt);
91447636
A
668 else
669 error = ENOPROTOOPT;
1c79356b
A
670 break ;
671#endif /* DUMMYNET */
1c79356b 672
1c79356b
A
673 default:
674 error = ip_ctloutput(so, sopt);
675 break;
676 }
677 break;
678
679 case SOPT_SET:
680 switch (sopt->sopt_name) {
681 case IP_HDRINCL:
682 error = sooptcopyin(sopt, &optval, sizeof optval,
683 sizeof optval);
684 if (error)
685 break;
686 if (optval)
687 inp->inp_flags |= INP_HDRINCL;
688 else
689 inp->inp_flags &= ~INP_HDRINCL;
690 break;
691
316670eb
A
692 case IP_STRIPHDR:
693 error = sooptcopyin(sopt, &optval, sizeof optval,
694 sizeof optval);
695 if (error)
696 break;
697 if (optval)
698 inp->inp_flags |= INP_STRIPHDR;
699 else
700 inp->inp_flags &= ~INP_STRIPHDR;
701 break;
1c79356b 702
2d21ac55 703#if IPFIREWALL
1c79356b
A
704 case IP_FW_ADD:
705 case IP_FW_DEL:
706 case IP_FW_FLUSH:
707 case IP_FW_ZERO:
9bccf70c
A
708 case IP_FW_RESETLOG:
709 case IP_OLD_FW_ADD:
710 case IP_OLD_FW_DEL:
711 case IP_OLD_FW_FLUSH:
712 case IP_OLD_FW_ZERO:
713 case IP_OLD_FW_RESETLOG:
1c79356b 714 if (ip_fw_ctl_ptr == 0)
55e303ae
A
715 error = load_ipfw();
716 if (ip_fw_ctl_ptr && error == 0)
1c79356b 717 error = ip_fw_ctl_ptr(sopt);
55e303ae
A
718 else
719 error = ENOPROTOOPT;
1c79356b 720 break;
2d21ac55 721#endif /* IPFIREWALL */
1c79356b 722
1c79356b
A
723#if DUMMYNET
724 case IP_DUMMYNET_CONFIGURE:
725 case IP_DUMMYNET_DEL:
726 case IP_DUMMYNET_FLUSH:
316670eb
A
727 if (!DUMMYNET_LOADED)
728 ip_dn_init();
91447636 729 if (DUMMYNET_LOADED)
1c79356b 730 error = ip_dn_ctl_ptr(sopt);
91447636
A
731 else
732 error = ENOPROTOOPT ;
1c79356b
A
733 break ;
734#endif
1c79356b 735
316670eb
A
736 case SO_FLUSH:
737 if ((error = sooptcopyin(sopt, &optval, sizeof (optval),
738 sizeof (optval))) != 0)
739 break;
740
741 error = inp_flush(inp, optval);
742 break;
743
1c79356b
A
744 default:
745 error = ip_ctloutput(so, sopt);
746 break;
747 }
748 break;
749 }
750
751 return (error);
752}
753
754/*
755 * This function exists solely to receive the PRC_IFDOWN messages which
756 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
757 * and calls in_ifadown() to remove all routes corresponding to that address.
758 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
759 * interface routes.
760 */
761void
2d21ac55
A
762rip_ctlinput(
763 int cmd,
764 struct sockaddr *sa,
5ba3f43e
A
765 __unused void *vip,
766 __unused struct ifnet *ifp)
1c79356b 767{
5ba3f43e
A
768 struct in_ifaddr *ia = NULL;
769 struct ifnet *iaifp = NULL;
770 int err = 0;
b0d623f7 771 int flags, done = 0;
1c79356b
A
772
773 switch (cmd) {
774 case PRC_IFDOWN:
b0d623f7 775 lck_rw_lock_shared(in_ifaddr_rwlock);
1c79356b
A
776 for (ia = in_ifaddrhead.tqh_first; ia;
777 ia = ia->ia_link.tqe_next) {
6d2010ae
A
778 IFA_LOCK(&ia->ia_ifa);
779 if (ia->ia_ifa.ifa_addr == sa &&
780 (ia->ia_flags & IFA_ROUTE)) {
b0d623f7 781 done = 1;
6d2010ae
A
782 IFA_ADDREF_LOCKED(&ia->ia_ifa);
783 IFA_UNLOCK(&ia->ia_ifa);
b0d623f7
A
784 lck_rw_done(in_ifaddr_rwlock);
785 lck_mtx_lock(rnh_lock);
1c79356b
A
786 /*
787 * in_ifscrub kills the interface route.
788 */
91447636 789 in_ifscrub(ia->ia_ifp, ia, 1);
1c79356b
A
790 /*
791 * in_ifadown gets rid of all the rest of
792 * the routes. This is not quite the right
793 * thing to do, but at least if we are running
794 * a routing process they will come back.
795 */
9bccf70c 796 in_ifadown(&ia->ia_ifa, 1);
b0d623f7 797 lck_mtx_unlock(rnh_lock);
6d2010ae 798 IFA_REMREF(&ia->ia_ifa);
1c79356b
A
799 break;
800 }
6d2010ae 801 IFA_UNLOCK(&ia->ia_ifa);
1c79356b 802 }
b0d623f7
A
803 if (!done)
804 lck_rw_done(in_ifaddr_rwlock);
1c79356b
A
805 break;
806
807 case PRC_IFUP:
b0d623f7 808 lck_rw_lock_shared(in_ifaddr_rwlock);
1c79356b
A
809 for (ia = in_ifaddrhead.tqh_first; ia;
810 ia = ia->ia_link.tqe_next) {
6d2010ae
A
811 IFA_LOCK(&ia->ia_ifa);
812 if (ia->ia_ifa.ifa_addr == sa) {
813 /* keep it locked */
1c79356b 814 break;
6d2010ae
A
815 }
816 IFA_UNLOCK(&ia->ia_ifa);
1c79356b 817 }
6d2010ae
A
818 if (ia == NULL || (ia->ia_flags & IFA_ROUTE) ||
819 (ia->ia_ifa.ifa_debug & IFD_NOTREADY)) {
820 if (ia != NULL)
821 IFA_UNLOCK(&ia->ia_ifa);
b0d623f7 822 lck_rw_done(in_ifaddr_rwlock);
1c79356b 823 return;
91447636 824 }
6d2010ae
A
825 IFA_ADDREF_LOCKED(&ia->ia_ifa);
826 IFA_UNLOCK(&ia->ia_ifa);
b0d623f7
A
827 lck_rw_done(in_ifaddr_rwlock);
828
1c79356b 829 flags = RTF_UP;
5ba3f43e 830 iaifp = ia->ia_ifa.ifa_ifp;
1c79356b 831
5ba3f43e
A
832 if ((iaifp->if_flags & IFF_LOOPBACK)
833 || (iaifp->if_flags & IFF_POINTOPOINT))
1c79356b
A
834 flags |= RTF_HOST;
835
b0d623f7 836 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
6d2010ae
A
837 if (err == 0) {
838 IFA_LOCK_SPIN(&ia->ia_ifa);
1c79356b 839 ia->ia_flags |= IFA_ROUTE;
6d2010ae
A
840 IFA_UNLOCK(&ia->ia_ifa);
841 }
842 IFA_REMREF(&ia->ia_ifa);
1c79356b
A
843 break;
844 }
845}
846
b0d623f7
A
847u_int32_t rip_sendspace = RIPSNDQ;
848u_int32_t rip_recvspace = RIPRCVQ;
1c79356b 849
6d2010ae 850SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW | CTLFLAG_LOCKED,
9bccf70c 851 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
6d2010ae 852SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
9bccf70c 853 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
39236c6e
A
854SYSCTL_UINT(_net_inet_raw, OID_AUTO, pcbcount, CTLFLAG_RD | CTLFLAG_LOCKED,
855 &ripcbinfo.ipi_count, 0, "Number of active PCBs");
1c79356b
A
856
857static int
858rip_attach(struct socket *so, int proto, struct proc *p)
859{
860 struct inpcb *inp;
2d21ac55 861 int error;
1c79356b
A
862
863 inp = sotoinpcb(so);
864 if (inp)
865 panic("rip_attach");
9bccf70c
A
866 if ((so->so_state & SS_PRIV) == 0)
867 return (EPERM);
1c79356b 868
9bccf70c
A
869 error = soreserve(so, rip_sendspace, rip_recvspace);
870 if (error)
871 return error;
1c79356b 872 error = in_pcballoc(so, &ripcbinfo, p);
1c79356b
A
873 if (error)
874 return error;
875 inp = (struct inpcb *)so->so_pcb;
876 inp->inp_vflag |= INP_IPV4;
877 inp->inp_ip_p = proto;
9bccf70c 878 inp->inp_ip_ttl = ip_defttl;
1c79356b
A
879 return 0;
880}
881
9bccf70c 882__private_extern__ int
1c79356b
A
883rip_detach(struct socket *so)
884{
885 struct inpcb *inp;
886
887 inp = sotoinpcb(so);
888 if (inp == 0)
889 panic("rip_detach");
1c79356b
A
890 in_pcbdetach(inp);
891 return 0;
892}
893
9bccf70c 894__private_extern__ int
1c79356b
A
895rip_abort(struct socket *so)
896{
897 soisdisconnected(so);
898 return rip_detach(so);
899}
900
9bccf70c 901__private_extern__ int
1c79356b
A
902rip_disconnect(struct socket *so)
903{
904 if ((so->so_state & SS_ISCONNECTED) == 0)
905 return ENOTCONN;
906 return rip_abort(so);
907}
908
9bccf70c 909__private_extern__ int
39236c6e 910rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
1c79356b 911{
39236c6e 912#pragma unused(p)
1c79356b 913 struct inpcb *inp = sotoinpcb(so);
39236c6e 914 struct sockaddr_in sin;
91447636 915 struct ifaddr *ifa = NULL;
316670eb 916 struct ifnet *outif = NULL;
1c79356b 917
fe8ab488
A
918 if (inp == NULL
919#if NECP
920 || (necp_socket_should_use_flow_divert(inp))
921#endif /* NECP */
922 )
39236c6e 923 return (inp == NULL ? EINVAL : EPROTOTYPE);
1c79356b 924
39236c6e
A
925 if (nam->sa_len != sizeof (struct sockaddr_in))
926 return (EINVAL);
927
928 /* Sanitized local copy for interface address searches */
929 bzero(&sin, sizeof (sin));
930 sin.sin_family = AF_INET;
931 sin.sin_len = sizeof (struct sockaddr_in);
932 sin.sin_addr.s_addr = SIN(nam)->sin_addr.s_addr;
933
934 if (TAILQ_EMPTY(&ifnet_head) ||
935 (sin.sin_family != AF_INET && sin.sin_family != AF_IMPLINK) ||
936 (sin.sin_addr.s_addr && (ifa = ifa_ifwithaddr(SA(&sin))) == 0)) {
937 return (EADDRNOTAVAIL);
938 } else if (ifa) {
939 /*
940 * Opportunistically determine the outbound
941 * interface that may be used; this may not
942 * hold true if we end up using a route
943 * going over a different interface, e.g.
944 * when sending to a local address. This
945 * will get updated again after sending.
946 */
6d2010ae 947 IFA_LOCK(ifa);
316670eb 948 outif = ifa->ifa_ifp;
6d2010ae
A
949 IFA_UNLOCK(ifa);
950 IFA_REMREF(ifa);
91447636 951 }
39236c6e 952 inp->inp_laddr = sin.sin_addr;
316670eb 953 inp->inp_last_outifp = outif;
5ba3f43e 954
39236c6e 955 return (0);
1c79356b
A
956}
957
9bccf70c 958__private_extern__ int
2d21ac55 959rip_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
1c79356b
A
960{
961 struct inpcb *inp = sotoinpcb(so);
316670eb 962 struct sockaddr_in *addr = (struct sockaddr_in *)(void *)nam;
1c79356b 963
fe8ab488
A
964 if (inp == NULL
965#if NECP
966 || (necp_socket_should_use_flow_divert(inp))
967#endif /* NECP */
968 )
39236c6e 969 return (inp == NULL ? EINVAL : EPROTOTYPE);
1c79356b
A
970 if (nam->sa_len != sizeof(*addr))
971 return EINVAL;
91447636 972 if (TAILQ_EMPTY(&ifnet_head))
1c79356b
A
973 return EADDRNOTAVAIL;
974 if ((addr->sin_family != AF_INET) &&
975 (addr->sin_family != AF_IMPLINK))
976 return EAFNOSUPPORT;
5ba3f43e
A
977
978 if (!(so->so_flags1 & SOF1_CONNECT_COUNTED)) {
979 so->so_flags1 |= SOF1_CONNECT_COUNTED;
980 INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_inet_dgram_connected);
981 }
982
1c79356b
A
983 inp->inp_faddr = addr->sin_addr;
984 soisconnected(so);
316670eb 985
1c79356b
A
986 return 0;
987}
988
9bccf70c 989__private_extern__ int
1c79356b
A
990rip_shutdown(struct socket *so)
991{
992 socantsendmore(so);
993 return 0;
994}
995
9bccf70c 996__private_extern__ int
39236c6e
A
997rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
998 struct mbuf *control, struct proc *p)
1c79356b 999{
39236c6e 1000#pragma unused(flags, p)
1c79356b 1001 struct inpcb *inp = sotoinpcb(so);
39236c6e
A
1002 u_int32_t dst;
1003 int error = 0;
1004
fe8ab488
A
1005 if (inp == NULL
1006#if NECP
1007 || (necp_socket_should_use_flow_divert(inp) && (error = EPROTOTYPE))
1008#endif /* NECP */
1009 ) {
1010 if (inp == NULL)
1011 error = EINVAL;
1012 else
1013 error = EPROTOTYPE;
39236c6e
A
1014 goto bad;
1015 }
1c79356b
A
1016
1017 if (so->so_state & SS_ISCONNECTED) {
39236c6e
A
1018 if (nam != NULL) {
1019 error = EISCONN;
1020 goto bad;
1c79356b
A
1021 }
1022 dst = inp->inp_faddr.s_addr;
1023 } else {
1024 if (nam == NULL) {
39236c6e
A
1025 error = ENOTCONN;
1026 goto bad;
1c79356b 1027 }
316670eb 1028 dst = ((struct sockaddr_in *)(void *)nam)->sin_addr.s_addr;
1c79356b 1029 }
39236c6e
A
1030 return (rip_output(m, so, dst, control));
1031
1032bad:
1033 VERIFY(error != 0);
1034
1035 if (m != NULL)
1036 m_freem(m);
1037 if (control != NULL)
1038 m_freem(control);
1039
1040 return (error);
1c79356b
A
1041}
1042
0c530ab8 1043/* note: rip_unlock is called from different protos instead of the generic socket_unlock,
39037602 1044 * it will handle the socket dealloc on last reference
0c530ab8 1045 * */
91447636 1046int
b0d623f7 1047rip_unlock(struct socket *so, int refcount, void *debug)
91447636 1048{
b0d623f7 1049 void *lr_saved;
91447636 1050 struct inpcb *inp = sotoinpcb(so);
0c530ab8 1051
b0d623f7
A
1052 if (debug == NULL)
1053 lr_saved = __builtin_return_address(0);
1054 else
1055 lr_saved = debug;
0c530ab8 1056
91447636 1057 if (refcount) {
b0d623f7
A
1058 if (so->so_usecount <= 0) {
1059 panic("rip_unlock: bad refoucnt so=%p val=%x lrh= %s\n",
1060 so, so->so_usecount, solockhistory_nr(so));
1061 /* NOTREACHED */
1062 }
91447636
A
1063 so->so_usecount--;
1064 if (so->so_usecount == 0 && (inp->inp_wantcnt == WNT_STOPUSING)) {
0c530ab8 1065 /* cleanup after last reference */
91447636 1066 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
39236c6e 1067 lck_rw_lock_exclusive(ripcbinfo.ipi_lock);
b0d623f7
A
1068 if (inp->inp_state != INPCB_STATE_DEAD) {
1069#if INET6
39236c6e 1070 if (SOCK_CHECK_DOM(so, PF_INET6))
b0d623f7
A
1071 in6_pcbdetach(inp);
1072 else
1073#endif /* INET6 */
1074 in_pcbdetach(inp);
1075 }
91447636 1076 in_pcbdispose(inp);
39236c6e 1077 lck_rw_done(ripcbinfo.ipi_lock);
91447636
A
1078 return(0);
1079 }
1080 }
b0d623f7 1081 so->unlock_lr[so->next_unlock_lr] = lr_saved;
0c530ab8 1082 so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX;
91447636
A
1083 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
1084 return(0);
1085}
1086
1c79356b
A
1087static int
1088rip_pcblist SYSCTL_HANDLER_ARGS
1089{
2d21ac55
A
1090#pragma unused(oidp, arg1, arg2)
1091 int error, i, n;
1c79356b
A
1092 struct inpcb *inp, **inp_list;
1093 inp_gen_t gencnt;
1094 struct xinpgen xig;
1095
1096 /*
1097 * The process of preparing the TCB list is too time-consuming and
1098 * resource-intensive to repeat twice on every request.
1099 */
39236c6e 1100 lck_rw_lock_exclusive(ripcbinfo.ipi_lock);
91447636 1101 if (req->oldptr == USER_ADDR_NULL) {
1c79356b
A
1102 n = ripcbinfo.ipi_count;
1103 req->oldidx = 2 * (sizeof xig)
1104 + (n + n/8) * sizeof(struct xinpcb);
39236c6e 1105 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b
A
1106 return 0;
1107 }
1108
91447636 1109 if (req->newptr != USER_ADDR_NULL) {
39236c6e 1110 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b 1111 return EPERM;
91447636 1112 }
1c79356b
A
1113
1114 /*
1115 * OK, now we're committed to doing something.
1116 */
1c79356b
A
1117 gencnt = ripcbinfo.ipi_gencnt;
1118 n = ripcbinfo.ipi_count;
39037602 1119
3a60a9f5 1120 bzero(&xig, sizeof(xig));
1c79356b
A
1121 xig.xig_len = sizeof xig;
1122 xig.xig_count = n;
1123 xig.xig_gen = gencnt;
1124 xig.xig_sogen = so_gencnt;
1125 error = SYSCTL_OUT(req, &xig, sizeof xig);
91447636 1126 if (error) {
39236c6e 1127 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b 1128 return error;
91447636 1129 }
9bccf70c
A
1130 /*
1131 * We are done if there is no pcb
1132 */
91447636 1133 if (n == 0) {
39236c6e 1134 lck_rw_done(ripcbinfo.ipi_lock);
39037602 1135 return 0;
91447636 1136 }
1c79356b
A
1137
1138 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
91447636 1139 if (inp_list == 0) {
39236c6e 1140 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b 1141 return ENOMEM;
91447636 1142 }
39037602 1143
39236c6e 1144 for (inp = ripcbinfo.ipi_listhead->lh_first, i = 0; inp && i < n;
1c79356b 1145 inp = inp->inp_list.le_next) {
91447636 1146 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
1c79356b
A
1147 inp_list[i++] = inp;
1148 }
1c79356b
A
1149 n = i;
1150
1151 error = 0;
1152 for (i = 0; i < n; i++) {
1153 inp = inp_list[i];
91447636 1154 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
1c79356b 1155 struct xinpcb xi;
3a60a9f5
A
1156
1157 bzero(&xi, sizeof(xi));
1c79356b
A
1158 xi.xi_len = sizeof xi;
1159 /* XXX should avoid extra copy */
91447636 1160 inpcb_to_compat(inp, &xi.xi_inp);
1c79356b
A
1161 if (inp->inp_socket)
1162 sotoxsocket(inp->inp_socket, &xi.xi_socket);
1163 error = SYSCTL_OUT(req, &xi, sizeof xi);
1164 }
1165 }
1166 if (!error) {
1167 /*
1168 * Give the user an updated idea of our state.
1169 * If the generation differs from what we told
1170 * her before, she knows that something happened
1171 * while we were processing this request, and it
1172 * might be necessary to retry.
1173 */
3a60a9f5
A
1174 bzero(&xig, sizeof(xig));
1175 xig.xig_len = sizeof xig;
1c79356b
A
1176 xig.xig_gen = ripcbinfo.ipi_gencnt;
1177 xig.xig_sogen = so_gencnt;
1178 xig.xig_count = ripcbinfo.ipi_count;
1c79356b
A
1179 error = SYSCTL_OUT(req, &xig, sizeof xig);
1180 }
1181 FREE(inp_list, M_TEMP);
39236c6e 1182 lck_rw_done(ripcbinfo.ipi_lock);
1c79356b
A
1183 return error;
1184}
1185
fe8ab488
A
1186SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist,
1187 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
1c79356b
A
1188 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
1189
5ba3f43e 1190#if !CONFIG_EMBEDDED
b0d623f7
A
1191
1192static int
1193rip_pcblist64 SYSCTL_HANDLER_ARGS
1194{
1195#pragma unused(oidp, arg1, arg2)
1196 int error, i, n;
1197 struct inpcb *inp, **inp_list;
1198 inp_gen_t gencnt;
1199 struct xinpgen xig;
1200
1201 /*
1202 * The process of preparing the TCB list is too time-consuming and
1203 * resource-intensive to repeat twice on every request.
1204 */
39236c6e 1205 lck_rw_lock_exclusive(ripcbinfo.ipi_lock);
b0d623f7
A
1206 if (req->oldptr == USER_ADDR_NULL) {
1207 n = ripcbinfo.ipi_count;
1208 req->oldidx = 2 * (sizeof xig)
1209 + (n + n/8) * sizeof(struct xinpcb64);
39236c6e 1210 lck_rw_done(ripcbinfo.ipi_lock);
b0d623f7
A
1211 return 0;
1212 }
1213
1214 if (req->newptr != USER_ADDR_NULL) {
39236c6e 1215 lck_rw_done(ripcbinfo.ipi_lock);
b0d623f7
A
1216 return EPERM;
1217 }
1218
1219 /*
1220 * OK, now we're committed to doing something.
1221 */
1222 gencnt = ripcbinfo.ipi_gencnt;
1223 n = ripcbinfo.ipi_count;
1224
1225 bzero(&xig, sizeof(xig));
1226 xig.xig_len = sizeof xig;
1227 xig.xig_count = n;
1228 xig.xig_gen = gencnt;
1229 xig.xig_sogen = so_gencnt;
1230 error = SYSCTL_OUT(req, &xig, sizeof xig);
1231 if (error) {
39236c6e 1232 lck_rw_done(ripcbinfo.ipi_lock);
b0d623f7
A
1233 return error;
1234 }
1235 /*
1236 * We are done if there is no pcb
1237 */
1238 if (n == 0) {
39236c6e 1239 lck_rw_done(ripcbinfo.ipi_lock);
b0d623f7
A
1240 return 0;
1241 }
1242
1243 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
1244 if (inp_list == 0) {
39236c6e 1245 lck_rw_done(ripcbinfo.ipi_lock);
b0d623f7
A
1246 return ENOMEM;
1247 }
1248
39236c6e 1249 for (inp = ripcbinfo.ipi_listhead->lh_first, i = 0; inp && i < n;
b0d623f7
A
1250 inp = inp->inp_list.le_next) {
1251 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
1252 inp_list[i++] = inp;
1253 }
1254 n = i;
1255
1256 error = 0;
1257 for (i = 0; i < n; i++) {
1258 inp = inp_list[i];
1259 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
1260 struct xinpcb64 xi;
1261
1262 bzero(&xi, sizeof(xi));
1263 xi.xi_len = sizeof xi;
1264 inpcb_to_xinpcb64(inp, &xi);
1265 if (inp->inp_socket)
1266 sotoxsocket64(inp->inp_socket, &xi.xi_socket);
1267 error = SYSCTL_OUT(req, &xi, sizeof xi);
1268 }
1269 }
1270 if (!error) {
1271 /*
1272 * Give the user an updated idea of our state.
1273 * If the generation differs from what we told
1274 * her before, she knows that something happened
1275 * while we were processing this request, and it
1276 * might be necessary to retry.
1277 */
1278 bzero(&xig, sizeof(xig));
1279 xig.xig_len = sizeof xig;
1280 xig.xig_gen = ripcbinfo.ipi_gencnt;
1281 xig.xig_sogen = so_gencnt;
1282 xig.xig_count = ripcbinfo.ipi_count;
1283 error = SYSCTL_OUT(req, &xig, sizeof xig);
1284 }
1285 FREE(inp_list, M_TEMP);
39236c6e 1286 lck_rw_done(ripcbinfo.ipi_lock);
b0d623f7
A
1287 return error;
1288}
1289
fe8ab488
A
1290SYSCTL_PROC(_net_inet_raw, OID_AUTO, pcblist64,
1291 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
b0d623f7
A
1292 rip_pcblist64, "S,xinpcb64", "List of active raw IP sockets");
1293
5ba3f43e 1294#endif /* !CONFIG_EMBEDDED */
b0d623f7 1295
6d2010ae
A
1296
1297static int
1298rip_pcblist_n SYSCTL_HANDLER_ARGS
1299{
1300#pragma unused(oidp, arg1, arg2)
1301 int error = 0;
39236c6e 1302
6d2010ae 1303 error = get_pcblist_n(IPPROTO_IP, req, &ripcbinfo);
39236c6e 1304
6d2010ae
A
1305 return error;
1306}
1307
fe8ab488
A
1308SYSCTL_PROC(_net_inet_raw, OID_AUTO, pcblist_n,
1309 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
6d2010ae
A
1310 rip_pcblist_n, "S,xinpcb_n", "List of active raw IP sockets");
1311
1c79356b 1312struct pr_usrreqs rip_usrreqs = {
39236c6e
A
1313 .pru_abort = rip_abort,
1314 .pru_attach = rip_attach,
1315 .pru_bind = rip_bind,
1316 .pru_connect = rip_connect,
1317 .pru_control = in_control,
1318 .pru_detach = rip_detach,
1319 .pru_disconnect = rip_disconnect,
1320 .pru_peeraddr = in_getpeeraddr,
1321 .pru_send = rip_send,
1322 .pru_shutdown = rip_shutdown,
1323 .pru_sockaddr = in_getsockaddr,
1324 .pru_sosend = sosend,
1325 .pru_soreceive = soreceive,
1c79356b 1326};
2d21ac55 1327/* DSEP Review Done pl-20051213-v02 @3253 */