]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/raw_ip.c
xnu-517.9.4.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 *
e5568f75
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 *
e5568f75
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,
e5568f75
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
55e303ae
A
300int
301load_ipfw()
302{
303 kern_return_t err;
304
305 /* Load the kext by the identifier */
306 err = kmod_load_extension("com.apple.nke.IPFirewall");
307 if (err) return err;
308
309 if (ip_fw_ctl_ptr == NULL) {
310 /* Wait for the kext to finish loading */
311 err = tsleep(&ip_fw_ctl_ptr, PWAIT | PCATCH, "load_ipfw_kext", 5 * 60 /* 5 seconds */);
312 }
313
314 return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
315}
316
1c79356b
A
317/*
318 * Raw IP socket option processing.
319 */
320int
321rip_ctloutput(so, sopt)
322 struct socket *so;
323 struct sockopt *sopt;
324{
325 struct inpcb *inp = sotoinpcb(so);
326 int error, optval;
327
328 if (sopt->sopt_level != IPPROTO_IP)
329 return (EINVAL);
330
331 error = 0;
332
333 switch (sopt->sopt_dir) {
334 case SOPT_GET:
335 switch (sopt->sopt_name) {
336 case IP_HDRINCL:
337 optval = inp->inp_flags & INP_HDRINCL;
338 error = sooptcopyout(sopt, &optval, sizeof optval);
339 break;
340
341 case IP_STRIPHDR:
342 optval = inp->inp_flags & INP_STRIPHDR;
343 error = sooptcopyout(sopt, &optval, sizeof optval);
344 break;
345
9bccf70c 346 case IP_FW_ADD:
1c79356b 347 case IP_FW_GET:
9bccf70c
A
348 case IP_OLD_FW_ADD:
349 case IP_OLD_FW_GET:
1c79356b 350 if (ip_fw_ctl_ptr == 0)
55e303ae
A
351 error = load_ipfw();
352 if (ip_fw_ctl_ptr && error == 0)
1c79356b 353 error = ip_fw_ctl_ptr(sopt);
55e303ae
A
354 else
355 error = ENOPROTOOPT;
1c79356b
A
356 break;
357
1c79356b
A
358#if DUMMYNET
359 case IP_DUMMYNET_GET:
360 if (ip_dn_ctl_ptr == NULL)
361 error = ENOPROTOOPT ;
362 else
363 error = ip_dn_ctl_ptr(sopt);
364 break ;
365#endif /* DUMMYNET */
1c79356b
A
366
367 case MRT_INIT:
368 case MRT_DONE:
369 case MRT_ADD_VIF:
370 case MRT_DEL_VIF:
371 case MRT_ADD_MFC:
372 case MRT_DEL_MFC:
373 case MRT_VERSION:
374 case MRT_ASSERT:
375 error = ip_mrouter_get(so, sopt);
376 break;
377
378 default:
379 error = ip_ctloutput(so, sopt);
380 break;
381 }
382 break;
383
384 case SOPT_SET:
385 switch (sopt->sopt_name) {
386 case IP_HDRINCL:
387 error = sooptcopyin(sopt, &optval, sizeof optval,
388 sizeof optval);
389 if (error)
390 break;
391 if (optval)
392 inp->inp_flags |= INP_HDRINCL;
393 else
394 inp->inp_flags &= ~INP_HDRINCL;
395 break;
396
397 case IP_STRIPHDR:
398 error = sooptcopyin(sopt, &optval, sizeof optval,
399 sizeof optval);
400 if (error)
401 break;
402 if (optval)
403 inp->inp_flags |= INP_STRIPHDR;
404 else
405 inp->inp_flags &= ~INP_STRIPHDR;
406 break;
407
408
1c79356b
A
409 case IP_FW_ADD:
410 case IP_FW_DEL:
411 case IP_FW_FLUSH:
412 case IP_FW_ZERO:
9bccf70c
A
413 case IP_FW_RESETLOG:
414 case IP_OLD_FW_ADD:
415 case IP_OLD_FW_DEL:
416 case IP_OLD_FW_FLUSH:
417 case IP_OLD_FW_ZERO:
418 case IP_OLD_FW_RESETLOG:
1c79356b 419 if (ip_fw_ctl_ptr == 0)
55e303ae
A
420 error = load_ipfw();
421 if (ip_fw_ctl_ptr && error == 0)
1c79356b 422 error = ip_fw_ctl_ptr(sopt);
55e303ae
A
423 else
424 error = ENOPROTOOPT;
1c79356b
A
425 break;
426
1c79356b
A
427#if DUMMYNET
428 case IP_DUMMYNET_CONFIGURE:
429 case IP_DUMMYNET_DEL:
430 case IP_DUMMYNET_FLUSH:
431 if (ip_dn_ctl_ptr == NULL)
432 error = ENOPROTOOPT ;
433 else
434 error = ip_dn_ctl_ptr(sopt);
435 break ;
436#endif
1c79356b
A
437
438 case IP_RSVP_ON:
439 error = ip_rsvp_init(so);
440 break;
441
442 case IP_RSVP_OFF:
443 error = ip_rsvp_done();
444 break;
445
446 /* XXX - should be combined */
447 case IP_RSVP_VIF_ON:
448 error = ip_rsvp_vif_init(so, sopt);
449 break;
450
451 case IP_RSVP_VIF_OFF:
452 error = ip_rsvp_vif_done(so, sopt);
453 break;
454
455 case MRT_INIT:
456 case MRT_DONE:
457 case MRT_ADD_VIF:
458 case MRT_DEL_VIF:
459 case MRT_ADD_MFC:
460 case MRT_DEL_MFC:
461 case MRT_VERSION:
462 case MRT_ASSERT:
463 error = ip_mrouter_set(so, sopt);
464 break;
465
466 default:
467 error = ip_ctloutput(so, sopt);
468 break;
469 }
470 break;
471 }
472
473 return (error);
474}
475
476/*
477 * This function exists solely to receive the PRC_IFDOWN messages which
478 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
479 * and calls in_ifadown() to remove all routes corresponding to that address.
480 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
481 * interface routes.
482 */
483void
484rip_ctlinput(cmd, sa, vip)
485 int cmd;
486 struct sockaddr *sa;
487 void *vip;
488{
489 struct in_ifaddr *ia;
490 struct ifnet *ifp;
491 int err;
492 int flags;
493
494 switch (cmd) {
495 case PRC_IFDOWN:
496 for (ia = in_ifaddrhead.tqh_first; ia;
497 ia = ia->ia_link.tqe_next) {
498 if (ia->ia_ifa.ifa_addr == sa
499 && (ia->ia_flags & IFA_ROUTE)) {
500 /*
501 * in_ifscrub kills the interface route.
502 */
503 in_ifscrub(ia->ia_ifp, ia);
504 /*
505 * in_ifadown gets rid of all the rest of
506 * the routes. This is not quite the right
507 * thing to do, but at least if we are running
508 * a routing process they will come back.
509 */
9bccf70c 510 in_ifadown(&ia->ia_ifa, 1);
1c79356b
A
511 break;
512 }
513 }
514 break;
515
516 case PRC_IFUP:
517 for (ia = in_ifaddrhead.tqh_first; ia;
518 ia = ia->ia_link.tqe_next) {
519 if (ia->ia_ifa.ifa_addr == sa)
520 break;
521 }
522 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
523 return;
524 flags = RTF_UP;
525 ifp = ia->ia_ifa.ifa_ifp;
526
527 if ((ifp->if_flags & IFF_LOOPBACK)
528 || (ifp->if_flags & IFF_POINTOPOINT))
529 flags |= RTF_HOST;
530
531 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
532 if (err == 0)
533 ia->ia_flags |= IFA_ROUTE;
534 break;
535 }
536}
537
538u_long rip_sendspace = RIPSNDQ;
539u_long rip_recvspace = RIPRCVQ;
540
9bccf70c
A
541SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
542 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
543SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
544 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
1c79356b
A
545
546static int
547rip_attach(struct socket *so, int proto, struct proc *p)
548{
549 struct inpcb *inp;
550 int error, s;
551
552 inp = sotoinpcb(so);
553 if (inp)
554 panic("rip_attach");
9bccf70c
A
555#if __APPLE__
556 if ((so->so_state & SS_PRIV) == 0)
557 return (EPERM);
1c79356b 558#else
9bccf70c
A
559 if (p && (error = suser(p)) != 0)
560 return error;
1c79356b
A
561#endif
562
9bccf70c
A
563 error = soreserve(so, rip_sendspace, rip_recvspace);
564 if (error)
565 return error;
1c79356b
A
566 s = splnet();
567 error = in_pcballoc(so, &ripcbinfo, p);
568 splx(s);
1c79356b
A
569 if (error)
570 return error;
571 inp = (struct inpcb *)so->so_pcb;
572 inp->inp_vflag |= INP_IPV4;
573 inp->inp_ip_p = proto;
9bccf70c 574 inp->inp_ip_ttl = ip_defttl;
1c79356b
A
575 return 0;
576}
577
9bccf70c 578__private_extern__ int
1c79356b
A
579rip_detach(struct socket *so)
580{
581 struct inpcb *inp;
582
583 inp = sotoinpcb(so);
584 if (inp == 0)
585 panic("rip_detach");
586 if (so == ip_mrouter)
587 ip_mrouter_done();
588 ip_rsvp_force_done(so);
589 if (so == ip_rsvpd)
590 ip_rsvp_done();
591 in_pcbdetach(inp);
592 return 0;
593}
594
9bccf70c 595__private_extern__ int
1c79356b
A
596rip_abort(struct socket *so)
597{
598 soisdisconnected(so);
599 return rip_detach(so);
600}
601
9bccf70c 602__private_extern__ int
1c79356b
A
603rip_disconnect(struct socket *so)
604{
605 if ((so->so_state & SS_ISCONNECTED) == 0)
606 return ENOTCONN;
607 return rip_abort(so);
608}
609
9bccf70c 610__private_extern__ int
1c79356b
A
611rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
612{
613 struct inpcb *inp = sotoinpcb(so);
614 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
615
616 if (nam->sa_len != sizeof(*addr))
617 return EINVAL;
618
619 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
620 (addr->sin_family != AF_IMPLINK)) ||
621 (addr->sin_addr.s_addr &&
622 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
623 return EADDRNOTAVAIL;
624 inp->inp_laddr = addr->sin_addr;
625 return 0;
626}
627
9bccf70c 628__private_extern__ int
1c79356b
A
629rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
630{
631 struct inpcb *inp = sotoinpcb(so);
632 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
633
634 if (nam->sa_len != sizeof(*addr))
635 return EINVAL;
636 if (TAILQ_EMPTY(&ifnet))
637 return EADDRNOTAVAIL;
638 if ((addr->sin_family != AF_INET) &&
639 (addr->sin_family != AF_IMPLINK))
640 return EAFNOSUPPORT;
641 inp->inp_faddr = addr->sin_addr;
642 soisconnected(so);
643 return 0;
644}
645
9bccf70c 646__private_extern__ int
1c79356b
A
647rip_shutdown(struct socket *so)
648{
649 socantsendmore(so);
650 return 0;
651}
652
9bccf70c 653__private_extern__ int
1c79356b
A
654rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
655 struct mbuf *control, struct proc *p)
656{
657 struct inpcb *inp = sotoinpcb(so);
658 register u_long dst;
659
660 if (so->so_state & SS_ISCONNECTED) {
661 if (nam) {
662 m_freem(m);
663 return EISCONN;
664 }
665 dst = inp->inp_faddr.s_addr;
666 } else {
667 if (nam == NULL) {
668 m_freem(m);
669 return ENOTCONN;
670 }
671 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
672 }
673 return rip_output(m, so, dst);
674}
675
1c79356b
A
676static int
677rip_pcblist SYSCTL_HANDLER_ARGS
678{
679 int error, i, n, s;
680 struct inpcb *inp, **inp_list;
681 inp_gen_t gencnt;
682 struct xinpgen xig;
683
684 /*
685 * The process of preparing the TCB list is too time-consuming and
686 * resource-intensive to repeat twice on every request.
687 */
688 if (req->oldptr == 0) {
689 n = ripcbinfo.ipi_count;
690 req->oldidx = 2 * (sizeof xig)
691 + (n + n/8) * sizeof(struct xinpcb);
692 return 0;
693 }
694
695 if (req->newptr != 0)
696 return EPERM;
697
698 /*
699 * OK, now we're committed to doing something.
700 */
701 s = splnet();
702 gencnt = ripcbinfo.ipi_gencnt;
703 n = ripcbinfo.ipi_count;
704 splx(s);
705
706 xig.xig_len = sizeof xig;
707 xig.xig_count = n;
708 xig.xig_gen = gencnt;
709 xig.xig_sogen = so_gencnt;
710 error = SYSCTL_OUT(req, &xig, sizeof xig);
711 if (error)
712 return error;
9bccf70c
A
713 /*
714 * We are done if there is no pcb
715 */
716 if (n == 0)
717 return 0;
1c79356b
A
718
719 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
720 if (inp_list == 0)
721 return ENOMEM;
722
723 s = splnet();
724 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
725 inp = inp->inp_list.le_next) {
726 if (inp->inp_gencnt <= gencnt)
727 inp_list[i++] = inp;
728 }
729 splx(s);
730 n = i;
731
732 error = 0;
733 for (i = 0; i < n; i++) {
734 inp = inp_list[i];
735 if (inp->inp_gencnt <= gencnt) {
736 struct xinpcb xi;
737 xi.xi_len = sizeof xi;
738 /* XXX should avoid extra copy */
739 bcopy(inp, &xi.xi_inp, sizeof *inp);
740 if (inp->inp_socket)
741 sotoxsocket(inp->inp_socket, &xi.xi_socket);
742 error = SYSCTL_OUT(req, &xi, sizeof xi);
743 }
744 }
745 if (!error) {
746 /*
747 * Give the user an updated idea of our state.
748 * If the generation differs from what we told
749 * her before, she knows that something happened
750 * while we were processing this request, and it
751 * might be necessary to retry.
752 */
753 s = splnet();
754 xig.xig_gen = ripcbinfo.ipi_gencnt;
755 xig.xig_sogen = so_gencnt;
756 xig.xig_count = ripcbinfo.ipi_count;
757 splx(s);
758 error = SYSCTL_OUT(req, &xig, sizeof xig);
759 }
760 FREE(inp_list, M_TEMP);
761 return error;
762}
763
1c79356b
A
764SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
765 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
766
767struct pr_usrreqs rip_usrreqs = {
768 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
769 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
770 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
9bccf70c 771 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
1c79356b
A
772 in_setsockaddr, sosend, soreceive, sopoll
773};