1/*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
34 * $Id: raw_ip.c,v 1.58 1999/04/27 11:17:36 phk Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/proc.h>
43#include <sys/protosw.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/sysctl.h>
47
48#include <vm/vm_zone.h>
49
50#include <net/if.h>
51#include <net/route.h>
52
53#define _IP_VHL
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/in_pcb.h>
58#include <netinet/in_var.h>
59#include <netinet/ip_var.h>
60#include <netinet/ip_mroute.h>
61
62#include <netinet/ip_fw.h>
63
64#include "opt_ipdn.h"
65#ifdef DUMMYNET
66#include <netinet/ip_dummynet.h>
67#endif
68
69static struct inpcbhead ripcb;
70static struct inpcbinfo ripcbinfo;
71
72/*
73 * Nominal space allocated to a raw ip socket.
74 */
75#define RIPSNDQ 8192
76#define RIPRCVQ 8192
77
78/*
79 * Raw interface to IP protocol.
80 */
81
82/*
83 * Initialize raw connection block q.
84 */
85void
86rip_init()
87{
88 LIST_INIT(&ripcb);
89 ripcbinfo.listhead = &ripcb;
90 /*
91 * XXX We don't use the hash list for raw IP, but it's easier
92 * to allocate a one entry hash list than it is to check all
93 * over the place for hashbase == NULL.
94 */
95 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
96 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
97 ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb),
98 maxsockets, ZONE_INTERRUPT, 0);
99}
100
101static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
102/*
103 * Setup generic address and protocol structures
104 * for raw_input routine, then pass them along with
105 * mbuf chain.
106 */
107void
108rip_input(m, iphlen)
109 struct mbuf *m;
110 int iphlen;
111{
112 register struct ip *ip = mtod(m, struct ip *);
113 register struct inpcb *inp;
114 struct inpcb *last = 0;
115 struct mbuf *opts = 0;
116
117 ripsrc.sin_addr = ip->ip_src;
118 for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
119 if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p)
120 continue;
121 if (inp->inp_laddr.s_addr &&
122 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
123 continue;
124 if (inp->inp_faddr.s_addr &&
125 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
126 continue;
127 if (last) {
128 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
129 if (n) {
130 if (last->inp_flags & INP_CONTROLOPTS ||
131 last->inp_socket->so_options & SO_TIMESTAMP)
132 ip_savecontrol(last, &opts, ip, n);
133 if (sbappendaddr(&last->inp_socket->so_rcv,
134 (struct sockaddr *)&ripsrc, n,
135 opts) == 0) {
136 /* should notify about lost packet */
137 m_freem(n);
138 if (opts)
139 m_freem(opts);
140 } else
141 sorwakeup(last->inp_socket);
142 opts = 0;
143 }
144 }
145 last = inp;
146 }
147 if (last) {
148 if (last->inp_flags & INP_CONTROLOPTS ||
149 last->inp_socket->so_options & SO_TIMESTAMP)
150 ip_savecontrol(last, &opts, ip, m);
151 if (sbappendaddr(&last->inp_socket->so_rcv,
152 (struct sockaddr *)&ripsrc, m, opts) == 0) {
153 m_freem(m);
154 if (opts)
155 m_freem(opts);
156 } else
157 sorwakeup(last->inp_socket);
158 } else {
159 m_freem(m);
160 ipstat.ips_noproto++;
161 ipstat.ips_delivered--;
162 }
163}
164
165/*
166 * Generate IP header and pass packet to ip_output.
167 * Tack on options user may have setup with control call.
168 */
169int
170rip_output(m, so, dst)
171 register struct mbuf *m;
172 struct socket *so;
173 u_long dst;
174{
175 register struct ip *ip;
176 register struct inpcb *inp = sotoinpcb(so);
177 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
178
179 /*
180 * If the user handed us a complete IP packet, use it.
181 * Otherwise, allocate an mbuf for a header and fill it in.
182 */
183 if ((inp->inp_flags & INP_HDRINCL) == 0) {
184 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
185 m_freem(m);
186 return(EMSGSIZE);
187 }
188 M_PREPEND(m, sizeof(struct ip), M_WAIT);
189 ip = mtod(m, struct ip *);
190 ip->ip_tos = 0;
191 ip->ip_off = 0;
192 ip->ip_p = inp->inp_ip_p;
193 ip->ip_len = m->m_pkthdr.len;
194 ip->ip_src = inp->inp_laddr;
195 ip->ip_dst.s_addr = dst;
196 ip->ip_ttl = MAXTTL;
197 } else {
198 if (m->m_pkthdr.len > IP_MAXPACKET) {
199 m_freem(m);
200 return(EMSGSIZE);
201 }
202 ip = mtod(m, struct ip *);
203 /* don't allow both user specified and setsockopt options,
204 and don't allow packet length sizes that will crash */
205 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
206 && inp->inp_options)
207 || (ip->ip_len > m->m_pkthdr.len)
208 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
209 m_freem(m);
210 return EINVAL;
211 }
212 if (ip->ip_id == 0)
213 ip->ip_id = htons(ip_id++);
214 /* XXX prevent ip_output from overwriting header fields */
215 flags |= IP_RAWOUTPUT;
216 ipstat.ips_rawout++;
217 }
218 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
219 inp->inp_moptions));
220}
221
222/*
223 * Raw IP socket option processing.
224 */
225int
226rip_ctloutput(so, sopt)
227 struct socket *so;
228 struct sockopt *sopt;
229{
230 struct inpcb *inp = sotoinpcb(so);
231 int error, optval;
232
233 if (sopt->sopt_level != IPPROTO_IP)
234 return (EINVAL);
235
236 error = 0;
237
238 switch (sopt->sopt_dir) {
239 case SOPT_GET:
240 switch (sopt->sopt_name) {
241 case IP_HDRINCL:
242 optval = inp->inp_flags & INP_HDRINCL;
243 error = sooptcopyout(sopt, &optval, sizeof optval);
244 break;
245
246 case IP_FW_GET:
247 if (ip_fw_ctl_ptr == 0)
248 error = ENOPROTOOPT;
249 else
250 error = ip_fw_ctl_ptr(sopt);
251 break;
252
253#ifdef DUMMYNET
254 case IP_DUMMYNET_GET:
255 if (ip_dn_ctl_ptr == NULL)
256 error = ENOPROTOOPT ;
257 else
258 error = ip_dn_ctl_ptr(sopt);
259 break ;
260#endif /* DUMMYNET */
261
262 case MRT_INIT:
263 case MRT_DONE:
264 case MRT_ADD_VIF:
265 case MRT_DEL_VIF:
266 case MRT_ADD_MFC:
267 case MRT_DEL_MFC:
268 case MRT_VERSION:
269 case MRT_ASSERT:
270 error = ip_mrouter_get(so, sopt);
271 break;
272
273 default:
274 error = ip_ctloutput(so, sopt);
275 break;
276 }
277 break;
278
279 case SOPT_SET:
280 switch (sopt->sopt_name) {
281 case IP_HDRINCL:
282 error = sooptcopyin(sopt, &optval, sizeof optval,
283 sizeof optval);
284 if (error)
285 break;
286 if (optval)
287 inp->inp_flags |= INP_HDRINCL;
288 else
289 inp->inp_flags &= ~INP_HDRINCL;
290 break;
291
292 case IP_FW_ADD:
293 case IP_FW_DEL:
294 case IP_FW_FLUSH:
295 case IP_FW_ZERO:
296 if (ip_fw_ctl_ptr == 0)
297 error = ENOPROTOOPT;
298 else
299 error = ip_fw_ctl_ptr(sopt);
300 break;
301
302#ifdef DUMMYNET
303 case IP_DUMMYNET_CONFIGURE:
304 case IP_DUMMYNET_DEL:
305 case IP_DUMMYNET_FLUSH:
306 if (ip_dn_ctl_ptr == NULL)
307 error = ENOPROTOOPT ;
308 else
309 error = ip_dn_ctl_ptr(sopt);
310 break ;
311#endif
312
313 case IP_RSVP_ON:
314 error = ip_rsvp_init(so);
315 break;
316
317 case IP_RSVP_OFF:
318 error = ip_rsvp_done();
319 break;
320
321 /* XXX - should be combined */
322 case IP_RSVP_VIF_ON:
323 error = ip_rsvp_vif_init(so, sopt);
324 break;
325
326 case IP_RSVP_VIF_OFF:
327 error = ip_rsvp_vif_done(so, sopt);
328 break;
329
330 case MRT_INIT:
331 case MRT_DONE:
332 case MRT_ADD_VIF:
333 case MRT_DEL_VIF:
334 case MRT_ADD_MFC:
335 case MRT_DEL_MFC:
336 case MRT_VERSION:
337 case MRT_ASSERT:
338 error = ip_mrouter_set(so, sopt);
339 break;
340
341 default:
342 error = ip_ctloutput(so, sopt);
343 break;
344 }
345 break;
346 }
347
348 return (error);
349}
350
351/*
352 * This function exists solely to receive the PRC_IFDOWN messages which
353 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
354 * and calls in_ifadown() to remove all routes corresponding to that address.
355 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
356 * interface routes.
357 */
358void
359rip_ctlinput(cmd, sa, vip)
360 int cmd;
361 struct sockaddr *sa;
362 void *vip;
363{
364 struct in_ifaddr *ia;
365 struct ifnet *ifp;
366 int err;
367 int flags;
368
369 switch (cmd) {
370 case PRC_IFDOWN:
371 for (ia = in_ifaddrhead.tqh_first; ia;
372 ia = ia->ia_link.tqe_next) {
373 if (ia->ia_ifa.ifa_addr == sa
374 && (ia->ia_flags & IFA_ROUTE)) {
375 /*
376 * in_ifscrub kills the interface route.
377 */
378 in_ifscrub(ia->ia_ifp, ia);
379 /*
380 * in_ifadown gets rid of all the rest of
381 * the routes. This is not quite the right
382 * thing to do, but at least if we are running
383 * a routing process they will come back.
384 */
385 in_ifadown(&ia->ia_ifa);
386 break;
387 }
388 }
389 break;
390
391 case PRC_IFUP:
392 for (ia = in_ifaddrhead.tqh_first; ia;
393 ia = ia->ia_link.tqe_next) {
394 if (ia->ia_ifa.ifa_addr == sa)
395 break;
396 }
397 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
398 return;
399 flags = RTF_UP;
400 ifp = ia->ia_ifa.ifa_ifp;
401
402 if ((ifp->if_flags & IFF_LOOPBACK)
403 || (ifp->if_flags & IFF_POINTOPOINT))
404 flags |= RTF_HOST;
405
406 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
407 if (err == 0)
408 ia->ia_flags |= IFA_ROUTE;
409 break;
410 }
411}
412
413static u_long rip_sendspace = RIPSNDQ;
414static u_long rip_recvspace = RIPRCVQ;
415
416SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
417 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
418SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
419 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
420
421static int
422rip_attach(struct socket *so, int proto, struct proc *p)
423{
424 struct inpcb *inp;
425 int error, s;
426
427 inp = sotoinpcb(so);
428 if (inp)
429 panic("rip_attach");
430 if (p && (error = suser(p)) != 0)
431 return error;
432
433 s = splnet();
434 error = in_pcballoc(so, &ripcbinfo, p);
435 splx(s);
436 if (error)
437 return error;
438 error = soreserve(so, rip_sendspace, rip_recvspace);
439 if (error)
440 return error;
441 inp = (struct inpcb *)so->so_pcb;
442 inp->inp_ip_p = proto;
443 return 0;
444}
445
446static int
447rip_detach(struct socket *so)
448{
449 struct inpcb *inp;
450
451 inp = sotoinpcb(so);
452 if (inp == 0)
453 panic("rip_detach");
454 if (so == ip_mrouter)
455 ip_mrouter_done();
456 ip_rsvp_force_done(so);
457 if (so == ip_rsvpd)
458 ip_rsvp_done();
459 in_pcbdetach(inp);
460 return 0;
461}
462
463static int
464rip_abort(struct socket *so)
465{
466 soisdisconnected(so);
467 return rip_detach(so);
468}
469
470static int
471rip_disconnect(struct socket *so)
472{
473 if ((so->so_state & SS_ISCONNECTED) == 0)
474 return ENOTCONN;
475 return rip_abort(so);
476}
477
478static int
479rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
480{
481 struct inpcb *inp = sotoinpcb(so);
482 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
483
484 if (nam->sa_len != sizeof(*addr))
485 return EINVAL;
486
487 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
488 (addr->sin_family != AF_IMPLINK)) ||
489 (addr->sin_addr.s_addr &&
490 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
491 return EADDRNOTAVAIL;
492 inp->inp_laddr = addr->sin_addr;
493 return 0;
494}
495
496static int
497rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
498{
499 struct inpcb *inp = sotoinpcb(so);
500 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
501
502 if (nam->sa_len != sizeof(*addr))
503 return EINVAL;
504 if (TAILQ_EMPTY(&ifnet))
505 return EADDRNOTAVAIL;
506 if ((addr->sin_family != AF_INET) &&
507 (addr->sin_family != AF_IMPLINK))
508 return EAFNOSUPPORT;
509 inp->inp_faddr = addr->sin_addr;
510 soisconnected(so);
511 return 0;
512}
513
514static int
515rip_shutdown(struct socket *so)
516{
517 socantsendmore(so);
518 return 0;
519}
520
521static int
522rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
523 struct mbuf *control, struct proc *p)
524{
525 struct inpcb *inp = sotoinpcb(so);
526 register u_long dst;
527
528 if (so->so_state & SS_ISCONNECTED) {
529 if (nam) {
530 m_freem(m);
531 return EISCONN;
532 }
533 dst = inp->inp_faddr.s_addr;
534 } else {
535 if (nam == NULL) {
536 m_freem(m);
537 return ENOTCONN;
538 }
539 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
540 }
541 return rip_output(m, so, dst);
542}
543
544static int
545rip_pcblist SYSCTL_HANDLER_ARGS
546{
547 int error, i, n, s;
548 struct inpcb *inp, **inp_list;
549 inp_gen_t gencnt;
550 struct xinpgen xig;
551
552 /*
553 * The process of preparing the TCB list is too time-consuming and
554 * resource-intensive to repeat twice on every request.
555 */
556 if (req->oldptr == 0) {
557 n = ripcbinfo.ipi_count;
558 req->oldidx = 2 * (sizeof xig)
559 + (n + n/8) * sizeof(struct xinpcb);
560 return 0;
561 }
562
563 if (req->newptr != 0)
564 return EPERM;
565
566 /*
567 * OK, now we're committed to doing something.
568 */
569 s = splnet();
570 gencnt = ripcbinfo.ipi_gencnt;
571 n = ripcbinfo.ipi_count;
572 splx(s);
573
574 xig.xig_len = sizeof xig;
575 xig.xig_count = n;
576 xig.xig_gen = gencnt;
577 xig.xig_sogen = so_gencnt;
578 error = SYSCTL_OUT(req, &xig, sizeof xig);
579 if (error)
580 return error;
581
582 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
583 if (inp_list == 0)
584 return ENOMEM;
585
586 s = splnet();
587 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
588 inp = inp->inp_list.le_next) {
589 if (inp->inp_gencnt <= gencnt)
590 inp_list[i++] = inp;
591 }
592 splx(s);
593 n = i;
594
595 error = 0;
596 for (i = 0; i < n; i++) {
597 inp = inp_list[i];
598 if (inp->inp_gencnt <= gencnt) {
599 struct xinpcb xi;
600 xi.xi_len = sizeof xi;
601 /* XXX should avoid extra copy */
602 bcopy(inp, &xi.xi_inp, sizeof *inp);
603 if (inp->inp_socket)
604 sotoxsocket(inp->inp_socket, &xi.xi_socket);
605 error = SYSCTL_OUT(req, &xi, sizeof xi);
606 }
607 }
608 if (!error) {
609 /*
610 * Give the user an updated idea of our state.
611 * If the generation differs from what we told
612 * her before, she knows that something happened
613 * while we were processing this request, and it
614 * might be necessary to retry.
615 */
616 s = splnet();
617 xig.xig_gen = ripcbinfo.ipi_gencnt;
618 xig.xig_sogen = so_gencnt;
619 xig.xig_count = ripcbinfo.ipi_count;
620 splx(s);
621 error = SYSCTL_OUT(req, &xig, sizeof xig);
622 }
623 free(inp_list, M_TEMP);
624 return error;
625}
626
627SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
628 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
629
630struct pr_usrreqs rip_usrreqs = {
631 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
632 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
633 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
634 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
635 in_setsockaddr, sosend, soreceive, sopoll
636};
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
34 * $Id: raw_ip.c,v 1.58 1999/04/27 11:17:36 phk Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/proc.h>
43#include <sys/protosw.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/sysctl.h>
47
48#include <vm/vm_zone.h>
49
50#include <net/if.h>
51#include <net/route.h>
52
53#define _IP_VHL
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/in_pcb.h>
58#include <netinet/in_var.h>
59#include <netinet/ip_var.h>
60#include <netinet/ip_mroute.h>
61
62#include <netinet/ip_fw.h>
63
64#include "opt_ipdn.h"
65#ifdef DUMMYNET
66#include <netinet/ip_dummynet.h>
67#endif
68
69static struct inpcbhead ripcb;
70static struct inpcbinfo ripcbinfo;
71
72/*
73 * Nominal space allocated to a raw ip socket.
74 */
75#define RIPSNDQ 8192
76#define RIPRCVQ 8192
77
78/*
79 * Raw interface to IP protocol.
80 */
81
82/*
83 * Initialize raw connection block q.
84 */
85void
86rip_init()
87{
88 LIST_INIT(&ripcb);
89 ripcbinfo.listhead = &ripcb;
90 /*
91 * XXX We don't use the hash list for raw IP, but it's easier
92 * to allocate a one entry hash list than it is to check all
93 * over the place for hashbase == NULL.
94 */
95 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
96 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
97 ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb),
98 maxsockets, ZONE_INTERRUPT, 0);
99}
100
101static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
102/*
103 * Setup generic address and protocol structures
104 * for raw_input routine, then pass them along with
105 * mbuf chain.
106 */
107void
108rip_input(m, iphlen)
109 struct mbuf *m;
110 int iphlen;
111{
112 register struct ip *ip = mtod(m, struct ip *);
113 register struct inpcb *inp;
114 struct inpcb *last = 0;
115 struct mbuf *opts = 0;
116
117 ripsrc.sin_addr = ip->ip_src;
118 for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
119 if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p)
120 continue;
121 if (inp->inp_laddr.s_addr &&
122 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
123 continue;
124 if (inp->inp_faddr.s_addr &&
125 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
126 continue;
127 if (last) {
128 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
129 if (n) {
130 if (last->inp_flags & INP_CONTROLOPTS ||
131 last->inp_socket->so_options & SO_TIMESTAMP)
132 ip_savecontrol(last, &opts, ip, n);
133 if (sbappendaddr(&last->inp_socket->so_rcv,
134 (struct sockaddr *)&ripsrc, n,
135 opts) == 0) {
136 /* should notify about lost packet */
137 m_freem(n);
138 if (opts)
139 m_freem(opts);
140 } else
141 sorwakeup(last->inp_socket);
142 opts = 0;
143 }
144 }
145 last = inp;
146 }
147 if (last) {
148 if (last->inp_flags & INP_CONTROLOPTS ||
149 last->inp_socket->so_options & SO_TIMESTAMP)
150 ip_savecontrol(last, &opts, ip, m);
151 if (sbappendaddr(&last->inp_socket->so_rcv,
152 (struct sockaddr *)&ripsrc, m, opts) == 0) {
153 m_freem(m);
154 if (opts)
155 m_freem(opts);
156 } else
157 sorwakeup(last->inp_socket);
158 } else {
159 m_freem(m);
160 ipstat.ips_noproto++;
161 ipstat.ips_delivered--;
162 }
163}
164
165/*
166 * Generate IP header and pass packet to ip_output.
167 * Tack on options user may have setup with control call.
168 */
169int
170rip_output(m, so, dst)
171 register struct mbuf *m;
172 struct socket *so;
173 u_long dst;
174{
175 register struct ip *ip;
176 register struct inpcb *inp = sotoinpcb(so);
177 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
178
179 /*
180 * If the user handed us a complete IP packet, use it.
181 * Otherwise, allocate an mbuf for a header and fill it in.
182 */
183 if ((inp->inp_flags & INP_HDRINCL) == 0) {
184 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
185 m_freem(m);
186 return(EMSGSIZE);
187 }
188 M_PREPEND(m, sizeof(struct ip), M_WAIT);
189 ip = mtod(m, struct ip *);
190 ip->ip_tos = 0;
191 ip->ip_off = 0;
192 ip->ip_p = inp->inp_ip_p;
193 ip->ip_len = m->m_pkthdr.len;
194 ip->ip_src = inp->inp_laddr;
195 ip->ip_dst.s_addr = dst;
196 ip->ip_ttl = MAXTTL;
197 } else {
198 if (m->m_pkthdr.len > IP_MAXPACKET) {
199 m_freem(m);
200 return(EMSGSIZE);
201 }
202 ip = mtod(m, struct ip *);
203 /* don't allow both user specified and setsockopt options,
204 and don't allow packet length sizes that will crash */
205 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
206 && inp->inp_options)
207 || (ip->ip_len > m->m_pkthdr.len)
208 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
209 m_freem(m);
210 return EINVAL;
211 }
212 if (ip->ip_id == 0)
213 ip->ip_id = htons(ip_id++);
214 /* XXX prevent ip_output from overwriting header fields */
215 flags |= IP_RAWOUTPUT;
216 ipstat.ips_rawout++;
217 }
218 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
219 inp->inp_moptions));
220}
221
222/*
223 * Raw IP socket option processing.
224 */
225int
226rip_ctloutput(so, sopt)
227 struct socket *so;
228 struct sockopt *sopt;
229{
230 struct inpcb *inp = sotoinpcb(so);
231 int error, optval;
232
233 if (sopt->sopt_level != IPPROTO_IP)
234 return (EINVAL);
235
236 error = 0;
237
238 switch (sopt->sopt_dir) {
239 case SOPT_GET:
240 switch (sopt->sopt_name) {
241 case IP_HDRINCL:
242 optval = inp->inp_flags & INP_HDRINCL;
243 error = sooptcopyout(sopt, &optval, sizeof optval);
244 break;
245
246 case IP_FW_GET:
247 if (ip_fw_ctl_ptr == 0)
248 error = ENOPROTOOPT;
249 else
250 error = ip_fw_ctl_ptr(sopt);
251 break;
252
253#ifdef DUMMYNET
254 case IP_DUMMYNET_GET:
255 if (ip_dn_ctl_ptr == NULL)
256 error = ENOPROTOOPT ;
257 else
258 error = ip_dn_ctl_ptr(sopt);
259 break ;
260#endif /* DUMMYNET */
261
262 case MRT_INIT:
263 case MRT_DONE:
264 case MRT_ADD_VIF:
265 case MRT_DEL_VIF:
266 case MRT_ADD_MFC:
267 case MRT_DEL_MFC:
268 case MRT_VERSION:
269 case MRT_ASSERT:
270 error = ip_mrouter_get(so, sopt);
271 break;
272
273 default:
274 error = ip_ctloutput(so, sopt);
275 break;
276 }
277 break;
278
279 case SOPT_SET:
280 switch (sopt->sopt_name) {
281 case IP_HDRINCL:
282 error = sooptcopyin(sopt, &optval, sizeof optval,
283 sizeof optval);
284 if (error)
285 break;
286 if (optval)
287 inp->inp_flags |= INP_HDRINCL;
288 else
289 inp->inp_flags &= ~INP_HDRINCL;
290 break;
291
292 case IP_FW_ADD:
293 case IP_FW_DEL:
294 case IP_FW_FLUSH:
295 case IP_FW_ZERO:
296 if (ip_fw_ctl_ptr == 0)
297 error = ENOPROTOOPT;
298 else
299 error = ip_fw_ctl_ptr(sopt);
300 break;
301
302#ifdef DUMMYNET
303 case IP_DUMMYNET_CONFIGURE:
304 case IP_DUMMYNET_DEL:
305 case IP_DUMMYNET_FLUSH:
306 if (ip_dn_ctl_ptr == NULL)
307 error = ENOPROTOOPT ;
308 else
309 error = ip_dn_ctl_ptr(sopt);
310 break ;
311#endif
312
313 case IP_RSVP_ON:
314 error = ip_rsvp_init(so);
315 break;
316
317 case IP_RSVP_OFF:
318 error = ip_rsvp_done();
319 break;
320
321 /* XXX - should be combined */
322 case IP_RSVP_VIF_ON:
323 error = ip_rsvp_vif_init(so, sopt);
324 break;
325
326 case IP_RSVP_VIF_OFF:
327 error = ip_rsvp_vif_done(so, sopt);
328 break;
329
330 case MRT_INIT:
331 case MRT_DONE:
332 case MRT_ADD_VIF:
333 case MRT_DEL_VIF:
334 case MRT_ADD_MFC:
335 case MRT_DEL_MFC:
336 case MRT_VERSION:
337 case MRT_ASSERT:
338 error = ip_mrouter_set(so, sopt);
339 break;
340
341 default:
342 error = ip_ctloutput(so, sopt);
343 break;
344 }
345 break;
346 }
347
348 return (error);
349}
350
351/*
352 * This function exists solely to receive the PRC_IFDOWN messages which
353 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
354 * and calls in_ifadown() to remove all routes corresponding to that address.
355 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
356 * interface routes.
357 */
358void
359rip_ctlinput(cmd, sa, vip)
360 int cmd;
361 struct sockaddr *sa;
362 void *vip;
363{
364 struct in_ifaddr *ia;
365 struct ifnet *ifp;
366 int err;
367 int flags;
368
369 switch (cmd) {
370 case PRC_IFDOWN:
371 for (ia = in_ifaddrhead.tqh_first; ia;
372 ia = ia->ia_link.tqe_next) {
373 if (ia->ia_ifa.ifa_addr == sa
374 && (ia->ia_flags & IFA_ROUTE)) {
375 /*
376 * in_ifscrub kills the interface route.
377 */
378 in_ifscrub(ia->ia_ifp, ia);
379 /*
380 * in_ifadown gets rid of all the rest of
381 * the routes. This is not quite the right
382 * thing to do, but at least if we are running
383 * a routing process they will come back.
384 */
385 in_ifadown(&ia->ia_ifa);
386 break;
387 }
388 }
389 break;
390
391 case PRC_IFUP:
392 for (ia = in_ifaddrhead.tqh_first; ia;
393 ia = ia->ia_link.tqe_next) {
394 if (ia->ia_ifa.ifa_addr == sa)
395 break;
396 }
397 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
398 return;
399 flags = RTF_UP;
400 ifp = ia->ia_ifa.ifa_ifp;
401
402 if ((ifp->if_flags & IFF_LOOPBACK)
403 || (ifp->if_flags & IFF_POINTOPOINT))
404 flags |= RTF_HOST;
405
406 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
407 if (err == 0)
408 ia->ia_flags |= IFA_ROUTE;
409 break;
410 }
411}
412
413static u_long rip_sendspace = RIPSNDQ;
414static u_long rip_recvspace = RIPRCVQ;
415
416SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
417 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
418SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
419 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
420
421static int
422rip_attach(struct socket *so, int proto, struct proc *p)
423{
424 struct inpcb *inp;
425 int error, s;
426
427 inp = sotoinpcb(so);
428 if (inp)
429 panic("rip_attach");
430 if (p && (error = suser(p)) != 0)
431 return error;
432
433 s = splnet();
434 error = in_pcballoc(so, &ripcbinfo, p);
435 splx(s);
436 if (error)
437 return error;
438 error = soreserve(so, rip_sendspace, rip_recvspace);
439 if (error)
440 return error;
441 inp = (struct inpcb *)so->so_pcb;
442 inp->inp_ip_p = proto;
443 return 0;
444}
445
446static int
447rip_detach(struct socket *so)
448{
449 struct inpcb *inp;
450
451 inp = sotoinpcb(so);
452 if (inp == 0)
453 panic("rip_detach");
454 if (so == ip_mrouter)
455 ip_mrouter_done();
456 ip_rsvp_force_done(so);
457 if (so == ip_rsvpd)
458 ip_rsvp_done();
459 in_pcbdetach(inp);
460 return 0;
461}
462
463static int
464rip_abort(struct socket *so)
465{
466 soisdisconnected(so);
467 return rip_detach(so);
468}
469
470static int
471rip_disconnect(struct socket *so)
472{
473 if ((so->so_state & SS_ISCONNECTED) == 0)
474 return ENOTCONN;
475 return rip_abort(so);
476}
477
478static int
479rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
480{
481 struct inpcb *inp = sotoinpcb(so);
482 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
483
484 if (nam->sa_len != sizeof(*addr))
485 return EINVAL;
486
487 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
488 (addr->sin_family != AF_IMPLINK)) ||
489 (addr->sin_addr.s_addr &&
490 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
491 return EADDRNOTAVAIL;
492 inp->inp_laddr = addr->sin_addr;
493 return 0;
494}
495
496static int
497rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
498{
499 struct inpcb *inp = sotoinpcb(so);
500 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
501
502 if (nam->sa_len != sizeof(*addr))
503 return EINVAL;
504 if (TAILQ_EMPTY(&ifnet))
505 return EADDRNOTAVAIL;
506 if ((addr->sin_family != AF_INET) &&
507 (addr->sin_family != AF_IMPLINK))
508 return EAFNOSUPPORT;
509 inp->inp_faddr = addr->sin_addr;
510 soisconnected(so);
511 return 0;
512}
513
514static int
515rip_shutdown(struct socket *so)
516{
517 socantsendmore(so);
518 return 0;
519}
520
521static int
522rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
523 struct mbuf *control, struct proc *p)
524{
525 struct inpcb *inp = sotoinpcb(so);
526 register u_long dst;
527
528 if (so->so_state & SS_ISCONNECTED) {
529 if (nam) {
530 m_freem(m);
531 return EISCONN;
532 }
533 dst = inp->inp_faddr.s_addr;
534 } else {
535 if (nam == NULL) {
536 m_freem(m);
537 return ENOTCONN;
538 }
539 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
540 }
541 return rip_output(m, so, dst);
542}
543
544static int
545rip_pcblist SYSCTL_HANDLER_ARGS
546{
547 int error, i, n, s;
548 struct inpcb *inp, **inp_list;
549 inp_gen_t gencnt;
550 struct xinpgen xig;
551
552 /*
553 * The process of preparing the TCB list is too time-consuming and
554 * resource-intensive to repeat twice on every request.
555 */
556 if (req->oldptr == 0) {
557 n = ripcbinfo.ipi_count;
558 req->oldidx = 2 * (sizeof xig)
559 + (n + n/8) * sizeof(struct xinpcb);
560 return 0;
561 }
562
563 if (req->newptr != 0)
564 return EPERM;
565
566 /*
567 * OK, now we're committed to doing something.
568 */
569 s = splnet();
570 gencnt = ripcbinfo.ipi_gencnt;
571 n = ripcbinfo.ipi_count;
572 splx(s);
573
574 xig.xig_len = sizeof xig;
575 xig.xig_count = n;
576 xig.xig_gen = gencnt;
577 xig.xig_sogen = so_gencnt;
578 error = SYSCTL_OUT(req, &xig, sizeof xig);
579 if (error)
580 return error;
581
582 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
583 if (inp_list == 0)
584 return ENOMEM;
585
586 s = splnet();
587 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
588 inp = inp->inp_list.le_next) {
589 if (inp->inp_gencnt <= gencnt)
590 inp_list[i++] = inp;
591 }
592 splx(s);
593 n = i;
594
595 error = 0;
596 for (i = 0; i < n; i++) {
597 inp = inp_list[i];
598 if (inp->inp_gencnt <= gencnt) {
599 struct xinpcb xi;
600 xi.xi_len = sizeof xi;
601 /* XXX should avoid extra copy */
602 bcopy(inp, &xi.xi_inp, sizeof *inp);
603 if (inp->inp_socket)
604 sotoxsocket(inp->inp_socket, &xi.xi_socket);
605 error = SYSCTL_OUT(req, &xi, sizeof xi);
606 }
607 }
608 if (!error) {
609 /*
610 * Give the user an updated idea of our state.
611 * If the generation differs from what we told
612 * her before, she knows that something happened
613 * while we were processing this request, and it
614 * might be necessary to retry.
615 */
616 s = splnet();
617 xig.xig_gen = ripcbinfo.ipi_gencnt;
618 xig.xig_sogen = so_gencnt;
619 xig.xig_count = ripcbinfo.ipi_count;
620 splx(s);
621 error = SYSCTL_OUT(req, &xig, sizeof xig);
622 }
623 free(inp_list, M_TEMP);
624 return error;
625}
626
627SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
628 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
629
630struct pr_usrreqs rip_usrreqs = {
631 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
632 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
633 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
634 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
635 in_setsockaddr, sosend, soreceive, sopoll
636};