]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/raw_ip.c
175962478c618b86018a89b942fc0641b642652c
[apple/xnu.git] / bsd / netinet / raw_ip.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * Copyright (c) 1982, 1986, 1988, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
63 */
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/kernel.h>
68 #include <sys/malloc.h>
69 #include <sys/mbuf.h>
70 #include <sys/proc.h>
71 #include <sys/domain.h>
72 #include <sys/protosw.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
75 #include <sys/sysctl.h>
76
77 #if __FreeBSD__
78 #include <vm/vm_zone.h>
79 #endif
80
81 #include <net/if.h>
82 #include <net/route.h>
83
84 #define _IP_VHL
85 #include <netinet/in.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/ip.h>
88 #include <netinet/in_pcb.h>
89 #include <netinet/in_var.h>
90 #include <netinet/ip_var.h>
91 #include <netinet/ip_mroute.h>
92
93 #include <netinet/ip_fw.h>
94
95 #if IPSEC
96 #include <netinet6/ipsec.h>
97 #endif /*IPSEC*/
98
99 #if DUMMYNET
100 #include <netinet/ip_dummynet.h>
101 #endif
102
103 #if IPSEC
104 extern int ipsec_bypass;
105 extern lck_mtx_t *sadb_mutex;
106 #endif
107
108 extern u_long route_generation;
109 struct inpcbhead ripcb;
110 struct inpcbinfo ripcbinfo;
111
112 /* control hooks for ipfw and dummynet */
113 ip_fw_ctl_t *ip_fw_ctl_ptr;
114 #if DUMMYNET
115 ip_dn_ctl_t *ip_dn_ctl_ptr;
116 #endif /* DUMMYNET */
117
118 /*
119 * Nominal space allocated to a raw ip socket.
120 */
121 #define RIPSNDQ 8192
122 #define RIPRCVQ 8192
123
124 /*
125 * Raw interface to IP protocol.
126 */
127
128 /*
129 * Initialize raw connection block q.
130 */
131 void
132 rip_init()
133 {
134 struct inpcbinfo *pcbinfo;
135
136 LIST_INIT(&ripcb);
137 ripcbinfo.listhead = &ripcb;
138 /*
139 * XXX We don't use the hash list for raw IP, but it's easier
140 * to allocate a one entry hash list than it is to check all
141 * over the place for hashbase == NULL.
142 */
143 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
144 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
145
146 ripcbinfo.ipi_zone = (void *) zinit(sizeof(struct inpcb),
147 (4096 * sizeof(struct inpcb)),
148 4096, "ripzone");
149
150 pcbinfo = &ripcbinfo;
151 /*
152 * allocate lock group attribute and group for udp pcb mutexes
153 */
154 pcbinfo->mtx_grp_attr = lck_grp_attr_alloc_init();
155
156 pcbinfo->mtx_grp = lck_grp_alloc_init("ripcb", pcbinfo->mtx_grp_attr);
157
158 /*
159 * allocate the lock attribute for udp pcb mutexes
160 */
161 pcbinfo->mtx_attr = lck_attr_alloc_init();
162
163 if ((pcbinfo->mtx = lck_rw_alloc_init(pcbinfo->mtx_grp, pcbinfo->mtx_attr)) == NULL)
164 return; /* pretty much dead if this fails... */
165
166 }
167
168 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
169 /*
170 * Setup generic address and protocol structures
171 * for raw_input routine, then pass them along with
172 * mbuf chain.
173 */
174 void
175 rip_input(m, iphlen)
176 struct mbuf *m;
177 int iphlen;
178 {
179 register struct ip *ip = mtod(m, struct ip *);
180 register struct inpcb *inp;
181 struct inpcb *last = 0;
182 struct mbuf *opts = 0;
183 int skipit;
184
185 ripsrc.sin_addr = ip->ip_src;
186 lck_rw_lock_shared(ripcbinfo.mtx);
187 LIST_FOREACH(inp, &ripcb, inp_list) {
188 #if INET6
189 if ((inp->inp_vflag & INP_IPV4) == 0)
190 continue;
191 #endif
192 if (inp->inp_ip_p && (inp->inp_ip_p != ip->ip_p))
193 continue;
194 if (inp->inp_laddr.s_addr &&
195 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
196 continue;
197 if (inp->inp_faddr.s_addr &&
198 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
199 continue;
200 if (last) {
201 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
202
203 #if IPSEC
204 /* check AH/ESP integrity. */
205 skipit = 0;
206 if (ipsec_bypass == 0 && n) {
207 lck_mtx_lock(sadb_mutex);
208 if (ipsec4_in_reject_so(n, last->inp_socket)) {
209 m_freem(n);
210 ipsecstat.in_polvio++;
211 /* do not inject data to pcb */
212 skipit = 1;
213 }
214 lck_mtx_unlock(sadb_mutex);
215 }
216 #endif /*IPSEC*/
217 if (n && skipit == 0) {
218 int error = 0;
219 if (last->inp_flags & INP_CONTROLOPTS ||
220 last->inp_socket->so_options & SO_TIMESTAMP)
221 ip_savecontrol(last, &opts, ip, n);
222 if (last->inp_flags & INP_STRIPHDR) {
223 n->m_len -= iphlen;
224 n->m_pkthdr.len -= iphlen;
225 n->m_data += iphlen;
226 }
227 // ###LOCK need to lock that socket?
228 if (sbappendaddr(&last->inp_socket->so_rcv,
229 (struct sockaddr *)&ripsrc, n,
230 opts, &error) != 0) {
231 sorwakeup(last->inp_socket);
232 }
233 else {
234 if (error) {
235 /* should notify about lost packet */
236 kprintf("rip_input can't append to socket\n");
237 }
238 }
239 opts = 0;
240 }
241 }
242 last = inp;
243 }
244 lck_rw_done(ripcbinfo.mtx);
245 #if IPSEC
246 /* check AH/ESP integrity. */
247 skipit = 0;
248 if (ipsec_bypass == 0 && last) {
249 lck_mtx_lock(sadb_mutex);
250 if (ipsec4_in_reject_so(m, last->inp_socket)) {
251 m_freem(m);
252 ipsecstat.in_polvio++;
253 ipstat.ips_delivered--;
254 /* do not inject data to pcb */
255 skipit = 1;
256 }
257 lck_mtx_unlock(sadb_mutex);
258 }
259 #endif /*IPSEC*/
260 if (skipit == 0) {
261 if (last) {
262 if (last->inp_flags & INP_CONTROLOPTS ||
263 last->inp_socket->so_options & SO_TIMESTAMP)
264 ip_savecontrol(last, &opts, ip, m);
265 if (last->inp_flags & INP_STRIPHDR) {
266 m->m_len -= iphlen;
267 m->m_pkthdr.len -= iphlen;
268 m->m_data += iphlen;
269 }
270 if (sbappendaddr(&last->inp_socket->so_rcv,
271 (struct sockaddr *)&ripsrc, m, opts, NULL) != 0) {
272 sorwakeup(last->inp_socket);
273 } else {
274 kprintf("rip_input(2) can't append to socket\n");
275 }
276 } else {
277 m_freem(m);
278 ipstat.ips_noproto++;
279 ipstat.ips_delivered--;
280 }
281 }
282 }
283
284 /*
285 * Generate IP header and pass packet to ip_output.
286 * Tack on options user may have setup with control call.
287 */
288 int
289 rip_output(m, so, dst)
290 register struct mbuf *m;
291 struct socket *so;
292 u_long dst;
293 {
294 register struct ip *ip;
295 register struct inpcb *inp = sotoinpcb(so);
296 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
297
298 /*
299 * If the user handed us a complete IP packet, use it.
300 * Otherwise, allocate an mbuf for a header and fill it in.
301 */
302 if ((inp->inp_flags & INP_HDRINCL) == 0) {
303 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
304 m_freem(m);
305 return(EMSGSIZE);
306 }
307 M_PREPEND(m, sizeof(struct ip), M_WAIT);
308 ip = mtod(m, struct ip *);
309 ip->ip_tos = inp->inp_ip_tos;
310 ip->ip_off = 0;
311 ip->ip_p = inp->inp_ip_p;
312 ip->ip_len = m->m_pkthdr.len;
313 ip->ip_src = inp->inp_laddr;
314 ip->ip_dst.s_addr = dst;
315 ip->ip_ttl = inp->inp_ip_ttl;
316 } else {
317 if (m->m_pkthdr.len > IP_MAXPACKET) {
318 m_freem(m);
319 return(EMSGSIZE);
320 }
321 ip = mtod(m, struct ip *);
322 /* don't allow both user specified and setsockopt options,
323 and don't allow packet length sizes that will crash */
324 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
325 && inp->inp_options)
326 || (ip->ip_len > m->m_pkthdr.len)
327 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
328 m_freem(m);
329 return EINVAL;
330 }
331 if (ip->ip_id == 0)
332 #if RANDOM_IP_ID
333 ip->ip_id = ip_randomid();
334 #else
335 ip->ip_id = htons(ip_id++);
336 #endif
337 /* XXX prevent ip_output from overwriting header fields */
338 flags |= IP_RAWOUTPUT;
339 ipstat.ips_rawout++;
340 }
341
342 #if IPSEC
343 if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) {
344 m_freem(m);
345 return ENOBUFS;
346 }
347 #endif /*IPSEC*/
348
349 if (inp->inp_route.ro_rt && inp->inp_route.ro_rt->generation_id != route_generation) {
350 rtfree(inp->inp_route.ro_rt);
351 inp->inp_route.ro_rt = (struct rtentry *)0;
352 }
353
354 return (ip_output_list(m, 0, inp->inp_options, &inp->inp_route, flags,
355 inp->inp_moptions));
356 }
357
358 extern int
359 load_ipfw()
360 {
361 kern_return_t err;
362
363 ipfw_init();
364
365 #if DUMMYNET
366 if (!DUMMYNET_LOADED)
367 ip_dn_init();
368 #endif /* DUMMYNET */
369 err = 0;
370
371 return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
372 }
373
374 /*
375 * Raw IP socket option processing.
376 */
377 int
378 rip_ctloutput(so, sopt)
379 struct socket *so;
380 struct sockopt *sopt;
381 {
382 struct inpcb *inp = sotoinpcb(so);
383 int error, optval;
384
385 if (sopt->sopt_level != IPPROTO_IP)
386 return (EINVAL);
387
388 error = 0;
389
390 switch (sopt->sopt_dir) {
391 case SOPT_GET:
392 switch (sopt->sopt_name) {
393 case IP_HDRINCL:
394 optval = inp->inp_flags & INP_HDRINCL;
395 error = sooptcopyout(sopt, &optval, sizeof optval);
396 break;
397
398 case IP_STRIPHDR:
399 optval = inp->inp_flags & INP_STRIPHDR;
400 error = sooptcopyout(sopt, &optval, sizeof optval);
401 break;
402
403 case IP_FW_ADD:
404 case IP_FW_GET:
405 case IP_OLD_FW_ADD:
406 case IP_OLD_FW_GET:
407 if (ip_fw_ctl_ptr == 0)
408 error = load_ipfw();
409 if (ip_fw_ctl_ptr && error == 0)
410 error = ip_fw_ctl_ptr(sopt);
411 else
412 error = ENOPROTOOPT;
413 break;
414
415 #if DUMMYNET
416 case IP_DUMMYNET_GET:
417 if (DUMMYNET_LOADED)
418 error = ip_dn_ctl_ptr(sopt);
419 else
420 error = ENOPROTOOPT;
421 break ;
422 #endif /* DUMMYNET */
423
424 case MRT_INIT:
425 case MRT_DONE:
426 case MRT_ADD_VIF:
427 case MRT_DEL_VIF:
428 case MRT_ADD_MFC:
429 case MRT_DEL_MFC:
430 case MRT_VERSION:
431 case MRT_ASSERT:
432 error = ip_mrouter_get(so, sopt);
433 break;
434
435 default:
436 error = ip_ctloutput(so, sopt);
437 break;
438 }
439 break;
440
441 case SOPT_SET:
442 switch (sopt->sopt_name) {
443 case IP_HDRINCL:
444 error = sooptcopyin(sopt, &optval, sizeof optval,
445 sizeof optval);
446 if (error)
447 break;
448 if (optval)
449 inp->inp_flags |= INP_HDRINCL;
450 else
451 inp->inp_flags &= ~INP_HDRINCL;
452 break;
453
454 case IP_STRIPHDR:
455 error = sooptcopyin(sopt, &optval, sizeof optval,
456 sizeof optval);
457 if (error)
458 break;
459 if (optval)
460 inp->inp_flags |= INP_STRIPHDR;
461 else
462 inp->inp_flags &= ~INP_STRIPHDR;
463 break;
464
465
466 case IP_FW_ADD:
467 case IP_FW_DEL:
468 case IP_FW_FLUSH:
469 case IP_FW_ZERO:
470 case IP_FW_RESETLOG:
471 case IP_OLD_FW_ADD:
472 case IP_OLD_FW_DEL:
473 case IP_OLD_FW_FLUSH:
474 case IP_OLD_FW_ZERO:
475 case IP_OLD_FW_RESETLOG:
476 if (ip_fw_ctl_ptr == 0)
477 error = load_ipfw();
478 if (ip_fw_ctl_ptr && error == 0)
479 error = ip_fw_ctl_ptr(sopt);
480 else
481 error = ENOPROTOOPT;
482 break;
483
484 #if DUMMYNET
485 case IP_DUMMYNET_CONFIGURE:
486 case IP_DUMMYNET_DEL:
487 case IP_DUMMYNET_FLUSH:
488 if (DUMMYNET_LOADED)
489 error = ip_dn_ctl_ptr(sopt);
490 else
491 error = ENOPROTOOPT ;
492 break ;
493 #endif
494
495 case IP_RSVP_ON:
496 error = ip_rsvp_init(so);
497 break;
498
499 case IP_RSVP_OFF:
500 error = ip_rsvp_done();
501 break;
502
503 /* XXX - should be combined */
504 case IP_RSVP_VIF_ON:
505 error = ip_rsvp_vif_init(so, sopt);
506 break;
507
508 case IP_RSVP_VIF_OFF:
509 error = ip_rsvp_vif_done(so, sopt);
510 break;
511
512 case MRT_INIT:
513 case MRT_DONE:
514 case MRT_ADD_VIF:
515 case MRT_DEL_VIF:
516 case MRT_ADD_MFC:
517 case MRT_DEL_MFC:
518 case MRT_VERSION:
519 case MRT_ASSERT:
520 error = ip_mrouter_set(so, sopt);
521 break;
522
523 default:
524 error = ip_ctloutput(so, sopt);
525 break;
526 }
527 break;
528 }
529
530 return (error);
531 }
532
533 /*
534 * This function exists solely to receive the PRC_IFDOWN messages which
535 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
536 * and calls in_ifadown() to remove all routes corresponding to that address.
537 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
538 * interface routes.
539 */
540 void
541 rip_ctlinput(cmd, sa, vip)
542 int cmd;
543 struct sockaddr *sa;
544 void *vip;
545 {
546 struct in_ifaddr *ia;
547 struct ifnet *ifp;
548 int err;
549 int flags;
550
551 switch (cmd) {
552 case PRC_IFDOWN:
553 lck_mtx_lock(rt_mtx);
554 for (ia = in_ifaddrhead.tqh_first; ia;
555 ia = ia->ia_link.tqe_next) {
556 if (ia->ia_ifa.ifa_addr == sa
557 && (ia->ia_flags & IFA_ROUTE)) {
558 /*
559 * in_ifscrub kills the interface route.
560 */
561 in_ifscrub(ia->ia_ifp, ia, 1);
562 /*
563 * in_ifadown gets rid of all the rest of
564 * the routes. This is not quite the right
565 * thing to do, but at least if we are running
566 * a routing process they will come back.
567 */
568 in_ifadown(&ia->ia_ifa, 1);
569 break;
570 }
571 }
572 lck_mtx_unlock(rt_mtx);
573 break;
574
575 case PRC_IFUP:
576 lck_mtx_lock(rt_mtx);
577 for (ia = in_ifaddrhead.tqh_first; ia;
578 ia = ia->ia_link.tqe_next) {
579 if (ia->ia_ifa.ifa_addr == sa)
580 break;
581 }
582 if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) {
583 lck_mtx_unlock(rt_mtx);
584 return;
585 }
586 flags = RTF_UP;
587 ifp = ia->ia_ifa.ifa_ifp;
588
589 if ((ifp->if_flags & IFF_LOOPBACK)
590 || (ifp->if_flags & IFF_POINTOPOINT))
591 flags |= RTF_HOST;
592
593 err = rtinit_locked(&ia->ia_ifa, RTM_ADD, flags);
594 lck_mtx_unlock(rt_mtx);
595 if (err == 0)
596 ia->ia_flags |= IFA_ROUTE;
597 break;
598 }
599 }
600
601 u_long rip_sendspace = RIPSNDQ;
602 u_long rip_recvspace = RIPRCVQ;
603
604 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
605 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
606 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
607 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
608
609 static int
610 rip_attach(struct socket *so, int proto, struct proc *p)
611 {
612 struct inpcb *inp;
613 int error, s;
614
615 inp = sotoinpcb(so);
616 if (inp)
617 panic("rip_attach");
618 #if __APPLE__
619 if ((so->so_state & SS_PRIV) == 0)
620 return (EPERM);
621 #else
622 if (p && (error = suser(p)) != 0)
623 return error;
624 #endif
625
626 error = soreserve(so, rip_sendspace, rip_recvspace);
627 if (error)
628 return error;
629 s = splnet();
630 error = in_pcballoc(so, &ripcbinfo, p);
631 splx(s);
632 if (error)
633 return error;
634 inp = (struct inpcb *)so->so_pcb;
635 inp->inp_vflag |= INP_IPV4;
636 inp->inp_ip_p = proto;
637 inp->inp_ip_ttl = ip_defttl;
638 return 0;
639 }
640
641 __private_extern__ int
642 rip_detach(struct socket *so)
643 {
644 struct inpcb *inp;
645
646 inp = sotoinpcb(so);
647 if (inp == 0)
648 panic("rip_detach");
649 if (so == ip_mrouter)
650 ip_mrouter_done();
651 ip_rsvp_force_done(so);
652 if (so == ip_rsvpd)
653 ip_rsvp_done();
654 in_pcbdetach(inp);
655 return 0;
656 }
657
658 __private_extern__ int
659 rip_abort(struct socket *so)
660 {
661 soisdisconnected(so);
662 return rip_detach(so);
663 }
664
665 __private_extern__ int
666 rip_disconnect(struct socket *so)
667 {
668 if ((so->so_state & SS_ISCONNECTED) == 0)
669 return ENOTCONN;
670 return rip_abort(so);
671 }
672
673 __private_extern__ int
674 rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
675 {
676 struct inpcb *inp = sotoinpcb(so);
677 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
678 struct ifaddr *ifa = NULL;
679
680 if (nam->sa_len != sizeof(*addr))
681 return EINVAL;
682
683 if (TAILQ_EMPTY(&ifnet_head) || ((addr->sin_family != AF_INET) &&
684 (addr->sin_family != AF_IMPLINK)) ||
685 (addr->sin_addr.s_addr &&
686 (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
687 return EADDRNOTAVAIL;
688 }
689 else if (ifa) {
690 ifafree(ifa);
691 ifa = NULL;
692 }
693 inp->inp_laddr = addr->sin_addr;
694 return 0;
695 }
696
697 __private_extern__ int
698 rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
699 {
700 struct inpcb *inp = sotoinpcb(so);
701 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
702
703 if (nam->sa_len != sizeof(*addr))
704 return EINVAL;
705 if (TAILQ_EMPTY(&ifnet_head))
706 return EADDRNOTAVAIL;
707 if ((addr->sin_family != AF_INET) &&
708 (addr->sin_family != AF_IMPLINK))
709 return EAFNOSUPPORT;
710 inp->inp_faddr = addr->sin_addr;
711 soisconnected(so);
712 return 0;
713 }
714
715 __private_extern__ int
716 rip_shutdown(struct socket *so)
717 {
718 socantsendmore(so);
719 return 0;
720 }
721
722 __private_extern__ int
723 rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
724 struct mbuf *control, struct proc *p)
725 {
726 struct inpcb *inp = sotoinpcb(so);
727 register u_long dst;
728
729 if (so->so_state & SS_ISCONNECTED) {
730 if (nam) {
731 m_freem(m);
732 return EISCONN;
733 }
734 dst = inp->inp_faddr.s_addr;
735 } else {
736 if (nam == NULL) {
737 m_freem(m);
738 return ENOTCONN;
739 }
740 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
741 }
742 return rip_output(m, so, dst);
743 }
744
745 /* note: rip_unlock is called from different protos instead of the generic socket_unlock,
746 * it will handle the socket dealloc on last reference
747 * */
748 int
749 rip_unlock(struct socket *so, int refcount, int debug)
750 {
751 int lr_saved;
752 struct inpcb *inp = sotoinpcb(so);
753
754 if (debug == 0)
755 lr_saved = (unsigned int) __builtin_return_address(0);
756 else lr_saved = debug;
757
758 if (refcount) {
759 if (so->so_usecount <= 0)
760 panic("rip_unlock: bad refoucnt so=%x val=%x\n", so, so->so_usecount);
761 so->so_usecount--;
762 if (so->so_usecount == 0 && (inp->inp_wantcnt == WNT_STOPUSING)) {
763 /* cleanup after last reference */
764 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
765 lck_rw_lock_exclusive(ripcbinfo.mtx);
766 in_pcbdispose(inp);
767 lck_rw_done(ripcbinfo.mtx);
768 return(0);
769 }
770 }
771 so->unlock_lr[so->next_unlock_lr] = (u_int *)lr_saved;
772 so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX;
773 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
774 return(0);
775 }
776
777 static int
778 rip_pcblist SYSCTL_HANDLER_ARGS
779 {
780 int error, i, n, s;
781 struct inpcb *inp, **inp_list;
782 inp_gen_t gencnt;
783 struct xinpgen xig;
784
785 /*
786 * The process of preparing the TCB list is too time-consuming and
787 * resource-intensive to repeat twice on every request.
788 */
789 lck_rw_lock_exclusive(ripcbinfo.mtx);
790 if (req->oldptr == USER_ADDR_NULL) {
791 n = ripcbinfo.ipi_count;
792 req->oldidx = 2 * (sizeof xig)
793 + (n + n/8) * sizeof(struct xinpcb);
794 lck_rw_done(ripcbinfo.mtx);
795 return 0;
796 }
797
798 if (req->newptr != USER_ADDR_NULL) {
799 lck_rw_done(ripcbinfo.mtx);
800 return EPERM;
801 }
802
803 /*
804 * OK, now we're committed to doing something.
805 */
806 gencnt = ripcbinfo.ipi_gencnt;
807 n = ripcbinfo.ipi_count;
808
809 bzero(&xig, sizeof(xig));
810 xig.xig_len = sizeof xig;
811 xig.xig_count = n;
812 xig.xig_gen = gencnt;
813 xig.xig_sogen = so_gencnt;
814 error = SYSCTL_OUT(req, &xig, sizeof xig);
815 if (error) {
816 lck_rw_done(ripcbinfo.mtx);
817 return error;
818 }
819 /*
820 * We are done if there is no pcb
821 */
822 if (n == 0) {
823 lck_rw_done(ripcbinfo.mtx);
824 return 0;
825 }
826
827 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
828 if (inp_list == 0) {
829 lck_rw_done(ripcbinfo.mtx);
830 return ENOMEM;
831 }
832
833 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
834 inp = inp->inp_list.le_next) {
835 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
836 inp_list[i++] = inp;
837 }
838 n = i;
839
840 error = 0;
841 for (i = 0; i < n; i++) {
842 inp = inp_list[i];
843 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
844 struct xinpcb xi;
845
846 bzero(&xi, sizeof(xi));
847 xi.xi_len = sizeof xi;
848 /* XXX should avoid extra copy */
849 inpcb_to_compat(inp, &xi.xi_inp);
850 if (inp->inp_socket)
851 sotoxsocket(inp->inp_socket, &xi.xi_socket);
852 error = SYSCTL_OUT(req, &xi, sizeof xi);
853 }
854 }
855 if (!error) {
856 /*
857 * Give the user an updated idea of our state.
858 * If the generation differs from what we told
859 * her before, she knows that something happened
860 * while we were processing this request, and it
861 * might be necessary to retry.
862 */
863 bzero(&xig, sizeof(xig));
864 xig.xig_len = sizeof xig;
865 xig.xig_gen = ripcbinfo.ipi_gencnt;
866 xig.xig_sogen = so_gencnt;
867 xig.xig_count = ripcbinfo.ipi_count;
868 error = SYSCTL_OUT(req, &xig, sizeof xig);
869 }
870 FREE(inp_list, M_TEMP);
871 lck_rw_done(ripcbinfo.mtx);
872 return error;
873 }
874
875 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
876 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
877
878 struct pr_usrreqs rip_usrreqs = {
879 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
880 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
881 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
882 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
883 in_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
884 };