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