1/*
2 * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 */
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 */
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>
74#include <sys/mcache.h>
75#include <sys/proc.h>
76#include <sys/domain.h>
77#include <sys/protosw.h>
78#include <sys/socket.h>
79#include <sys/socketvar.h>
80#include <sys/sysctl.h>
81#include <libkern/OSAtomic.h>
82#include <kern/zalloc.h>
83
84#include <pexpert/pexpert.h>
85
86#include <net/if.h>
87#include <net/net_api_stats.h>
88#include <net/route.h>
89
90#define _IP_VHL
91#include <netinet/in.h>
92#include <netinet/in_systm.h>
93#include <netinet/in_tclass.h>
94#include <netinet/ip.h>
95#include <netinet/in_pcb.h>
96#include <netinet/in_var.h>
97#include <netinet/ip_var.h>
98
99#if INET6
100#include <netinet6/in6_pcb.h>
101#endif /* INET6 */
102
103#include <netinet/ip_fw.h>
104
105#if IPSEC
106#include <netinet6/ipsec.h>
107#endif /*IPSEC*/
108
109#if DUMMYNET
110#include <netinet/ip_dummynet.h>
111#endif
112
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 *);
124
125struct inpcbhead ripcb;
126struct inpcbinfo ripcbinfo;
127
128/* control hooks for ipfw and dummynet */
129#if IPFIREWALL
130ip_fw_ctl_t *ip_fw_ctl_ptr;
131#endif /* IPFIREWALL */
132#if DUMMYNET
133ip_dn_ctl_t *ip_dn_ctl_ptr;
134#endif /* DUMMYNET */
135
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
150rip_init(struct protosw *pp, struct domain *dp)
151{
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;
161
162 LIST_INIT(&ripcb);
163 ripcbinfo.ipi_listhead = &ripcb;
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
167 * over the place for ipi_hashbase == NULL.
168 */
169 ripcbinfo.ipi_hashbase = hashinit(1, M_PCB, &ripcbinfo.ipi_hashmask);
170 ripcbinfo.ipi_porthashbase = hashinit(1, M_PCB, &ripcbinfo.ipi_porthashmask);
171
172 ripcbinfo.ipi_zone = zinit(sizeof(struct inpcb),
173 (4096 * sizeof(struct inpcb)), 4096, "ripzone");
174
175 pcbinfo = &ripcbinfo;
176 /*
177 * allocate lock group attribute and group for udp pcb mutexes
178 */
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);
181
182 /*
183 * allocate the lock attribute for udp pcb mutexes
184 */
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 }
191
192 in_pcbinfo_attach(&ripcbinfo);
193}
194
195static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET , 0, {0}, {0,0,0,0,0,0,0,0,} };
196/*
197 * Setup generic address and protocol structures
198 * for raw_input routine, then pass them along with
199 * mbuf chain.
200 */
201void
202rip_input(struct mbuf *m, int iphlen)
203{
204 struct ip *ip = mtod(m, struct ip *);
205 struct inpcb *inp;
206 struct inpcb *last = 0;
207 struct mbuf *opts = 0;
208 int skipit = 0, ret = 0;
209 struct ifnet *ifp = m->m_pkthdr.rcvif;
210
211 /* Expect 32-bit aligned data pointer on strict-align platforms */
212 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
213
214 ripsrc.sin_addr = ip->ip_src;
215 lck_rw_lock_shared(ripcbinfo.ipi_lock);
216 LIST_FOREACH(inp, &ripcb, inp_list) {
217#if INET6
218 if ((inp->inp_vflag & INP_IPV4) == 0)
219 continue;
220#endif
221 if (inp->inp_ip_p && (inp->inp_ip_p != ip->ip_p))
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;
229 if (inp_restricted_recv(inp, ifp))
230 continue;
231 if (last) {
232 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
233
234 skipit = 0;
235
236#if NECP
237 if (n && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
238 &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
239 m_freem(n);
240 /* do not inject data to pcb */
241 skipit = 1;
242 }
243#endif /* NECP */
244#if CONFIG_MACF_NET
245 if (n && skipit == 0) {
246 if (mac_inpcb_check_deliver(last, n, AF_INET,
247 SOCK_RAW) != 0) {
248 m_freem(n);
249 skipit = 1;
250 }
251 }
252#endif
253 if (n && skipit == 0) {
254 int error = 0;
255 if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
256 (last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
257 (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
258 (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
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 }
267 if (last->inp_flags & INP_STRIPHDR) {
268 n->m_len -= iphlen;
269 n->m_pkthdr.len -= iphlen;
270 n->m_data += iphlen;
271 }
272 so_recv_data_stat(last->inp_socket, m, 0);
273 if (sbappendaddr(&last->inp_socket->so_rcv,
274 (struct sockaddr *)&ripsrc, n,
275 opts, &error) != 0) {
276 sorwakeup(last->inp_socket);
277 } else {
278 if (error) {
279 /* should notify about lost packet */
280 ipstat.ips_raw_sappend_fail++;
281 }
282 }
283 opts = 0;
284 }
285 }
286 last = inp;
287 }
288
289 skipit = 0;
290#if NECP
291 if (last && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
292 &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
293 m_freem(m);
294 OSAddAtomic(1, &ipstat.ips_delivered);
295 /* do not inject data to pcb */
296 skipit = 1;
297 }
298#endif /* NECP */
299#if CONFIG_MACF_NET
300 if (last && skipit == 0) {
301 if (mac_inpcb_check_deliver(last, m, AF_INET, SOCK_RAW) != 0) {
302 skipit = 1;
303 m_freem(m);
304 }
305 }
306#endif
307 if (skipit == 0) {
308 if (last) {
309 if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
310 (last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
311 (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
312 (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
313 ret = ip_savecontrol(last, &opts, ip, m);
314 if (ret != 0) {
315 m_freem(m);
316 m_freem(opts);
317 goto unlock;
318 }
319 }
320 if (last->inp_flags & INP_STRIPHDR) {
321 m->m_len -= iphlen;
322 m->m_pkthdr.len -= iphlen;
323 m->m_data += iphlen;
324 }
325 so_recv_data_stat(last->inp_socket, m, 0);
326 if (sbappendaddr(&last->inp_socket->so_rcv,
327 (struct sockaddr *)&ripsrc, m, opts, NULL) != 0) {
328 sorwakeup(last->inp_socket);
329 } else {
330 ipstat.ips_raw_sappend_fail++;
331 }
332 } else {
333 m_freem(m);
334 OSAddAtomic(1, &ipstat.ips_noproto);
335 OSAddAtomic(-1, &ipstat.ips_delivered);
336 }
337 }
338unlock:
339 /*
340 * Keep the list locked because socket filter may force the socket lock
341 * to be released when calling sbappendaddr() -- see rdar://7627704
342 */
343 lck_rw_done(ripcbinfo.ipi_lock);
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
351rip_output(
352 struct mbuf *m,
353 struct socket *so,
354 u_int32_t dst,
355 struct mbuf *control)
356{
357 struct ip *ip;
358 struct inpcb *inp = sotoinpcb(so);
359 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
360 struct ip_out_args ipoa;
361 struct ip_moptions *imo;
362 int error = 0;
363
364 bzero(&ipoa, sizeof(ipoa));
365 ipoa.ipoa_boundif = IFSCOPE_NONE;
366 ipoa.ipoa_flags = IPOAF_SELECT_SRCIF;
367
368 int sotc = SO_TC_UNSPEC;
369 int netsvctype = _NET_SERVICE_TYPE_UNSPEC;
370
371
372 if (control != NULL) {
373 sotc = so_tc_from_control(control, &netsvctype);
374
375 m_freem(control);
376 control = NULL;
377 }
378 if (sotc == SO_TC_UNSPEC) {
379 sotc = so->so_traffic_class;
380 netsvctype = so->so_netsvctype;
381 }
382
383 if (inp == NULL
384#if NECP
385 || (necp_socket_should_use_flow_divert(inp))
386#endif /* NECP */
387 ) {
388 if (m != NULL)
389 m_freem(m);
390 VERIFY(control == NULL);
391 return (inp == NULL ? EINVAL : EPROTOTYPE);
392 }
393
394 flags |= IP_OUTARGS;
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 }
400 if (INP_NO_CELLULAR(inp))
401 ipoa.ipoa_flags |= IPOAF_NO_CELLULAR;
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;
406 ipoa.ipoa_sotc = sotc;
407 ipoa.ipoa_netsvctype = netsvctype;
408
409 if (inp->inp_flowhash == 0)
410 inp->inp_flowhash = inp_calc_flowhash(inp);
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 }
421 M_PREPEND(m, sizeof(struct ip), M_WAIT, 1);
422 if (m == NULL)
423 return ENOBUFS;
424 ip = mtod(m, struct ip *);
425 ip->ip_tos = inp->inp_ip_tos;
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;
431 ip->ip_ttl = inp->inp_ip_ttl;
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 */
440 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
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 }
447 if (ip->ip_id == 0 && !(rfc6864 && IP_OFF_IS_ATOMIC(ntohs(ip->ip_off))))
448 ip->ip_id = ip_randomid();
449 /* XXX prevent ip_output from overwriting header fields */
450 flags |= IP_RAWOUTPUT;
451 OSAddAtomic(1, &ipstat.ips_rawout);
452 }
453
454 if (inp->inp_laddr.s_addr != INADDR_ANY)
455 ipoa.ipoa_flags |= IPOAF_BOUND_SRCADDR;
456
457#if NECP
458 {
459 necp_kernel_policy_id policy_id;
460 necp_kernel_policy_id skip_policy_id;
461 u_int32_t route_rule_id;
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
497 if (!necp_socket_is_allowed_to_send_recv_v4(inp, 0, 0,
498 &ip->ip_src, &ip->ip_dst, NULL, &policy_id, &route_rule_id, &skip_policy_id)) {
499 m_freem(m);
500 return(EHOSTUNREACH);
501 }
502
503 necp_mark_packet_from_socket(m, inp, policy_id, route_rule_id, skip_policy_id);
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
511 necp_socket_update_qos_marking(inp, inp->inp_route.ro_rt,
512 NULL, route_rule_id);
513 }
514 }
515#endif /* NECP */
516 if ((so->so_flags1 & SOF1_QOSMARKING_ALLOWED))
517 ipoa.ipoa_flags |= IPOAF_QOSMARKING_ALLOWED;
518
519#if IPSEC
520 if (inp->inp_sp != NULL && ipsec_setsocket(m, so) != 0) {
521 m_freem(m);
522 return ENOBUFS;
523 }
524#endif /*IPSEC*/
525
526 if (ROUTE_UNUSABLE(&inp->inp_route))
527 ROUTE_RELEASE(&inp->inp_route);
528
529 set_packet_service_class(m, so, sotc, 0);
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;
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;
541
542#if CONFIG_MACF_NET
543 mac_mbuf_label_associate_inpcb(inp, m);
544#endif
545
546 imo = inp->inp_moptions;
547 if (imo != NULL)
548 IMO_ADDREF(imo);
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 */
554 // TODO: PASS DOWN ROUTE RULE ID
555 error = ip_output(m, inp->inp_options, &inp->inp_route, flags,
556 imo, &ipoa);
557
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;
563 struct ifnet *outif;
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 */
574 if (rt == NULL)
575 ROUTE_RELEASE(&inp->inp_route);
576
577 /*
578 * If this is a connected socket and the destination
579 * route is unicast, update outif with that of the
580 * route interface used by IP.
581 */
582 if (rt != NULL &&
583 (outif = rt->rt_ifp) != inp->inp_last_outifp) {
584 inp->inp_last_outifp = outif;
585 }
586 } else {
587 ROUTE_RELEASE(&inp->inp_route);
588 }
589
590 /*
591 * If output interface was cellular/expensive, and this socket is
592 * denied access to it, generate an event.
593 */
594 if (error != 0 && (ipoa.ipoa_retflags & IPOARF_IFDENIED) &&
595 (INP_NO_CELLULAR(inp) || INP_NO_EXPENSIVE(inp)))
596 soevent(so, (SO_FILT_HINT_LOCKED|SO_FILT_HINT_IFDENIED));
597
598 return (error);
599}
600
601#if IPFIREWALL
602int
603load_ipfw(void)
604{
605 kern_return_t err;
606
607 ipfw_init();
608
609#if DUMMYNET
610 if (!DUMMYNET_LOADED)
611 ip_dn_init();
612#endif /* DUMMYNET */
613 err = 0;
614
615 return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
616}
617#endif /* IPFIREWALL */
618
619/*
620 * Raw IP socket option processing.
621 */
622int
623rip_ctloutput(struct socket *so, struct sockopt *sopt)
624{
625 struct inpcb *inp = sotoinpcb(so);
626 int error, optval;
627
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))
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
643 case IP_STRIPHDR:
644 optval = inp->inp_flags & INP_STRIPHDR;
645 error = sooptcopyout(sopt, &optval, sizeof optval);
646 break;
647
648#if IPFIREWALL
649 case IP_FW_ADD:
650 case IP_FW_GET:
651 case IP_OLD_FW_ADD:
652 case IP_OLD_FW_GET:
653 if (ip_fw_ctl_ptr == 0)
654 error = load_ipfw();
655 if (ip_fw_ctl_ptr && error == 0)
656 error = ip_fw_ctl_ptr(sopt);
657 else
658 error = ENOPROTOOPT;
659 break;
660#endif /* IPFIREWALL */
661
662#if DUMMYNET
663 case IP_DUMMYNET_GET:
664 if (!DUMMYNET_LOADED)
665 ip_dn_init();
666 if (DUMMYNET_LOADED)
667 error = ip_dn_ctl_ptr(sopt);
668 else
669 error = ENOPROTOOPT;
670 break ;
671#endif /* DUMMYNET */
672
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
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;
702
703#if IPFIREWALL
704 case IP_FW_ADD:
705 case IP_FW_DEL:
706 case IP_FW_FLUSH:
707 case IP_FW_ZERO:
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:
714 if (ip_fw_ctl_ptr == 0)
715 error = load_ipfw();
716 if (ip_fw_ctl_ptr && error == 0)
717 error = ip_fw_ctl_ptr(sopt);
718 else
719 error = ENOPROTOOPT;
720 break;
721#endif /* IPFIREWALL */
722
723#if DUMMYNET
724 case IP_DUMMYNET_CONFIGURE:
725 case IP_DUMMYNET_DEL:
726 case IP_DUMMYNET_FLUSH:
727 if (!DUMMYNET_LOADED)
728 ip_dn_init();
729 if (DUMMYNET_LOADED)
730 error = ip_dn_ctl_ptr(sopt);
731 else
732 error = ENOPROTOOPT ;
733 break ;
734#endif
735
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
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
762rip_ctlinput(
763 int cmd,
764 struct sockaddr *sa,
765 __unused void *vip,
766 __unused struct ifnet *ifp)
767{
768 struct in_ifaddr *ia = NULL;
769 struct ifnet *iaifp = NULL;
770 int err = 0;
771 int flags, done = 0;
772
773 switch (cmd) {
774 case PRC_IFDOWN:
775 lck_rw_lock_shared(in_ifaddr_rwlock);
776 for (ia = in_ifaddrhead.tqh_first; ia;
777 ia = ia->ia_link.tqe_next) {
778 IFA_LOCK(&ia->ia_ifa);
779 if (ia->ia_ifa.ifa_addr == sa &&
780 (ia->ia_flags & IFA_ROUTE)) {
781 done = 1;
782 IFA_ADDREF_LOCKED(&ia->ia_ifa);
783 IFA_UNLOCK(&ia->ia_ifa);
784 lck_rw_done(in_ifaddr_rwlock);
785 lck_mtx_lock(rnh_lock);
786 /*
787 * in_ifscrub kills the interface route.
788 */
789 in_ifscrub(ia->ia_ifp, ia, 1);
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 */
796 in_ifadown(&ia->ia_ifa, 1);
797 lck_mtx_unlock(rnh_lock);
798 IFA_REMREF(&ia->ia_ifa);
799 break;
800 }
801 IFA_UNLOCK(&ia->ia_ifa);
802 }
803 if (!done)
804 lck_rw_done(in_ifaddr_rwlock);
805 break;
806
807 case PRC_IFUP:
808 lck_rw_lock_shared(in_ifaddr_rwlock);
809 for (ia = in_ifaddrhead.tqh_first; ia;
810 ia = ia->ia_link.tqe_next) {
811 IFA_LOCK(&ia->ia_ifa);
812 if (ia->ia_ifa.ifa_addr == sa) {
813 /* keep it locked */
814 break;
815 }
816 IFA_UNLOCK(&ia->ia_ifa);
817 }
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);
822 lck_rw_done(in_ifaddr_rwlock);
823 return;
824 }
825 IFA_ADDREF_LOCKED(&ia->ia_ifa);
826 IFA_UNLOCK(&ia->ia_ifa);
827 lck_rw_done(in_ifaddr_rwlock);
828
829 flags = RTF_UP;
830 iaifp = ia->ia_ifa.ifa_ifp;
831
832 if ((iaifp->if_flags & IFF_LOOPBACK)
833 || (iaifp->if_flags & IFF_POINTOPOINT))
834 flags |= RTF_HOST;
835
836 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
837 if (err == 0) {
838 IFA_LOCK_SPIN(&ia->ia_ifa);
839 ia->ia_flags |= IFA_ROUTE;
840 IFA_UNLOCK(&ia->ia_ifa);
841 }
842 IFA_REMREF(&ia->ia_ifa);
843 break;
844 }
845}
846
847u_int32_t rip_sendspace = RIPSNDQ;
848u_int32_t rip_recvspace = RIPRCVQ;
849
850SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW | CTLFLAG_LOCKED,
851 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
852SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
853 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
854SYSCTL_UINT(_net_inet_raw, OID_AUTO, pcbcount, CTLFLAG_RD | CTLFLAG_LOCKED,
855 &ripcbinfo.ipi_count, 0, "Number of active PCBs");
856
857static int
858rip_attach(struct socket *so, int proto, struct proc *p)
859{
860 struct inpcb *inp;
861 int error;
862
863 inp = sotoinpcb(so);
864 if (inp)
865 panic("rip_attach");
866 if ((so->so_state & SS_PRIV) == 0)
867 return (EPERM);
868
869 error = soreserve(so, rip_sendspace, rip_recvspace);
870 if (error)
871 return error;
872 error = in_pcballoc(so, &ripcbinfo, p);
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;
878 inp->inp_ip_ttl = ip_defttl;
879 return 0;
880}
881
882__private_extern__ int
883rip_detach(struct socket *so)
884{
885 struct inpcb *inp;
886
887 inp = sotoinpcb(so);
888 if (inp == 0)
889 panic("rip_detach");
890 in_pcbdetach(inp);
891 return 0;
892}
893
894__private_extern__ int
895rip_abort(struct socket *so)
896{
897 soisdisconnected(so);
898 return rip_detach(so);
899}
900
901__private_extern__ int
902rip_disconnect(struct socket *so)
903{
904 if ((so->so_state & SS_ISCONNECTED) == 0)
905 return ENOTCONN;
906 return rip_abort(so);
907}
908
909__private_extern__ int
910rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
911{
912#pragma unused(p)
913 struct inpcb *inp = sotoinpcb(so);
914 struct sockaddr_in sin;
915 struct ifaddr *ifa = NULL;
916 struct ifnet *outif = NULL;
917
918 if (inp == NULL
919#if NECP
920 || (necp_socket_should_use_flow_divert(inp))
921#endif /* NECP */
922 )
923 return (inp == NULL ? EINVAL : EPROTOTYPE);
924
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 */
947 IFA_LOCK(ifa);
948 outif = ifa->ifa_ifp;
949 IFA_UNLOCK(ifa);
950 IFA_REMREF(ifa);
951 }
952 inp->inp_laddr = sin.sin_addr;
953 inp->inp_last_outifp = outif;
954
955 return (0);
956}
957
958__private_extern__ int
959rip_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
960{
961 struct inpcb *inp = sotoinpcb(so);
962 struct sockaddr_in *addr = (struct sockaddr_in *)(void *)nam;
963
964 if (inp == NULL
965#if NECP
966 || (necp_socket_should_use_flow_divert(inp))
967#endif /* NECP */
968 )
969 return (inp == NULL ? EINVAL : EPROTOTYPE);
970 if (nam->sa_len != sizeof(*addr))
971 return EINVAL;
972 if (TAILQ_EMPTY(&ifnet_head))
973 return EADDRNOTAVAIL;
974 if ((addr->sin_family != AF_INET) &&
975 (addr->sin_family != AF_IMPLINK))
976 return EAFNOSUPPORT;
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
983 inp->inp_faddr = addr->sin_addr;
984 soisconnected(so);
985
986 return 0;
987}
988
989__private_extern__ int
990rip_shutdown(struct socket *so)
991{
992 socantsendmore(so);
993 return 0;
994}
995
996__private_extern__ int
997rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
998 struct mbuf *control, struct proc *p)
999{
1000#pragma unused(flags, p)
1001 struct inpcb *inp = sotoinpcb(so);
1002 u_int32_t dst;
1003 int error = 0;
1004
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;
1014 goto bad;
1015 }
1016
1017 if (so->so_state & SS_ISCONNECTED) {
1018 if (nam != NULL) {
1019 error = EISCONN;
1020 goto bad;
1021 }
1022 dst = inp->inp_faddr.s_addr;
1023 } else {
1024 if (nam == NULL) {
1025 error = ENOTCONN;
1026 goto bad;
1027 }
1028 dst = ((struct sockaddr_in *)(void *)nam)->sin_addr.s_addr;
1029 }
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);
1041}
1042
1043/* note: rip_unlock is called from different protos instead of the generic socket_unlock,
1044 * it will handle the socket dealloc on last reference
1045 * */
1046int
1047rip_unlock(struct socket *so, int refcount, void *debug)
1048{
1049 void *lr_saved;
1050 struct inpcb *inp = sotoinpcb(so);
1051
1052 if (debug == NULL)
1053 lr_saved = __builtin_return_address(0);
1054 else
1055 lr_saved = debug;
1056
1057 if (refcount) {
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 }
1063 so->so_usecount--;
1064 if (so->so_usecount == 0 && (inp->inp_wantcnt == WNT_STOPUSING)) {
1065 /* cleanup after last reference */
1066 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
1067 lck_rw_lock_exclusive(ripcbinfo.ipi_lock);
1068 if (inp->inp_state != INPCB_STATE_DEAD) {
1069#if INET6
1070 if (SOCK_CHECK_DOM(so, PF_INET6))
1071 in6_pcbdetach(inp);
1072 else
1073#endif /* INET6 */
1074 in_pcbdetach(inp);
1075 }
1076 in_pcbdispose(inp);
1077 lck_rw_done(ripcbinfo.ipi_lock);
1078 return(0);
1079 }
1080 }
1081 so->unlock_lr[so->next_unlock_lr] = lr_saved;
1082 so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX;
1083 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
1084 return(0);
1085}
1086
1087static int
1088rip_pcblist SYSCTL_HANDLER_ARGS
1089{
1090#pragma unused(oidp, arg1, arg2)
1091 int error, i, n;
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 */
1100 lck_rw_lock_exclusive(ripcbinfo.ipi_lock);
1101 if (req->oldptr == USER_ADDR_NULL) {
1102 n = ripcbinfo.ipi_count;
1103 req->oldidx = 2 * (sizeof xig)
1104 + (n + n/8) * sizeof(struct xinpcb);
1105 lck_rw_done(ripcbinfo.ipi_lock);
1106 return 0;
1107 }
1108
1109 if (req->newptr != USER_ADDR_NULL) {
1110 lck_rw_done(ripcbinfo.ipi_lock);
1111 return EPERM;
1112 }
1113
1114 /*
1115 * OK, now we're committed to doing something.
1116 */
1117 gencnt = ripcbinfo.ipi_gencnt;
1118 n = ripcbinfo.ipi_count;
1119
1120 bzero(&xig, sizeof(xig));
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);
1126 if (error) {
1127 lck_rw_done(ripcbinfo.ipi_lock);
1128 return error;
1129 }
1130 /*
1131 * We are done if there is no pcb
1132 */
1133 if (n == 0) {
1134 lck_rw_done(ripcbinfo.ipi_lock);
1135 return 0;
1136 }
1137
1138 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
1139 if (inp_list == 0) {
1140 lck_rw_done(ripcbinfo.ipi_lock);
1141 return ENOMEM;
1142 }
1143
1144 for (inp = ripcbinfo.ipi_listhead->lh_first, i = 0; inp && i < n;
1145 inp = inp->inp_list.le_next) {
1146 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
1147 inp_list[i++] = inp;
1148 }
1149 n = i;
1150
1151 error = 0;
1152 for (i = 0; i < n; i++) {
1153 inp = inp_list[i];
1154 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
1155 struct xinpcb xi;
1156
1157 bzero(&xi, sizeof(xi));
1158 xi.xi_len = sizeof xi;
1159 /* XXX should avoid extra copy */
1160 inpcb_to_compat(inp, &xi.xi_inp);
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 */
1174 bzero(&xig, sizeof(xig));
1175 xig.xig_len = sizeof xig;
1176 xig.xig_gen = ripcbinfo.ipi_gencnt;
1177 xig.xig_sogen = so_gencnt;
1178 xig.xig_count = ripcbinfo.ipi_count;
1179 error = SYSCTL_OUT(req, &xig, sizeof xig);
1180 }
1181 FREE(inp_list, M_TEMP);
1182 lck_rw_done(ripcbinfo.ipi_lock);
1183 return error;
1184}
1185
1186SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist,
1187 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
1188 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
1189
1190#if !CONFIG_EMBEDDED
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 */
1205 lck_rw_lock_exclusive(ripcbinfo.ipi_lock);
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);
1210 lck_rw_done(ripcbinfo.ipi_lock);
1211 return 0;
1212 }
1213
1214 if (req->newptr != USER_ADDR_NULL) {
1215 lck_rw_done(ripcbinfo.ipi_lock);
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) {
1232 lck_rw_done(ripcbinfo.ipi_lock);
1233 return error;
1234 }
1235 /*
1236 * We are done if there is no pcb
1237 */
1238 if (n == 0) {
1239 lck_rw_done(ripcbinfo.ipi_lock);
1240 return 0;
1241 }
1242
1243 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
1244 if (inp_list == 0) {
1245 lck_rw_done(ripcbinfo.ipi_lock);
1246 return ENOMEM;
1247 }
1248
1249 for (inp = ripcbinfo.ipi_listhead->lh_first, i = 0; inp && i < n;
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);
1286 lck_rw_done(ripcbinfo.ipi_lock);
1287 return error;
1288}
1289
1290SYSCTL_PROC(_net_inet_raw, OID_AUTO, pcblist64,
1291 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
1292 rip_pcblist64, "S,xinpcb64", "List of active raw IP sockets");
1293
1294#endif /* !CONFIG_EMBEDDED */
1295
1296
1297static int
1298rip_pcblist_n SYSCTL_HANDLER_ARGS
1299{
1300#pragma unused(oidp, arg1, arg2)
1301 int error = 0;
1302
1303 error = get_pcblist_n(IPPROTO_IP, req, &ripcbinfo);
1304
1305 return error;
1306}
1307
1308SYSCTL_PROC(_net_inet_raw, OID_AUTO, pcblist_n,
1309 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
1310 rip_pcblist_n, "S,xinpcb_n", "List of active raw IP sockets");
1311
1312struct pr_usrreqs rip_usrreqs = {
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,
1326};
1327/* DSEP Review Done pl-20051213-v02 @3253 */
1328