]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/raw_ip.c
xnu-517.3.15.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 int
304 load_ipfw()
305 {
306 kern_return_t err;
307
308 /* Load the kext by the identifier */
309 err = kmod_load_extension("com.apple.nke.IPFirewall");
310 if (err) return err;
311
312 if (ip_fw_ctl_ptr == NULL) {
313 /* Wait for the kext to finish loading */
314 err = tsleep(&ip_fw_ctl_ptr, PWAIT | PCATCH, "load_ipfw_kext", 5 * 60 /* 5 seconds */);
315 }
316
317 return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
318 }
319
320 /*
321 * Raw IP socket option processing.
322 */
323 int
324 rip_ctloutput(so, sopt)
325 struct socket *so;
326 struct sockopt *sopt;
327 {
328 struct inpcb *inp = sotoinpcb(so);
329 int error, optval;
330
331 if (sopt->sopt_level != IPPROTO_IP)
332 return (EINVAL);
333
334 error = 0;
335
336 switch (sopt->sopt_dir) {
337 case SOPT_GET:
338 switch (sopt->sopt_name) {
339 case IP_HDRINCL:
340 optval = inp->inp_flags & INP_HDRINCL;
341 error = sooptcopyout(sopt, &optval, sizeof optval);
342 break;
343
344 case IP_STRIPHDR:
345 optval = inp->inp_flags & INP_STRIPHDR;
346 error = sooptcopyout(sopt, &optval, sizeof optval);
347 break;
348
349 case IP_FW_ADD:
350 case IP_FW_GET:
351 case IP_OLD_FW_ADD:
352 case IP_OLD_FW_GET:
353 if (ip_fw_ctl_ptr == 0)
354 error = load_ipfw();
355 if (ip_fw_ctl_ptr && error == 0)
356 error = ip_fw_ctl_ptr(sopt);
357 else
358 error = ENOPROTOOPT;
359 break;
360
361 #if DUMMYNET
362 case IP_DUMMYNET_GET:
363 if (ip_dn_ctl_ptr == NULL)
364 error = ENOPROTOOPT ;
365 else
366 error = ip_dn_ctl_ptr(sopt);
367 break ;
368 #endif /* DUMMYNET */
369
370 case MRT_INIT:
371 case MRT_DONE:
372 case MRT_ADD_VIF:
373 case MRT_DEL_VIF:
374 case MRT_ADD_MFC:
375 case MRT_DEL_MFC:
376 case MRT_VERSION:
377 case MRT_ASSERT:
378 error = ip_mrouter_get(so, sopt);
379 break;
380
381 default:
382 error = ip_ctloutput(so, sopt);
383 break;
384 }
385 break;
386
387 case SOPT_SET:
388 switch (sopt->sopt_name) {
389 case IP_HDRINCL:
390 error = sooptcopyin(sopt, &optval, sizeof optval,
391 sizeof optval);
392 if (error)
393 break;
394 if (optval)
395 inp->inp_flags |= INP_HDRINCL;
396 else
397 inp->inp_flags &= ~INP_HDRINCL;
398 break;
399
400 case IP_STRIPHDR:
401 error = sooptcopyin(sopt, &optval, sizeof optval,
402 sizeof optval);
403 if (error)
404 break;
405 if (optval)
406 inp->inp_flags |= INP_STRIPHDR;
407 else
408 inp->inp_flags &= ~INP_STRIPHDR;
409 break;
410
411
412 case IP_FW_ADD:
413 case IP_FW_DEL:
414 case IP_FW_FLUSH:
415 case IP_FW_ZERO:
416 case IP_FW_RESETLOG:
417 case IP_OLD_FW_ADD:
418 case IP_OLD_FW_DEL:
419 case IP_OLD_FW_FLUSH:
420 case IP_OLD_FW_ZERO:
421 case IP_OLD_FW_RESETLOG:
422 if (ip_fw_ctl_ptr == 0)
423 error = load_ipfw();
424 if (ip_fw_ctl_ptr && error == 0)
425 error = ip_fw_ctl_ptr(sopt);
426 else
427 error = ENOPROTOOPT;
428 break;
429
430 #if DUMMYNET
431 case IP_DUMMYNET_CONFIGURE:
432 case IP_DUMMYNET_DEL:
433 case IP_DUMMYNET_FLUSH:
434 if (ip_dn_ctl_ptr == NULL)
435 error = ENOPROTOOPT ;
436 else
437 error = ip_dn_ctl_ptr(sopt);
438 break ;
439 #endif
440
441 case IP_RSVP_ON:
442 error = ip_rsvp_init(so);
443 break;
444
445 case IP_RSVP_OFF:
446 error = ip_rsvp_done();
447 break;
448
449 /* XXX - should be combined */
450 case IP_RSVP_VIF_ON:
451 error = ip_rsvp_vif_init(so, sopt);
452 break;
453
454 case IP_RSVP_VIF_OFF:
455 error = ip_rsvp_vif_done(so, sopt);
456 break;
457
458 case MRT_INIT:
459 case MRT_DONE:
460 case MRT_ADD_VIF:
461 case MRT_DEL_VIF:
462 case MRT_ADD_MFC:
463 case MRT_DEL_MFC:
464 case MRT_VERSION:
465 case MRT_ASSERT:
466 error = ip_mrouter_set(so, sopt);
467 break;
468
469 default:
470 error = ip_ctloutput(so, sopt);
471 break;
472 }
473 break;
474 }
475
476 return (error);
477 }
478
479 /*
480 * This function exists solely to receive the PRC_IFDOWN messages which
481 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
482 * and calls in_ifadown() to remove all routes corresponding to that address.
483 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
484 * interface routes.
485 */
486 void
487 rip_ctlinput(cmd, sa, vip)
488 int cmd;
489 struct sockaddr *sa;
490 void *vip;
491 {
492 struct in_ifaddr *ia;
493 struct ifnet *ifp;
494 int err;
495 int flags;
496
497 switch (cmd) {
498 case PRC_IFDOWN:
499 for (ia = in_ifaddrhead.tqh_first; ia;
500 ia = ia->ia_link.tqe_next) {
501 if (ia->ia_ifa.ifa_addr == sa
502 && (ia->ia_flags & IFA_ROUTE)) {
503 /*
504 * in_ifscrub kills the interface route.
505 */
506 in_ifscrub(ia->ia_ifp, ia);
507 /*
508 * in_ifadown gets rid of all the rest of
509 * the routes. This is not quite the right
510 * thing to do, but at least if we are running
511 * a routing process they will come back.
512 */
513 in_ifadown(&ia->ia_ifa, 1);
514 break;
515 }
516 }
517 break;
518
519 case PRC_IFUP:
520 for (ia = in_ifaddrhead.tqh_first; ia;
521 ia = ia->ia_link.tqe_next) {
522 if (ia->ia_ifa.ifa_addr == sa)
523 break;
524 }
525 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
526 return;
527 flags = RTF_UP;
528 ifp = ia->ia_ifa.ifa_ifp;
529
530 if ((ifp->if_flags & IFF_LOOPBACK)
531 || (ifp->if_flags & IFF_POINTOPOINT))
532 flags |= RTF_HOST;
533
534 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
535 if (err == 0)
536 ia->ia_flags |= IFA_ROUTE;
537 break;
538 }
539 }
540
541 u_long rip_sendspace = RIPSNDQ;
542 u_long rip_recvspace = RIPRCVQ;
543
544 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
545 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
546 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
547 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
548
549 static int
550 rip_attach(struct socket *so, int proto, struct proc *p)
551 {
552 struct inpcb *inp;
553 int error, s;
554
555 inp = sotoinpcb(so);
556 if (inp)
557 panic("rip_attach");
558 #if __APPLE__
559 if ((so->so_state & SS_PRIV) == 0)
560 return (EPERM);
561 #else
562 if (p && (error = suser(p)) != 0)
563 return error;
564 #endif
565
566 error = soreserve(so, rip_sendspace, rip_recvspace);
567 if (error)
568 return error;
569 s = splnet();
570 error = in_pcballoc(so, &ripcbinfo, p);
571 splx(s);
572 if (error)
573 return error;
574 inp = (struct inpcb *)so->so_pcb;
575 inp->inp_vflag |= INP_IPV4;
576 inp->inp_ip_p = proto;
577 inp->inp_ip_ttl = ip_defttl;
578 return 0;
579 }
580
581 __private_extern__ int
582 rip_detach(struct socket *so)
583 {
584 struct inpcb *inp;
585
586 inp = sotoinpcb(so);
587 if (inp == 0)
588 panic("rip_detach");
589 if (so == ip_mrouter)
590 ip_mrouter_done();
591 ip_rsvp_force_done(so);
592 if (so == ip_rsvpd)
593 ip_rsvp_done();
594 in_pcbdetach(inp);
595 return 0;
596 }
597
598 __private_extern__ int
599 rip_abort(struct socket *so)
600 {
601 soisdisconnected(so);
602 return rip_detach(so);
603 }
604
605 __private_extern__ int
606 rip_disconnect(struct socket *so)
607 {
608 if ((so->so_state & SS_ISCONNECTED) == 0)
609 return ENOTCONN;
610 return rip_abort(so);
611 }
612
613 __private_extern__ int
614 rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
615 {
616 struct inpcb *inp = sotoinpcb(so);
617 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
618
619 if (nam->sa_len != sizeof(*addr))
620 return EINVAL;
621
622 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
623 (addr->sin_family != AF_IMPLINK)) ||
624 (addr->sin_addr.s_addr &&
625 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
626 return EADDRNOTAVAIL;
627 inp->inp_laddr = addr->sin_addr;
628 return 0;
629 }
630
631 __private_extern__ int
632 rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
633 {
634 struct inpcb *inp = sotoinpcb(so);
635 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
636
637 if (nam->sa_len != sizeof(*addr))
638 return EINVAL;
639 if (TAILQ_EMPTY(&ifnet))
640 return EADDRNOTAVAIL;
641 if ((addr->sin_family != AF_INET) &&
642 (addr->sin_family != AF_IMPLINK))
643 return EAFNOSUPPORT;
644 inp->inp_faddr = addr->sin_addr;
645 soisconnected(so);
646 return 0;
647 }
648
649 __private_extern__ int
650 rip_shutdown(struct socket *so)
651 {
652 socantsendmore(so);
653 return 0;
654 }
655
656 __private_extern__ int
657 rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
658 struct mbuf *control, struct proc *p)
659 {
660 struct inpcb *inp = sotoinpcb(so);
661 register u_long dst;
662
663 if (so->so_state & SS_ISCONNECTED) {
664 if (nam) {
665 m_freem(m);
666 return EISCONN;
667 }
668 dst = inp->inp_faddr.s_addr;
669 } else {
670 if (nam == NULL) {
671 m_freem(m);
672 return ENOTCONN;
673 }
674 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
675 }
676 return rip_output(m, so, dst);
677 }
678
679 static int
680 rip_pcblist SYSCTL_HANDLER_ARGS
681 {
682 int error, i, n, s;
683 struct inpcb *inp, **inp_list;
684 inp_gen_t gencnt;
685 struct xinpgen xig;
686
687 /*
688 * The process of preparing the TCB list is too time-consuming and
689 * resource-intensive to repeat twice on every request.
690 */
691 if (req->oldptr == 0) {
692 n = ripcbinfo.ipi_count;
693 req->oldidx = 2 * (sizeof xig)
694 + (n + n/8) * sizeof(struct xinpcb);
695 return 0;
696 }
697
698 if (req->newptr != 0)
699 return EPERM;
700
701 /*
702 * OK, now we're committed to doing something.
703 */
704 s = splnet();
705 gencnt = ripcbinfo.ipi_gencnt;
706 n = ripcbinfo.ipi_count;
707 splx(s);
708
709 xig.xig_len = sizeof xig;
710 xig.xig_count = n;
711 xig.xig_gen = gencnt;
712 xig.xig_sogen = so_gencnt;
713 error = SYSCTL_OUT(req, &xig, sizeof xig);
714 if (error)
715 return error;
716 /*
717 * We are done if there is no pcb
718 */
719 if (n == 0)
720 return 0;
721
722 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
723 if (inp_list == 0)
724 return ENOMEM;
725
726 s = splnet();
727 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
728 inp = inp->inp_list.le_next) {
729 if (inp->inp_gencnt <= gencnt)
730 inp_list[i++] = inp;
731 }
732 splx(s);
733 n = i;
734
735 error = 0;
736 for (i = 0; i < n; i++) {
737 inp = inp_list[i];
738 if (inp->inp_gencnt <= gencnt) {
739 struct xinpcb xi;
740 xi.xi_len = sizeof xi;
741 /* XXX should avoid extra copy */
742 bcopy(inp, &xi.xi_inp, sizeof *inp);
743 if (inp->inp_socket)
744 sotoxsocket(inp->inp_socket, &xi.xi_socket);
745 error = SYSCTL_OUT(req, &xi, sizeof xi);
746 }
747 }
748 if (!error) {
749 /*
750 * Give the user an updated idea of our state.
751 * If the generation differs from what we told
752 * her before, she knows that something happened
753 * while we were processing this request, and it
754 * might be necessary to retry.
755 */
756 s = splnet();
757 xig.xig_gen = ripcbinfo.ipi_gencnt;
758 xig.xig_sogen = so_gencnt;
759 xig.xig_count = ripcbinfo.ipi_count;
760 splx(s);
761 error = SYSCTL_OUT(req, &xig, sizeof xig);
762 }
763 FREE(inp_list, M_TEMP);
764 return error;
765 }
766
767 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
768 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
769
770 struct pr_usrreqs rip_usrreqs = {
771 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
772 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
773 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
774 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
775 in_setsockaddr, sosend, soreceive, sopoll
776 };