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