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