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