]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/raw_ip.c
c305d431f57d18e0f4b8ba24c4e8ea2239eda941
[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 short need_wakeup = 0;
157
158 ripsrc.sin_addr = ip->ip_src;
159 LIST_FOREACH(inp, &ripcb, inp_list) {
160 if ((inp->inp_vflag & INP_IPV4) == NULL)
161 continue;
162 #warning do something about this
163 if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p)
164 continue;
165 if (inp->inp_laddr.s_addr &&
166 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
167 continue;
168 if (inp->inp_faddr.s_addr &&
169 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
170 continue;
171 if (last) {
172 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
173 if (n) {
174 if (last->inp_flags & INP_CONTROLOPTS ||
175 last->inp_socket->so_options & SO_TIMESTAMP)
176 ip_savecontrol(last, &opts, ip, n);
177 if (last->inp_flags & INP_STRIPHDR) {
178 n->m_len -= iphlen;
179 n->m_pkthdr.len -= iphlen;
180 n->m_data += iphlen;
181 }
182 if (sbappendaddr(&last->inp_socket->so_rcv,
183 (struct sockaddr *)&ripsrc, n,
184 opts) == 0) {
185 /* should notify about lost packet */
186 kprintf("rip_input can't append to socket\n");
187 m_freem(n);
188 if (opts)
189 m_freem(opts);
190 } else {
191 /* kprintf("rip_input calling sorwakeup\n"); */
192 need_wakeup++;
193 }
194 opts = 0;
195 }
196 }
197 last = inp;
198 }
199 if (last) {
200 if (last->inp_flags & INP_CONTROLOPTS ||
201 last->inp_socket->so_options & SO_TIMESTAMP)
202 ip_savecontrol(last, &opts, ip, m);
203 if (last->inp_flags & INP_STRIPHDR) {
204 m->m_len -= iphlen;
205 m->m_pkthdr.len -= iphlen;
206 m->m_data += iphlen;
207 }
208 if (sbappendaddr(&last->inp_socket->so_rcv,
209 (struct sockaddr *)&ripsrc, m, opts) == 0) {
210 kprintf("rip_input(2) can't append to socket\n");
211 m_freem(m);
212 if (opts)
213 m_freem(opts);
214 } else {
215 /* kprintf("rip_input calling sorwakeup\n"); */
216 need_wakeup++;
217 }
218 } else {
219 m_freem(m);
220 ipstat.ips_noproto++;
221 ipstat.ips_delivered--;
222 }
223 if (need_wakeup)
224 sorwakeup(last->inp_socket);
225 }
226
227 /*
228 * Generate IP header and pass packet to ip_output.
229 * Tack on options user may have setup with control call.
230 */
231 int
232 rip_output(m, so, dst)
233 register struct mbuf *m;
234 struct socket *so;
235 u_long dst;
236 {
237 register struct ip *ip;
238 register struct inpcb *inp = sotoinpcb(so);
239 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
240
241 /*
242 * If the user handed us a complete IP packet, use it.
243 * Otherwise, allocate an mbuf for a header and fill it in.
244 */
245 if ((inp->inp_flags & INP_HDRINCL) == 0) {
246 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
247 m_freem(m);
248 return(EMSGSIZE);
249 }
250 M_PREPEND(m, sizeof(struct ip), M_WAIT);
251 ip = mtod(m, struct ip *);
252 ip->ip_tos = 0;
253 ip->ip_off = 0;
254 ip->ip_p = inp->inp_ip_p;
255 ip->ip_len = m->m_pkthdr.len;
256 ip->ip_src = inp->inp_laddr;
257 ip->ip_dst.s_addr = dst;
258 ip->ip_ttl = MAXTTL;
259 } else {
260 if (m->m_pkthdr.len > IP_MAXPACKET) {
261 m_freem(m);
262 return(EMSGSIZE);
263 }
264 ip = mtod(m, struct ip *);
265 /* don't allow both user specified and setsockopt options,
266 and don't allow packet length sizes that will crash */
267 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
268 && inp->inp_options)
269 || (ip->ip_len > m->m_pkthdr.len)
270 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
271 m_freem(m);
272 return EINVAL;
273 }
274 if (ip->ip_id == 0)
275 ip->ip_id = htons(ip_id++);
276 /* XXX prevent ip_output from overwriting header fields */
277 flags |= IP_RAWOUTPUT;
278 ipstat.ips_rawout++;
279 }
280
281 #if IPSEC
282 m->m_pkthdr.rcvif = (struct ifnet *)so; /*XXX*/
283 #endif /*IPSEC*/
284
285 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
286 inp->inp_moptions));
287 }
288
289 /*
290 * Raw IP socket option processing.
291 */
292 int
293 rip_ctloutput(so, sopt)
294 struct socket *so;
295 struct sockopt *sopt;
296 {
297 struct inpcb *inp = sotoinpcb(so);
298 int error, optval;
299
300 if (sopt->sopt_level != IPPROTO_IP)
301 return (EINVAL);
302
303 error = 0;
304
305 switch (sopt->sopt_dir) {
306 case SOPT_GET:
307 switch (sopt->sopt_name) {
308 case IP_HDRINCL:
309 optval = inp->inp_flags & INP_HDRINCL;
310 error = sooptcopyout(sopt, &optval, sizeof optval);
311 break;
312
313 case IP_STRIPHDR:
314 optval = inp->inp_flags & INP_STRIPHDR;
315 error = sooptcopyout(sopt, &optval, sizeof optval);
316 break;
317
318 #if COMPAT_IPFW
319 case IP_FW_GET:
320 if (ip_fw_ctl_ptr == 0)
321 error = ENOPROTOOPT;
322 else
323 error = ip_fw_ctl_ptr(sopt);
324 break;
325
326 case IP_NAT:
327 if (ip_nat_ctl_ptr == 0)
328 error = ENOPROTOOPT;
329 else
330 error = ip_nat_ctl_ptr(sopt);
331 break;
332 #if DUMMYNET
333 case IP_DUMMYNET_GET:
334 if (ip_dn_ctl_ptr == NULL)
335 error = ENOPROTOOPT ;
336 else
337 error = ip_dn_ctl_ptr(sopt);
338 break ;
339 #endif /* DUMMYNET */
340 #endif /* COMPAT_IPFW */
341
342 case MRT_INIT:
343 case MRT_DONE:
344 case MRT_ADD_VIF:
345 case MRT_DEL_VIF:
346 case MRT_ADD_MFC:
347 case MRT_DEL_MFC:
348 case MRT_VERSION:
349 case MRT_ASSERT:
350 error = ip_mrouter_get(so, sopt);
351 break;
352
353 default:
354 error = ip_ctloutput(so, sopt);
355 break;
356 }
357 break;
358
359 case SOPT_SET:
360 switch (sopt->sopt_name) {
361 case IP_HDRINCL:
362 error = sooptcopyin(sopt, &optval, sizeof optval,
363 sizeof optval);
364 if (error)
365 break;
366 if (optval)
367 inp->inp_flags |= INP_HDRINCL;
368 else
369 inp->inp_flags &= ~INP_HDRINCL;
370 break;
371
372 case IP_STRIPHDR:
373 error = sooptcopyin(sopt, &optval, sizeof optval,
374 sizeof optval);
375 if (error)
376 break;
377 if (optval)
378 inp->inp_flags |= INP_STRIPHDR;
379 else
380 inp->inp_flags &= ~INP_STRIPHDR;
381 break;
382
383
384 #if COMPAT_IPFW
385 case IP_FW_ADD:
386 case IP_FW_DEL:
387 case IP_FW_FLUSH:
388 case IP_FW_ZERO:
389 if (ip_fw_ctl_ptr == 0)
390 error = ENOPROTOOPT;
391 else
392 error = ip_fw_ctl_ptr(sopt);
393 break;
394
395 case IP_NAT:
396 if (ip_nat_ctl_ptr == 0)
397 error = ENOPROTOOPT;
398 else
399 error = ip_nat_ctl_ptr(sopt);
400 break;
401 #if DUMMYNET
402 case IP_DUMMYNET_CONFIGURE:
403 case IP_DUMMYNET_DEL:
404 case IP_DUMMYNET_FLUSH:
405 if (ip_dn_ctl_ptr == NULL)
406 error = ENOPROTOOPT ;
407 else
408 error = ip_dn_ctl_ptr(sopt);
409 break ;
410 #endif
411 #endif /* COMPAT_IPFW */
412
413 case IP_RSVP_ON:
414 error = ip_rsvp_init(so);
415 break;
416
417 case IP_RSVP_OFF:
418 error = ip_rsvp_done();
419 break;
420
421 /* XXX - should be combined */
422 case IP_RSVP_VIF_ON:
423 error = ip_rsvp_vif_init(so, sopt);
424 break;
425
426 case IP_RSVP_VIF_OFF:
427 error = ip_rsvp_vif_done(so, sopt);
428 break;
429
430 case MRT_INIT:
431 case MRT_DONE:
432 case MRT_ADD_VIF:
433 case MRT_DEL_VIF:
434 case MRT_ADD_MFC:
435 case MRT_DEL_MFC:
436 case MRT_VERSION:
437 case MRT_ASSERT:
438 error = ip_mrouter_set(so, sopt);
439 break;
440
441 default:
442 error = ip_ctloutput(so, sopt);
443 break;
444 }
445 break;
446 }
447
448 return (error);
449 }
450
451 /*
452 * This function exists solely to receive the PRC_IFDOWN messages which
453 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
454 * and calls in_ifadown() to remove all routes corresponding to that address.
455 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
456 * interface routes.
457 */
458 void
459 rip_ctlinput(cmd, sa, vip)
460 int cmd;
461 struct sockaddr *sa;
462 void *vip;
463 {
464 struct in_ifaddr *ia;
465 struct ifnet *ifp;
466 int err;
467 int flags;
468
469 switch (cmd) {
470 case PRC_IFDOWN:
471 for (ia = in_ifaddrhead.tqh_first; ia;
472 ia = ia->ia_link.tqe_next) {
473 if (ia->ia_ifa.ifa_addr == sa
474 && (ia->ia_flags & IFA_ROUTE)) {
475 /*
476 * in_ifscrub kills the interface route.
477 */
478 in_ifscrub(ia->ia_ifp, ia);
479 /*
480 * in_ifadown gets rid of all the rest of
481 * the routes. This is not quite the right
482 * thing to do, but at least if we are running
483 * a routing process they will come back.
484 */
485 in_ifadown(&ia->ia_ifa);
486 break;
487 }
488 }
489 break;
490
491 case PRC_IFUP:
492 for (ia = in_ifaddrhead.tqh_first; ia;
493 ia = ia->ia_link.tqe_next) {
494 if (ia->ia_ifa.ifa_addr == sa)
495 break;
496 }
497 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
498 return;
499 flags = RTF_UP;
500 ifp = ia->ia_ifa.ifa_ifp;
501
502 if ((ifp->if_flags & IFF_LOOPBACK)
503 || (ifp->if_flags & IFF_POINTOPOINT))
504 flags |= RTF_HOST;
505
506 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
507 if (err == 0)
508 ia->ia_flags |= IFA_ROUTE;
509 break;
510 }
511 }
512
513 u_long rip_sendspace = RIPSNDQ;
514 u_long rip_recvspace = RIPRCVQ;
515
516 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, &rip_sendspace,
517 0, "");
518 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, &rip_recvspace,
519 0, "");
520
521 static int
522 rip_attach(struct socket *so, int proto, struct proc *p)
523 {
524 struct inpcb *inp;
525 int error, s;
526
527 inp = sotoinpcb(so);
528 if (inp)
529 panic("rip_attach");
530
531
532 #if ISFB31
533 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
534 return error;
535 #else
536 if ((so->so_state & SS_PRIV) == 0)
537 return (EPERM);
538 #endif
539
540 s = splnet();
541 error = in_pcballoc(so, &ripcbinfo, p);
542 splx(s);
543 if (error)
544 return error;
545 error = soreserve(so, rip_sendspace, rip_recvspace);
546 if (error)
547 return error;
548 inp = (struct inpcb *)so->so_pcb;
549 inp->inp_vflag |= INP_IPV4;
550 inp->inp_ip_p = proto;
551 #if IPSEC
552 error = ipsec_init_policy(so, &inp->inp_sp);
553 if (error != 0) {
554 in_pcbdetach(inp);
555 return error;
556 }
557 #endif /*IPSEC*/
558
559 return 0;
560 }
561
562 static int
563 rip_detach(struct socket *so)
564 {
565 struct inpcb *inp;
566
567 inp = sotoinpcb(so);
568 if (inp == 0)
569 panic("rip_detach");
570 if (so == ip_mrouter)
571 ip_mrouter_done();
572 ip_rsvp_force_done(so);
573 if (so == ip_rsvpd)
574 ip_rsvp_done();
575 in_pcbdetach(inp);
576 return 0;
577 }
578
579 static int
580 rip_abort(struct socket *so)
581 {
582 soisdisconnected(so);
583 return rip_detach(so);
584 }
585
586 static int
587 rip_disconnect(struct socket *so)
588 {
589 if ((so->so_state & SS_ISCONNECTED) == 0)
590 return ENOTCONN;
591 return rip_abort(so);
592 }
593
594 static int
595 rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
596 {
597 struct inpcb *inp = sotoinpcb(so);
598 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
599
600 if (nam->sa_len != sizeof(*addr))
601 return EINVAL;
602
603 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
604 (addr->sin_family != AF_IMPLINK)) ||
605 (addr->sin_addr.s_addr &&
606 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
607 return EADDRNOTAVAIL;
608 inp->inp_laddr = addr->sin_addr;
609 return 0;
610 }
611
612 static int
613 rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
614 {
615 struct inpcb *inp = sotoinpcb(so);
616 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
617
618 if (nam->sa_len != sizeof(*addr))
619 return EINVAL;
620 if (TAILQ_EMPTY(&ifnet))
621 return EADDRNOTAVAIL;
622 if ((addr->sin_family != AF_INET) &&
623 (addr->sin_family != AF_IMPLINK))
624 return EAFNOSUPPORT;
625 inp->inp_faddr = addr->sin_addr;
626 soisconnected(so);
627 return 0;
628 }
629
630 static int
631 rip_shutdown(struct socket *so)
632 {
633 socantsendmore(so);
634 return 0;
635 }
636
637 static int
638 rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
639 struct mbuf *control, struct proc *p)
640 {
641 struct inpcb *inp = sotoinpcb(so);
642 register u_long dst;
643
644 if (so->so_state & SS_ISCONNECTED) {
645 if (nam) {
646 m_freem(m);
647 return EISCONN;
648 }
649 dst = inp->inp_faddr.s_addr;
650 } else {
651 if (nam == NULL) {
652 m_freem(m);
653 return ENOTCONN;
654 }
655 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
656 }
657 return rip_output(m, so, dst);
658 }
659
660
661 static int
662 rip_pcblist SYSCTL_HANDLER_ARGS
663 {
664 int error, i, n, s;
665 struct inpcb *inp, **inp_list;
666 inp_gen_t gencnt;
667 struct xinpgen xig;
668
669 /*
670 * The process of preparing the TCB list is too time-consuming and
671 * resource-intensive to repeat twice on every request.
672 */
673 if (req->oldptr == 0) {
674 n = ripcbinfo.ipi_count;
675 req->oldidx = 2 * (sizeof xig)
676 + (n + n/8) * sizeof(struct xinpcb);
677 return 0;
678 }
679
680 if (req->newptr != 0)
681 return EPERM;
682
683 /*
684 * OK, now we're committed to doing something.
685 */
686 s = splnet();
687 gencnt = ripcbinfo.ipi_gencnt;
688 n = ripcbinfo.ipi_count;
689 splx(s);
690
691 xig.xig_len = sizeof xig;
692 xig.xig_count = n;
693 xig.xig_gen = gencnt;
694 xig.xig_sogen = so_gencnt;
695 error = SYSCTL_OUT(req, &xig, sizeof xig);
696 if (error)
697 return error;
698
699 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
700 if (inp_list == 0)
701 return ENOMEM;
702
703 s = splnet();
704 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
705 inp = inp->inp_list.le_next) {
706 if (inp->inp_gencnt <= gencnt)
707 inp_list[i++] = inp;
708 }
709 splx(s);
710 n = i;
711
712 error = 0;
713 for (i = 0; i < n; i++) {
714 inp = inp_list[i];
715 if (inp->inp_gencnt <= gencnt) {
716 struct xinpcb xi;
717 xi.xi_len = sizeof xi;
718 /* XXX should avoid extra copy */
719 bcopy(inp, &xi.xi_inp, sizeof *inp);
720 if (inp->inp_socket)
721 sotoxsocket(inp->inp_socket, &xi.xi_socket);
722 error = SYSCTL_OUT(req, &xi, sizeof xi);
723 }
724 }
725 if (!error) {
726 /*
727 * Give the user an updated idea of our state.
728 * If the generation differs from what we told
729 * her before, she knows that something happened
730 * while we were processing this request, and it
731 * might be necessary to retry.
732 */
733 s = splnet();
734 xig.xig_gen = ripcbinfo.ipi_gencnt;
735 xig.xig_sogen = so_gencnt;
736 xig.xig_count = ripcbinfo.ipi_count;
737 splx(s);
738 error = SYSCTL_OUT(req, &xig, sizeof xig);
739 }
740 FREE(inp_list, M_TEMP);
741 return error;
742 }
743
744
745 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
746 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
747
748 struct pr_usrreqs rip_usrreqs = {
749 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
750 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
751 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
752 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
753 in_setsockaddr, sosend, soreceive, sopoll
754 };