]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/raw_ip.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / netinet / raw_ip.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1982, 1986, 1988, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
58 */
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/kernel.h>
63 #include <sys/malloc.h>
64 #include <sys/mbuf.h>
65 #include <sys/proc.h>
66 #include <sys/protosw.h>
67 #include <sys/socket.h>
68 #include <sys/socketvar.h>
69 #include <sys/sysctl.h>
70
71 #if __FreeBSD__
72 #include <vm/vm_zone.h>
73 #endif
74
75 #include <net/if.h>
76 #include <net/route.h>
77
78 #define _IP_VHL
79 #include <netinet/in.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/ip.h>
82 #include <netinet/in_pcb.h>
83 #include <netinet/in_var.h>
84 #include <netinet/ip_var.h>
85 #include <netinet/ip_mroute.h>
86
87 #include <netinet/ip_fw.h>
88
89 #if IPSEC
90 #include <netinet6/ipsec.h>
91 #endif /*IPSEC*/
92
93 #if DUMMYNET
94 #include <netinet/ip_dummynet.h>
95 #endif
96
97 #if IPSEC
98 extern int ipsec_bypass;
99 #endif
100
101 struct inpcbhead ripcb;
102 struct inpcbinfo ripcbinfo;
103
104 /*
105 * Nominal space allocated to a raw ip socket.
106 */
107 #define RIPSNDQ 8192
108 #define RIPRCVQ 8192
109
110 /*
111 * Raw interface to IP protocol.
112 */
113
114 /*
115 * Initialize raw connection block q.
116 */
117 void
118 rip_init()
119 {
120 LIST_INIT(&ripcb);
121 ripcbinfo.listhead = &ripcb;
122 /*
123 * XXX We don't use the hash list for raw IP, but it's easier
124 * to allocate a one entry hash list than it is to check all
125 * over the place for hashbase == NULL.
126 */
127 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
128 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
129
130 ripcbinfo.ipi_zone = (void *) zinit(sizeof(struct inpcb),
131 (4096 * sizeof(struct inpcb)),
132 4096, "ripzone");
133
134 }
135
136 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
137 /*
138 * Setup generic address and protocol structures
139 * for raw_input routine, then pass them along with
140 * mbuf chain.
141 */
142 void
143 rip_input(m, iphlen)
144 struct mbuf *m;
145 int iphlen;
146 {
147 register struct ip *ip = mtod(m, struct ip *);
148 register struct inpcb *inp;
149 struct inpcb *last = 0;
150 struct mbuf *opts = 0;
151
152 ripsrc.sin_addr = ip->ip_src;
153 LIST_FOREACH(inp, &ripcb, inp_list) {
154 #if INET6
155 if ((inp->inp_vflag & INP_IPV4) == 0)
156 continue;
157 #endif
158 if (inp->inp_ip_p && (inp->inp_ip_p != ip->ip_p))
159 continue;
160 if (inp->inp_laddr.s_addr &&
161 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
162 continue;
163 if (inp->inp_faddr.s_addr &&
164 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
165 continue;
166 if (last) {
167 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
168
169 #if IPSEC
170 /* check AH/ESP integrity. */
171 if (ipsec_bypass == 0 && n && ipsec4_in_reject_so(n, last->inp_socket)) {
172 m_freem(n);
173 ipsecstat.in_polvio++;
174 /* do not inject data to pcb */
175 } else
176 #endif /*IPSEC*/
177 if (n) {
178 if (last->inp_flags & INP_CONTROLOPTS ||
179 last->inp_socket->so_options & SO_TIMESTAMP)
180 ip_savecontrol(last, &opts, ip, n);
181 if (last->inp_flags & INP_STRIPHDR) {
182 n->m_len -= iphlen;
183 n->m_pkthdr.len -= iphlen;
184 n->m_data += iphlen;
185 }
186 if (sbappendaddr(&last->inp_socket->so_rcv,
187 (struct sockaddr *)&ripsrc, n,
188 opts) == 0) {
189 /* should notify about lost packet */
190 kprintf("rip_input can't append to socket\n");
191 m_freem(n);
192 if (opts)
193 m_freem(opts);
194 } else
195 sorwakeup(last->inp_socket);
196 opts = 0;
197 }
198 }
199 last = inp;
200 }
201 #if IPSEC
202 /* check AH/ESP integrity. */
203 if (ipsec_bypass == 0 && last && ipsec4_in_reject_so(m, last->inp_socket)) {
204 m_freem(m);
205 ipsecstat.in_polvio++;
206 ipstat.ips_delivered--;
207 /* do not inject data to pcb */
208 } else
209 #endif /*IPSEC*/
210 if (last) {
211 if (last->inp_flags & INP_CONTROLOPTS ||
212 last->inp_socket->so_options & SO_TIMESTAMP)
213 ip_savecontrol(last, &opts, ip, m);
214 if (last->inp_flags & INP_STRIPHDR) {
215 m->m_len -= iphlen;
216 m->m_pkthdr.len -= iphlen;
217 m->m_data += iphlen;
218 }
219 if (sbappendaddr(&last->inp_socket->so_rcv,
220 (struct sockaddr *)&ripsrc, m, opts) == 0) {
221 kprintf("rip_input(2) can't append to socket\n");
222 m_freem(m);
223 if (opts)
224 m_freem(opts);
225 } else
226 sorwakeup(last->inp_socket);
227 } else {
228 m_freem(m);
229 ipstat.ips_noproto++;
230 ipstat.ips_delivered--;
231 }
232 }
233
234 /*
235 * Generate IP header and pass packet to ip_output.
236 * Tack on options user may have setup with control call.
237 */
238 int
239 rip_output(m, so, dst)
240 register struct mbuf *m;
241 struct socket *so;
242 u_long dst;
243 {
244 register struct ip *ip;
245 register struct inpcb *inp = sotoinpcb(so);
246 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
247
248 /*
249 * If the user handed us a complete IP packet, use it.
250 * Otherwise, allocate an mbuf for a header and fill it in.
251 */
252 if ((inp->inp_flags & INP_HDRINCL) == 0) {
253 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
254 m_freem(m);
255 return(EMSGSIZE);
256 }
257 M_PREPEND(m, sizeof(struct ip), M_WAIT);
258 ip = mtod(m, struct ip *);
259 ip->ip_tos = inp->inp_ip_tos;
260 ip->ip_off = 0;
261 ip->ip_p = inp->inp_ip_p;
262 ip->ip_len = m->m_pkthdr.len;
263 ip->ip_src = inp->inp_laddr;
264 ip->ip_dst.s_addr = dst;
265 ip->ip_ttl = inp->inp_ip_ttl;
266 } else {
267 if (m->m_pkthdr.len > IP_MAXPACKET) {
268 m_freem(m);
269 return(EMSGSIZE);
270 }
271 ip = mtod(m, struct ip *);
272 /* don't allow both user specified and setsockopt options,
273 and don't allow packet length sizes that will crash */
274 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
275 && inp->inp_options)
276 || (ip->ip_len > m->m_pkthdr.len)
277 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
278 m_freem(m);
279 return EINVAL;
280 }
281 if (ip->ip_id == 0)
282 #if RANDOM_IP_ID
283 ip->ip_id = ip_randomid();
284 #else
285 ip->ip_id = htons(ip_id++);
286 #endif
287 /* XXX prevent ip_output from overwriting header fields */
288 flags |= IP_RAWOUTPUT;
289 ipstat.ips_rawout++;
290 }
291
292 #if IPSEC
293 if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) {
294 m_freem(m);
295 return ENOBUFS;
296 }
297 #endif /*IPSEC*/
298
299 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
300 inp->inp_moptions));
301 }
302
303 /*
304 * Raw IP socket option processing.
305 */
306 int
307 rip_ctloutput(so, sopt)
308 struct socket *so;
309 struct sockopt *sopt;
310 {
311 struct inpcb *inp = sotoinpcb(so);
312 int error, optval;
313
314 if (sopt->sopt_level != IPPROTO_IP)
315 return (EINVAL);
316
317 error = 0;
318
319 switch (sopt->sopt_dir) {
320 case SOPT_GET:
321 switch (sopt->sopt_name) {
322 case IP_HDRINCL:
323 optval = inp->inp_flags & INP_HDRINCL;
324 error = sooptcopyout(sopt, &optval, sizeof optval);
325 break;
326
327 case IP_STRIPHDR:
328 optval = inp->inp_flags & INP_STRIPHDR;
329 error = sooptcopyout(sopt, &optval, sizeof optval);
330 break;
331
332 case IP_FW_ADD:
333 case IP_FW_GET:
334 case IP_OLD_FW_ADD:
335 case IP_OLD_FW_GET:
336 if (ip_fw_ctl_ptr == 0)
337 error = ENOPROTOOPT;
338 else
339 error = ip_fw_ctl_ptr(sopt);
340 break;
341
342 #if DUMMYNET
343 case IP_DUMMYNET_GET:
344 if (ip_dn_ctl_ptr == NULL)
345 error = ENOPROTOOPT ;
346 else
347 error = ip_dn_ctl_ptr(sopt);
348 break ;
349 #endif /* DUMMYNET */
350
351 case MRT_INIT:
352 case MRT_DONE:
353 case MRT_ADD_VIF:
354 case MRT_DEL_VIF:
355 case MRT_ADD_MFC:
356 case MRT_DEL_MFC:
357 case MRT_VERSION:
358 case MRT_ASSERT:
359 error = ip_mrouter_get(so, sopt);
360 break;
361
362 default:
363 error = ip_ctloutput(so, sopt);
364 break;
365 }
366 break;
367
368 case SOPT_SET:
369 switch (sopt->sopt_name) {
370 case IP_HDRINCL:
371 error = sooptcopyin(sopt, &optval, sizeof optval,
372 sizeof optval);
373 if (error)
374 break;
375 if (optval)
376 inp->inp_flags |= INP_HDRINCL;
377 else
378 inp->inp_flags &= ~INP_HDRINCL;
379 break;
380
381 case IP_STRIPHDR:
382 error = sooptcopyin(sopt, &optval, sizeof optval,
383 sizeof optval);
384 if (error)
385 break;
386 if (optval)
387 inp->inp_flags |= INP_STRIPHDR;
388 else
389 inp->inp_flags &= ~INP_STRIPHDR;
390 break;
391
392
393 case IP_FW_ADD:
394 case IP_FW_DEL:
395 case IP_FW_FLUSH:
396 case IP_FW_ZERO:
397 case IP_FW_RESETLOG:
398 case IP_OLD_FW_ADD:
399 case IP_OLD_FW_DEL:
400 case IP_OLD_FW_FLUSH:
401 case IP_OLD_FW_ZERO:
402 case IP_OLD_FW_RESETLOG:
403 if (ip_fw_ctl_ptr == 0)
404 error = ENOPROTOOPT;
405 else
406 error = ip_fw_ctl_ptr(sopt);
407 break;
408
409 #if DUMMYNET
410 case IP_DUMMYNET_CONFIGURE:
411 case IP_DUMMYNET_DEL:
412 case IP_DUMMYNET_FLUSH:
413 if (ip_dn_ctl_ptr == NULL)
414 error = ENOPROTOOPT ;
415 else
416 error = ip_dn_ctl_ptr(sopt);
417 break ;
418 #endif
419
420 case IP_RSVP_ON:
421 error = ip_rsvp_init(so);
422 break;
423
424 case IP_RSVP_OFF:
425 error = ip_rsvp_done();
426 break;
427
428 /* XXX - should be combined */
429 case IP_RSVP_VIF_ON:
430 error = ip_rsvp_vif_init(so, sopt);
431 break;
432
433 case IP_RSVP_VIF_OFF:
434 error = ip_rsvp_vif_done(so, sopt);
435 break;
436
437 case MRT_INIT:
438 case MRT_DONE:
439 case MRT_ADD_VIF:
440 case MRT_DEL_VIF:
441 case MRT_ADD_MFC:
442 case MRT_DEL_MFC:
443 case MRT_VERSION:
444 case MRT_ASSERT:
445 error = ip_mrouter_set(so, sopt);
446 break;
447
448 default:
449 error = ip_ctloutput(so, sopt);
450 break;
451 }
452 break;
453 }
454
455 return (error);
456 }
457
458 /*
459 * This function exists solely to receive the PRC_IFDOWN messages which
460 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
461 * and calls in_ifadown() to remove all routes corresponding to that address.
462 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
463 * interface routes.
464 */
465 void
466 rip_ctlinput(cmd, sa, vip)
467 int cmd;
468 struct sockaddr *sa;
469 void *vip;
470 {
471 struct in_ifaddr *ia;
472 struct ifnet *ifp;
473 int err;
474 int flags;
475
476 switch (cmd) {
477 case PRC_IFDOWN:
478 for (ia = in_ifaddrhead.tqh_first; ia;
479 ia = ia->ia_link.tqe_next) {
480 if (ia->ia_ifa.ifa_addr == sa
481 && (ia->ia_flags & IFA_ROUTE)) {
482 /*
483 * in_ifscrub kills the interface route.
484 */
485 in_ifscrub(ia->ia_ifp, ia);
486 /*
487 * in_ifadown gets rid of all the rest of
488 * the routes. This is not quite the right
489 * thing to do, but at least if we are running
490 * a routing process they will come back.
491 */
492 in_ifadown(&ia->ia_ifa, 1);
493 break;
494 }
495 }
496 break;
497
498 case PRC_IFUP:
499 for (ia = in_ifaddrhead.tqh_first; ia;
500 ia = ia->ia_link.tqe_next) {
501 if (ia->ia_ifa.ifa_addr == sa)
502 break;
503 }
504 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
505 return;
506 flags = RTF_UP;
507 ifp = ia->ia_ifa.ifa_ifp;
508
509 if ((ifp->if_flags & IFF_LOOPBACK)
510 || (ifp->if_flags & IFF_POINTOPOINT))
511 flags |= RTF_HOST;
512
513 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
514 if (err == 0)
515 ia->ia_flags |= IFA_ROUTE;
516 break;
517 }
518 }
519
520 u_long rip_sendspace = RIPSNDQ;
521 u_long rip_recvspace = RIPRCVQ;
522
523 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
524 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
525 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
526 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
527
528 static int
529 rip_attach(struct socket *so, int proto, struct proc *p)
530 {
531 struct inpcb *inp;
532 int error, s;
533
534 inp = sotoinpcb(so);
535 if (inp)
536 panic("rip_attach");
537 #if __APPLE__
538 if ((so->so_state & SS_PRIV) == 0)
539 return (EPERM);
540 #else
541 if (p && (error = suser(p)) != 0)
542 return error;
543 #endif
544
545 error = soreserve(so, rip_sendspace, rip_recvspace);
546 if (error)
547 return error;
548 s = splnet();
549 error = in_pcballoc(so, &ripcbinfo, p);
550 splx(s);
551 if (error)
552 return error;
553 inp = (struct inpcb *)so->so_pcb;
554 inp->inp_vflag |= INP_IPV4;
555 inp->inp_ip_p = proto;
556 inp->inp_ip_ttl = ip_defttl;
557 return 0;
558 }
559
560 __private_extern__ int
561 rip_detach(struct socket *so)
562 {
563 struct inpcb *inp;
564
565 inp = sotoinpcb(so);
566 if (inp == 0)
567 panic("rip_detach");
568 if (so == ip_mrouter)
569 ip_mrouter_done();
570 ip_rsvp_force_done(so);
571 if (so == ip_rsvpd)
572 ip_rsvp_done();
573 in_pcbdetach(inp);
574 return 0;
575 }
576
577 __private_extern__ int
578 rip_abort(struct socket *so)
579 {
580 soisdisconnected(so);
581 return rip_detach(so);
582 }
583
584 __private_extern__ int
585 rip_disconnect(struct socket *so)
586 {
587 if ((so->so_state & SS_ISCONNECTED) == 0)
588 return ENOTCONN;
589 return rip_abort(so);
590 }
591
592 __private_extern__ int
593 rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
594 {
595 struct inpcb *inp = sotoinpcb(so);
596 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
597
598 if (nam->sa_len != sizeof(*addr))
599 return EINVAL;
600
601 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
602 (addr->sin_family != AF_IMPLINK)) ||
603 (addr->sin_addr.s_addr &&
604 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
605 return EADDRNOTAVAIL;
606 inp->inp_laddr = addr->sin_addr;
607 return 0;
608 }
609
610 __private_extern__ int
611 rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
612 {
613 struct inpcb *inp = sotoinpcb(so);
614 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
615
616 if (nam->sa_len != sizeof(*addr))
617 return EINVAL;
618 if (TAILQ_EMPTY(&ifnet))
619 return EADDRNOTAVAIL;
620 if ((addr->sin_family != AF_INET) &&
621 (addr->sin_family != AF_IMPLINK))
622 return EAFNOSUPPORT;
623 inp->inp_faddr = addr->sin_addr;
624 soisconnected(so);
625 return 0;
626 }
627
628 __private_extern__ int
629 rip_shutdown(struct socket *so)
630 {
631 socantsendmore(so);
632 return 0;
633 }
634
635 __private_extern__ int
636 rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
637 struct mbuf *control, struct proc *p)
638 {
639 struct inpcb *inp = sotoinpcb(so);
640 register u_long dst;
641
642 if (so->so_state & SS_ISCONNECTED) {
643 if (nam) {
644 m_freem(m);
645 return EISCONN;
646 }
647 dst = inp->inp_faddr.s_addr;
648 } else {
649 if (nam == NULL) {
650 m_freem(m);
651 return ENOTCONN;
652 }
653 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
654 }
655 return rip_output(m, so, dst);
656 }
657
658 static int
659 rip_pcblist SYSCTL_HANDLER_ARGS
660 {
661 int error, i, n, s;
662 struct inpcb *inp, **inp_list;
663 inp_gen_t gencnt;
664 struct xinpgen xig;
665
666 /*
667 * The process of preparing the TCB list is too time-consuming and
668 * resource-intensive to repeat twice on every request.
669 */
670 if (req->oldptr == 0) {
671 n = ripcbinfo.ipi_count;
672 req->oldidx = 2 * (sizeof xig)
673 + (n + n/8) * sizeof(struct xinpcb);
674 return 0;
675 }
676
677 if (req->newptr != 0)
678 return EPERM;
679
680 /*
681 * OK, now we're committed to doing something.
682 */
683 s = splnet();
684 gencnt = ripcbinfo.ipi_gencnt;
685 n = ripcbinfo.ipi_count;
686 splx(s);
687
688 xig.xig_len = sizeof xig;
689 xig.xig_count = n;
690 xig.xig_gen = gencnt;
691 xig.xig_sogen = so_gencnt;
692 error = SYSCTL_OUT(req, &xig, sizeof xig);
693 if (error)
694 return error;
695 /*
696 * We are done if there is no pcb
697 */
698 if (n == 0)
699 return 0;
700
701 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
702 if (inp_list == 0)
703 return ENOMEM;
704
705 s = splnet();
706 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
707 inp = inp->inp_list.le_next) {
708 if (inp->inp_gencnt <= gencnt)
709 inp_list[i++] = inp;
710 }
711 splx(s);
712 n = i;
713
714 error = 0;
715 for (i = 0; i < n; i++) {
716 inp = inp_list[i];
717 if (inp->inp_gencnt <= gencnt) {
718 struct xinpcb xi;
719 xi.xi_len = sizeof xi;
720 /* XXX should avoid extra copy */
721 bcopy(inp, &xi.xi_inp, sizeof *inp);
722 if (inp->inp_socket)
723 sotoxsocket(inp->inp_socket, &xi.xi_socket);
724 error = SYSCTL_OUT(req, &xi, sizeof xi);
725 }
726 }
727 if (!error) {
728 /*
729 * Give the user an updated idea of our state.
730 * If the generation differs from what we told
731 * her before, she knows that something happened
732 * while we were processing this request, and it
733 * might be necessary to retry.
734 */
735 s = splnet();
736 xig.xig_gen = ripcbinfo.ipi_gencnt;
737 xig.xig_sogen = so_gencnt;
738 xig.xig_count = ripcbinfo.ipi_count;
739 splx(s);
740 error = SYSCTL_OUT(req, &xig, sizeof xig);
741 }
742 FREE(inp_list, M_TEMP);
743 return error;
744 }
745
746 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
747 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
748
749 struct pr_usrreqs rip_usrreqs = {
750 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
751 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
752 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
753 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
754 in_setsockaddr, sosend, soreceive, sopoll
755 };