]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/raw_ip.c
c96397f15564e3f1d2341da63c4924054576f63e
[apple/xnu.git] / bsd / netinet / raw_ip.c
1 /*
2 * Copyright (c) 2006 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 lck_grp_attr_setdefault(pcbinfo->mtx_grp_attr);
156
157 pcbinfo->mtx_grp = lck_grp_alloc_init("ripcb", pcbinfo->mtx_grp_attr);
158
159 /*
160 * allocate the lock attribute for udp pcb mutexes
161 */
162 pcbinfo->mtx_attr = lck_attr_alloc_init();
163 lck_attr_setdefault(pcbinfo->mtx_attr);
164
165 if ((pcbinfo->mtx = lck_rw_alloc_init(pcbinfo->mtx_grp, pcbinfo->mtx_attr)) == NULL)
166 return; /* pretty much dead if this fails... */
167
168 }
169
170 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
171 /*
172 * Setup generic address and protocol structures
173 * for raw_input routine, then pass them along with
174 * mbuf chain.
175 */
176 void
177 rip_input(m, iphlen)
178 struct mbuf *m;
179 int iphlen;
180 {
181 register struct ip *ip = mtod(m, struct ip *);
182 register struct inpcb *inp;
183 struct inpcb *last = 0;
184 struct mbuf *opts = 0;
185 int skipit;
186
187 ripsrc.sin_addr = ip->ip_src;
188 lck_rw_lock_shared(ripcbinfo.mtx);
189 LIST_FOREACH(inp, &ripcb, inp_list) {
190 #if INET6
191 if ((inp->inp_vflag & INP_IPV4) == 0)
192 continue;
193 #endif
194 if (inp->inp_ip_p && (inp->inp_ip_p != ip->ip_p))
195 continue;
196 if (inp->inp_laddr.s_addr &&
197 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
198 continue;
199 if (inp->inp_faddr.s_addr &&
200 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
201 continue;
202 if (last) {
203 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
204
205 #if IPSEC
206 /* check AH/ESP integrity. */
207 skipit = 0;
208 if (ipsec_bypass == 0 && n) {
209 lck_mtx_lock(sadb_mutex);
210 if (ipsec4_in_reject_so(n, last->inp_socket)) {
211 m_freem(n);
212 ipsecstat.in_polvio++;
213 /* do not inject data to pcb */
214 skipit = 1;
215 }
216 lck_mtx_unlock(sadb_mutex);
217 }
218 #endif /*IPSEC*/
219 if (n && skipit == 0) {
220 int error = 0;
221 if (last->inp_flags & INP_CONTROLOPTS ||
222 last->inp_socket->so_options & SO_TIMESTAMP)
223 ip_savecontrol(last, &opts, ip, n);
224 if (last->inp_flags & INP_STRIPHDR) {
225 n->m_len -= iphlen;
226 n->m_pkthdr.len -= iphlen;
227 n->m_data += iphlen;
228 }
229 // ###LOCK need to lock that socket?
230 if (sbappendaddr(&last->inp_socket->so_rcv,
231 (struct sockaddr *)&ripsrc, n,
232 opts, &error) != 0) {
233 sorwakeup(last->inp_socket);
234 }
235 else {
236 if (error) {
237 /* should notify about lost packet */
238 kprintf("rip_input can't append to socket\n");
239 }
240 }
241 opts = 0;
242 }
243 }
244 last = inp;
245 }
246 lck_rw_done(ripcbinfo.mtx);
247 #if IPSEC
248 /* check AH/ESP integrity. */
249 skipit = 0;
250 if (ipsec_bypass == 0 && last) {
251 lck_mtx_lock(sadb_mutex);
252 if (ipsec4_in_reject_so(m, last->inp_socket)) {
253 m_freem(m);
254 ipsecstat.in_polvio++;
255 ipstat.ips_delivered--;
256 /* do not inject data to pcb */
257 skipit = 1;
258 }
259 lck_mtx_unlock(sadb_mutex);
260 }
261 #endif /*IPSEC*/
262 if (skipit == 0) {
263 if (last) {
264 if (last->inp_flags & INP_CONTROLOPTS ||
265 last->inp_socket->so_options & SO_TIMESTAMP)
266 ip_savecontrol(last, &opts, ip, m);
267 if (last->inp_flags & INP_STRIPHDR) {
268 m->m_len -= iphlen;
269 m->m_pkthdr.len -= iphlen;
270 m->m_data += iphlen;
271 }
272 if (sbappendaddr(&last->inp_socket->so_rcv,
273 (struct sockaddr *)&ripsrc, m, opts, NULL) != 0) {
274 sorwakeup(last->inp_socket);
275 } else {
276 kprintf("rip_input(2) can't append to socket\n");
277 }
278 } else {
279 m_freem(m);
280 ipstat.ips_noproto++;
281 ipstat.ips_delivered--;
282 }
283 }
284 }
285
286 /*
287 * Generate IP header and pass packet to ip_output.
288 * Tack on options user may have setup with control call.
289 */
290 int
291 rip_output(m, so, dst)
292 register struct mbuf *m;
293 struct socket *so;
294 u_long dst;
295 {
296 register struct ip *ip;
297 register struct inpcb *inp = sotoinpcb(so);
298 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
299
300 /*
301 * If the user handed us a complete IP packet, use it.
302 * Otherwise, allocate an mbuf for a header and fill it in.
303 */
304 if ((inp->inp_flags & INP_HDRINCL) == 0) {
305 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
306 m_freem(m);
307 return(EMSGSIZE);
308 }
309 M_PREPEND(m, sizeof(struct ip), M_WAIT);
310 ip = mtod(m, struct ip *);
311 ip->ip_tos = inp->inp_ip_tos;
312 ip->ip_off = 0;
313 ip->ip_p = inp->inp_ip_p;
314 ip->ip_len = m->m_pkthdr.len;
315 ip->ip_src = inp->inp_laddr;
316 ip->ip_dst.s_addr = dst;
317 ip->ip_ttl = inp->inp_ip_ttl;
318 } else {
319 if (m->m_pkthdr.len > IP_MAXPACKET) {
320 m_freem(m);
321 return(EMSGSIZE);
322 }
323 ip = mtod(m, struct ip *);
324 /* don't allow both user specified and setsockopt options,
325 and don't allow packet length sizes that will crash */
326 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
327 && inp->inp_options)
328 || (ip->ip_len > m->m_pkthdr.len)
329 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
330 m_freem(m);
331 return EINVAL;
332 }
333 if (ip->ip_id == 0)
334 #if RANDOM_IP_ID
335 ip->ip_id = ip_randomid();
336 #else
337 ip->ip_id = htons(ip_id++);
338 #endif
339 /* XXX prevent ip_output from overwriting header fields */
340 flags |= IP_RAWOUTPUT;
341 ipstat.ips_rawout++;
342 }
343
344 #if IPSEC
345 if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) {
346 m_freem(m);
347 return ENOBUFS;
348 }
349 #endif /*IPSEC*/
350
351 if (inp->inp_route.ro_rt && inp->inp_route.ro_rt->generation_id != route_generation) {
352 rtfree(inp->inp_route.ro_rt);
353 inp->inp_route.ro_rt = (struct rtentry *)0;
354 }
355
356 return (ip_output_list(m, 0, inp->inp_options, &inp->inp_route, flags,
357 inp->inp_moptions));
358 }
359
360 extern int
361 load_ipfw()
362 {
363 kern_return_t err;
364
365 ipfw_init();
366
367 #if DUMMYNET
368 if (!DUMMYNET_LOADED)
369 ip_dn_init();
370 #endif /* DUMMYNET */
371 err = 0;
372
373 return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
374 }
375
376 /*
377 * Raw IP socket option processing.
378 */
379 int
380 rip_ctloutput(so, sopt)
381 struct socket *so;
382 struct sockopt *sopt;
383 {
384 struct inpcb *inp = sotoinpcb(so);
385 int error, optval;
386
387 if (sopt->sopt_level != IPPROTO_IP)
388 return (EINVAL);
389
390 error = 0;
391
392 switch (sopt->sopt_dir) {
393 case SOPT_GET:
394 switch (sopt->sopt_name) {
395 case IP_HDRINCL:
396 optval = inp->inp_flags & INP_HDRINCL;
397 error = sooptcopyout(sopt, &optval, sizeof optval);
398 break;
399
400 case IP_STRIPHDR:
401 optval = inp->inp_flags & INP_STRIPHDR;
402 error = sooptcopyout(sopt, &optval, sizeof optval);
403 break;
404
405 case IP_FW_ADD:
406 case IP_FW_GET:
407 case IP_OLD_FW_ADD:
408 case IP_OLD_FW_GET:
409 if (ip_fw_ctl_ptr == 0)
410 error = load_ipfw();
411 if (ip_fw_ctl_ptr && error == 0)
412 error = ip_fw_ctl_ptr(sopt);
413 else
414 error = ENOPROTOOPT;
415 break;
416
417 #if DUMMYNET
418 case IP_DUMMYNET_GET:
419 if (DUMMYNET_LOADED)
420 error = ip_dn_ctl_ptr(sopt);
421 else
422 error = ENOPROTOOPT;
423 break ;
424 #endif /* DUMMYNET */
425
426 case MRT_INIT:
427 case MRT_DONE:
428 case MRT_ADD_VIF:
429 case MRT_DEL_VIF:
430 case MRT_ADD_MFC:
431 case MRT_DEL_MFC:
432 case MRT_VERSION:
433 case MRT_ASSERT:
434 error = ip_mrouter_get(so, sopt);
435 break;
436
437 default:
438 error = ip_ctloutput(so, sopt);
439 break;
440 }
441 break;
442
443 case SOPT_SET:
444 switch (sopt->sopt_name) {
445 case IP_HDRINCL:
446 error = sooptcopyin(sopt, &optval, sizeof optval,
447 sizeof optval);
448 if (error)
449 break;
450 if (optval)
451 inp->inp_flags |= INP_HDRINCL;
452 else
453 inp->inp_flags &= ~INP_HDRINCL;
454 break;
455
456 case IP_STRIPHDR:
457 error = sooptcopyin(sopt, &optval, sizeof optval,
458 sizeof optval);
459 if (error)
460 break;
461 if (optval)
462 inp->inp_flags |= INP_STRIPHDR;
463 else
464 inp->inp_flags &= ~INP_STRIPHDR;
465 break;
466
467
468 case IP_FW_ADD:
469 case IP_FW_DEL:
470 case IP_FW_FLUSH:
471 case IP_FW_ZERO:
472 case IP_FW_RESETLOG:
473 case IP_OLD_FW_ADD:
474 case IP_OLD_FW_DEL:
475 case IP_OLD_FW_FLUSH:
476 case IP_OLD_FW_ZERO:
477 case IP_OLD_FW_RESETLOG:
478 if (ip_fw_ctl_ptr == 0)
479 error = load_ipfw();
480 if (ip_fw_ctl_ptr && error == 0)
481 error = ip_fw_ctl_ptr(sopt);
482 else
483 error = ENOPROTOOPT;
484 break;
485
486 #if DUMMYNET
487 case IP_DUMMYNET_CONFIGURE:
488 case IP_DUMMYNET_DEL:
489 case IP_DUMMYNET_FLUSH:
490 if (DUMMYNET_LOADED)
491 error = ip_dn_ctl_ptr(sopt);
492 else
493 error = ENOPROTOOPT ;
494 break ;
495 #endif
496
497 case IP_RSVP_ON:
498 error = ip_rsvp_init(so);
499 break;
500
501 case IP_RSVP_OFF:
502 error = ip_rsvp_done();
503 break;
504
505 /* XXX - should be combined */
506 case IP_RSVP_VIF_ON:
507 error = ip_rsvp_vif_init(so, sopt);
508 break;
509
510 case IP_RSVP_VIF_OFF:
511 error = ip_rsvp_vif_done(so, sopt);
512 break;
513
514 case MRT_INIT:
515 case MRT_DONE:
516 case MRT_ADD_VIF:
517 case MRT_DEL_VIF:
518 case MRT_ADD_MFC:
519 case MRT_DEL_MFC:
520 case MRT_VERSION:
521 case MRT_ASSERT:
522 error = ip_mrouter_set(so, sopt);
523 break;
524
525 default:
526 error = ip_ctloutput(so, sopt);
527 break;
528 }
529 break;
530 }
531
532 return (error);
533 }
534
535 /*
536 * This function exists solely to receive the PRC_IFDOWN messages which
537 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
538 * and calls in_ifadown() to remove all routes corresponding to that address.
539 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
540 * interface routes.
541 */
542 void
543 rip_ctlinput(cmd, sa, vip)
544 int cmd;
545 struct sockaddr *sa;
546 void *vip;
547 {
548 struct in_ifaddr *ia;
549 struct ifnet *ifp;
550 int err;
551 int flags;
552
553 switch (cmd) {
554 case PRC_IFDOWN:
555 lck_mtx_lock(rt_mtx);
556 for (ia = in_ifaddrhead.tqh_first; ia;
557 ia = ia->ia_link.tqe_next) {
558 if (ia->ia_ifa.ifa_addr == sa
559 && (ia->ia_flags & IFA_ROUTE)) {
560 /*
561 * in_ifscrub kills the interface route.
562 */
563 in_ifscrub(ia->ia_ifp, ia, 1);
564 /*
565 * in_ifadown gets rid of all the rest of
566 * the routes. This is not quite the right
567 * thing to do, but at least if we are running
568 * a routing process they will come back.
569 */
570 in_ifadown(&ia->ia_ifa, 1);
571 break;
572 }
573 }
574 lck_mtx_unlock(rt_mtx);
575 break;
576
577 case PRC_IFUP:
578 lck_mtx_lock(rt_mtx);
579 for (ia = in_ifaddrhead.tqh_first; ia;
580 ia = ia->ia_link.tqe_next) {
581 if (ia->ia_ifa.ifa_addr == sa)
582 break;
583 }
584 if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) {
585 lck_mtx_unlock(rt_mtx);
586 return;
587 }
588 flags = RTF_UP;
589 ifp = ia->ia_ifa.ifa_ifp;
590
591 if ((ifp->if_flags & IFF_LOOPBACK)
592 || (ifp->if_flags & IFF_POINTOPOINT))
593 flags |= RTF_HOST;
594
595 err = rtinit_locked(&ia->ia_ifa, RTM_ADD, flags);
596 lck_mtx_unlock(rt_mtx);
597 if (err == 0)
598 ia->ia_flags |= IFA_ROUTE;
599 break;
600 }
601 }
602
603 u_long rip_sendspace = RIPSNDQ;
604 u_long rip_recvspace = RIPRCVQ;
605
606 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
607 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
608 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
609 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
610
611 static int
612 rip_attach(struct socket *so, int proto, struct proc *p)
613 {
614 struct inpcb *inp;
615 int error, s;
616
617 inp = sotoinpcb(so);
618 if (inp)
619 panic("rip_attach");
620 #if __APPLE__
621 if ((so->so_state & SS_PRIV) == 0)
622 return (EPERM);
623 #else
624 if (p && (error = suser(p)) != 0)
625 return error;
626 #endif
627
628 error = soreserve(so, rip_sendspace, rip_recvspace);
629 if (error)
630 return error;
631 s = splnet();
632 error = in_pcballoc(so, &ripcbinfo, p);
633 splx(s);
634 if (error)
635 return error;
636 inp = (struct inpcb *)so->so_pcb;
637 inp->inp_vflag |= INP_IPV4;
638 inp->inp_ip_p = proto;
639 inp->inp_ip_ttl = ip_defttl;
640 return 0;
641 }
642
643 __private_extern__ int
644 rip_detach(struct socket *so)
645 {
646 struct inpcb *inp;
647
648 inp = sotoinpcb(so);
649 if (inp == 0)
650 panic("rip_detach");
651 if (so == ip_mrouter)
652 ip_mrouter_done();
653 ip_rsvp_force_done(so);
654 if (so == ip_rsvpd)
655 ip_rsvp_done();
656 in_pcbdetach(inp);
657 return 0;
658 }
659
660 __private_extern__ int
661 rip_abort(struct socket *so)
662 {
663 soisdisconnected(so);
664 return rip_detach(so);
665 }
666
667 __private_extern__ int
668 rip_disconnect(struct socket *so)
669 {
670 if ((so->so_state & SS_ISCONNECTED) == 0)
671 return ENOTCONN;
672 return rip_abort(so);
673 }
674
675 __private_extern__ int
676 rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
677 {
678 struct inpcb *inp = sotoinpcb(so);
679 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
680 struct ifaddr *ifa = NULL;
681
682 if (nam->sa_len != sizeof(*addr))
683 return EINVAL;
684
685 if (TAILQ_EMPTY(&ifnet_head) || ((addr->sin_family != AF_INET) &&
686 (addr->sin_family != AF_IMPLINK)) ||
687 (addr->sin_addr.s_addr &&
688 (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
689 return EADDRNOTAVAIL;
690 }
691 else if (ifa) {
692 ifafree(ifa);
693 ifa = NULL;
694 }
695 inp->inp_laddr = addr->sin_addr;
696 return 0;
697 }
698
699 __private_extern__ int
700 rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
701 {
702 struct inpcb *inp = sotoinpcb(so);
703 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
704
705 if (nam->sa_len != sizeof(*addr))
706 return EINVAL;
707 if (TAILQ_EMPTY(&ifnet_head))
708 return EADDRNOTAVAIL;
709 if ((addr->sin_family != AF_INET) &&
710 (addr->sin_family != AF_IMPLINK))
711 return EAFNOSUPPORT;
712 inp->inp_faddr = addr->sin_addr;
713 soisconnected(so);
714 return 0;
715 }
716
717 __private_extern__ int
718 rip_shutdown(struct socket *so)
719 {
720 socantsendmore(so);
721 return 0;
722 }
723
724 __private_extern__ int
725 rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
726 struct mbuf *control, struct proc *p)
727 {
728 struct inpcb *inp = sotoinpcb(so);
729 register u_long dst;
730
731 if (so->so_state & SS_ISCONNECTED) {
732 if (nam) {
733 m_freem(m);
734 return EISCONN;
735 }
736 dst = inp->inp_faddr.s_addr;
737 } else {
738 if (nam == NULL) {
739 m_freem(m);
740 return ENOTCONN;
741 }
742 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
743 }
744 return rip_output(m, so, dst);
745 }
746
747 int
748 rip_unlock(struct socket *so, int refcount, int debug)
749 {
750 int lr_saved;
751 struct inpcb *inp = sotoinpcb(so);
752 #ifdef __ppc__
753 if (debug == 0) {
754 __asm__ volatile("mflr %0" : "=r" (lr_saved));
755 }
756 else lr_saved = debug;
757 #endif
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 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
764 lck_rw_lock_exclusive(ripcbinfo.mtx);
765 in_pcbdispose(inp);
766 lck_rw_done(ripcbinfo.mtx);
767 return(0);
768 }
769 }
770 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
771 return(0);
772 }
773
774 static int
775 rip_pcblist SYSCTL_HANDLER_ARGS
776 {
777 int error, i, n, s;
778 struct inpcb *inp, **inp_list;
779 inp_gen_t gencnt;
780 struct xinpgen xig;
781
782 /*
783 * The process of preparing the TCB list is too time-consuming and
784 * resource-intensive to repeat twice on every request.
785 */
786 lck_rw_lock_exclusive(ripcbinfo.mtx);
787 if (req->oldptr == USER_ADDR_NULL) {
788 n = ripcbinfo.ipi_count;
789 req->oldidx = 2 * (sizeof xig)
790 + (n + n/8) * sizeof(struct xinpcb);
791 lck_rw_done(ripcbinfo.mtx);
792 return 0;
793 }
794
795 if (req->newptr != USER_ADDR_NULL) {
796 lck_rw_done(ripcbinfo.mtx);
797 return EPERM;
798 }
799
800 /*
801 * OK, now we're committed to doing something.
802 */
803 gencnt = ripcbinfo.ipi_gencnt;
804 n = ripcbinfo.ipi_count;
805
806 bzero(&xig, sizeof(xig));
807 xig.xig_len = sizeof xig;
808 xig.xig_count = n;
809 xig.xig_gen = gencnt;
810 xig.xig_sogen = so_gencnt;
811 error = SYSCTL_OUT(req, &xig, sizeof xig);
812 if (error) {
813 lck_rw_done(ripcbinfo.mtx);
814 return error;
815 }
816 /*
817 * We are done if there is no pcb
818 */
819 if (n == 0) {
820 lck_rw_done(ripcbinfo.mtx);
821 return 0;
822 }
823
824 inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
825 if (inp_list == 0) {
826 lck_rw_done(ripcbinfo.mtx);
827 return ENOMEM;
828 }
829
830 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
831 inp = inp->inp_list.le_next) {
832 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
833 inp_list[i++] = inp;
834 }
835 n = i;
836
837 error = 0;
838 for (i = 0; i < n; i++) {
839 inp = inp_list[i];
840 if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
841 struct xinpcb xi;
842
843 bzero(&xi, sizeof(xi));
844 xi.xi_len = sizeof xi;
845 /* XXX should avoid extra copy */
846 inpcb_to_compat(inp, &xi.xi_inp);
847 if (inp->inp_socket)
848 sotoxsocket(inp->inp_socket, &xi.xi_socket);
849 error = SYSCTL_OUT(req, &xi, sizeof xi);
850 }
851 }
852 if (!error) {
853 /*
854 * Give the user an updated idea of our state.
855 * If the generation differs from what we told
856 * her before, she knows that something happened
857 * while we were processing this request, and it
858 * might be necessary to retry.
859 */
860 bzero(&xig, sizeof(xig));
861 xig.xig_len = sizeof xig;
862 xig.xig_gen = ripcbinfo.ipi_gencnt;
863 xig.xig_sogen = so_gencnt;
864 xig.xig_count = ripcbinfo.ipi_count;
865 error = SYSCTL_OUT(req, &xig, sizeof xig);
866 }
867 FREE(inp_list, M_TEMP);
868 lck_rw_done(ripcbinfo.mtx);
869 return error;
870 }
871
872 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
873 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
874
875 struct pr_usrreqs rip_usrreqs = {
876 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
877 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
878 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
879 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
880 in_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
881 };