]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/raw_ip.c
fd2ae4fe60492de7354e551f5fea43710c1450d5
[apple/xnu.git] / bsd / netinet / raw_ip.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1982, 1986, 1988, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
61 */
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67 #include <sys/mbuf.h>
68 #include <sys/proc.h>
69 #include <sys/domain.h>
70 #include <sys/protosw.h>
71 #include <sys/socket.h>
72 #include <sys/socketvar.h>
73 #include <sys/sysctl.h>
74
75 #if __FreeBSD__
76 #include <vm/vm_zone.h>
77 #endif
78
79 #include <net/if.h>
80 #include <net/route.h>
81
82 #define _IP_VHL
83 #include <netinet/in.h>
84 #include <netinet/in_systm.h>
85 #include <netinet/ip.h>
86 #include <netinet/in_pcb.h>
87 #include <netinet/in_var.h>
88 #include <netinet/ip_var.h>
89 #include <netinet/ip_mroute.h>
90
91 #include <netinet/ip_fw.h>
92
93 #if IPSEC
94 #include <netinet6/ipsec.h>
95 #endif /*IPSEC*/
96
97 #if DUMMYNET
98 #include <netinet/ip_dummynet.h>
99 #endif
100
101 #if IPSEC
102 extern int ipsec_bypass;
103 extern lck_mtx_t *sadb_mutex;
104 #endif
105
106 extern u_long route_generation;
107 struct inpcbhead ripcb;
108 struct inpcbinfo ripcbinfo;
109
110 /* control hooks for ipfw and dummynet */
111 ip_fw_ctl_t *ip_fw_ctl_ptr;
112 #if DUMMYNET
113 ip_dn_ctl_t *ip_dn_ctl_ptr;
114 #endif /* DUMMYNET */
115
116 /*
117 * Nominal space allocated to a raw ip socket.
118 */
119 #define RIPSNDQ 8192
120 #define RIPRCVQ 8192
121
122 /*
123 * Raw interface to IP protocol.
124 */
125
126 /*
127 * Initialize raw connection block q.
128 */
129 void
130 rip_init()
131 {
132 struct inpcbinfo *pcbinfo;
133
134 LIST_INIT(&ripcb);
135 ripcbinfo.listhead = &ripcb;
136 /*
137 * XXX We don't use the hash list for raw IP, but it's easier
138 * to allocate a one entry hash list than it is to check all
139 * over the place for hashbase == NULL.
140 */
141 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
142 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
143
144 ripcbinfo.ipi_zone = (void *) zinit(sizeof(struct inpcb),
145 (4096 * sizeof(struct inpcb)),
146 4096, "ripzone");
147
148 pcbinfo = &ripcbinfo;
149 /*
150 * allocate lock group attribute and group for udp pcb mutexes
151 */
152 pcbinfo->mtx_grp_attr = lck_grp_attr_alloc_init();
153 lck_grp_attr_setdefault(pcbinfo->mtx_grp_attr);
154
155 pcbinfo->mtx_grp = lck_grp_alloc_init("ripcb", pcbinfo->mtx_grp_attr);
156
157 /*
158 * allocate the lock attribute for udp pcb mutexes
159 */
160 pcbinfo->mtx_attr = lck_attr_alloc_init();
161 lck_attr_setdefault(pcbinfo->mtx_attr);
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 int
746 rip_unlock(struct socket *so, int refcount, int debug)
747 {
748 int lr_saved;
749 struct inpcb *inp = sotoinpcb(so);
750 #ifdef __ppc__
751 if (debug == 0) {
752 __asm__ volatile("mflr %0" : "=r" (lr_saved));
753 }
754 else lr_saved = debug;
755 #endif
756 if (refcount) {
757 if (so->so_usecount <= 0)
758 panic("rip_unlock: bad refoucnt so=%x val=%x\n", so, so->so_usecount);
759 so->so_usecount--;
760 if (so->so_usecount == 0 && (inp->inp_wantcnt == WNT_STOPUSING)) {
761 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
762 lck_rw_lock_exclusive(ripcbinfo.mtx);
763 in_pcbdispose(inp);
764 lck_rw_done(ripcbinfo.mtx);
765 return(0);
766 }
767 }
768 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
769 return(0);
770 }
771
772 static int
773 rip_pcblist SYSCTL_HANDLER_ARGS
774 {
775 int error, i, n, s;
776 struct inpcb *inp, **inp_list;
777 inp_gen_t gencnt;
778 struct xinpgen xig;
779
780 /*
781 * The process of preparing the TCB list is too time-consuming and
782 * resource-intensive to repeat twice on every request.
783 */
784 lck_rw_lock_exclusive(ripcbinfo.mtx);
785 if (req->oldptr == USER_ADDR_NULL) {
786 n = ripcbinfo.ipi_count;
787 req->oldidx = 2 * (sizeof xig)
788 + (n + n/8) * sizeof(struct xinpcb);
789 lck_rw_done(ripcbinfo.mtx);
790 return 0;
791 }
792
793 if (req->newptr != USER_ADDR_NULL) {
794 lck_rw_done(ripcbinfo.mtx);
795 return EPERM;
796 }
797
798 /*
799 * OK, now we're committed to doing something.
800 */
801 gencnt = ripcbinfo.ipi_gencnt;
802 n = ripcbinfo.ipi_count;
803
804 bzero(&xig, sizeof(xig));
805 xig.xig_len = sizeof xig;
806 xig.xig_count = n;
807 xig.xig_gen = gencnt;
808 xig.xig_sogen = so_gencnt;
809 error = SYSCTL_OUT(req, &xig, sizeof xig);
810 if (error) {
811 lck_rw_done(ripcbinfo.mtx);
812 return error;
813 }
814 /*
815 * We are done if there is no pcb
816 */
817 if (n == 0) {
818 lck_rw_done(ripcbinfo.mtx);
819 return 0;
820 }
821
822 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
823 if (inp_list == 0) {
824 lck_rw_done(ripcbinfo.mtx);
825 return ENOMEM;
826 }
827
828 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
829 inp = inp->inp_list.le_next) {
830 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
831 inp_list[i++] = inp;
832 }
833 n = i;
834
835 error = 0;
836 for (i = 0; i < n; i++) {
837 inp = inp_list[i];
838 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
839 struct xinpcb xi;
840
841 bzero(&xi, sizeof(xi));
842 xi.xi_len = sizeof xi;
843 /* XXX should avoid extra copy */
844 inpcb_to_compat(inp, &xi.xi_inp);
845 if (inp->inp_socket)
846 sotoxsocket(inp->inp_socket, &xi.xi_socket);
847 error = SYSCTL_OUT(req, &xi, sizeof xi);
848 }
849 }
850 if (!error) {
851 /*
852 * Give the user an updated idea of our state.
853 * If the generation differs from what we told
854 * her before, she knows that something happened
855 * while we were processing this request, and it
856 * might be necessary to retry.
857 */
858 bzero(&xig, sizeof(xig));
859 xig.xig_len = sizeof xig;
860 xig.xig_gen = ripcbinfo.ipi_gencnt;
861 xig.xig_sogen = so_gencnt;
862 xig.xig_count = ripcbinfo.ipi_count;
863 error = SYSCTL_OUT(req, &xig, sizeof xig);
864 }
865 FREE(inp_list, M_TEMP);
866 lck_rw_done(ripcbinfo.mtx);
867 return error;
868 }
869
870 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
871 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
872
873 struct pr_usrreqs rip_usrreqs = {
874 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
875 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
876 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
877 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
878 in_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
879 };