]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/raw_ip.c
This commit was generated by cvs2svn to compensate for changes in r53809,
[FreeBSD/FreeBSD.git] / sys / netinet / raw_ip.c
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  * $FreeBSD$
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
69 struct  inpcbhead ripcb;
70 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  */
85 void
86 rip_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
101 static 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  */
107 void
108 rip_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  */
169 int
170 rip_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  */
225 int
226 rip_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                 case IP_FW_RESETLOG:
297                         if (ip_fw_ctl_ptr == 0)
298                                 error = ENOPROTOOPT;
299                         else
300                                 error = ip_fw_ctl_ptr(sopt);
301                         break;
302
303 #ifdef DUMMYNET
304                 case IP_DUMMYNET_CONFIGURE:
305                 case IP_DUMMYNET_DEL:
306                 case IP_DUMMYNET_FLUSH:
307                         if (ip_dn_ctl_ptr == NULL)
308                                 error = ENOPROTOOPT ;
309                         else
310                                 error = ip_dn_ctl_ptr(sopt);
311                         break ;
312 #endif
313
314                 case IP_RSVP_ON:
315                         error = ip_rsvp_init(so);
316                         break;
317
318                 case IP_RSVP_OFF:
319                         error = ip_rsvp_done();
320                         break;
321
322                         /* XXX - should be combined */
323                 case IP_RSVP_VIF_ON:
324                         error = ip_rsvp_vif_init(so, sopt);
325                         break;
326                         
327                 case IP_RSVP_VIF_OFF:
328                         error = ip_rsvp_vif_done(so, sopt);
329                         break;
330
331                 case MRT_INIT:
332                 case MRT_DONE:
333                 case MRT_ADD_VIF:
334                 case MRT_DEL_VIF:
335                 case MRT_ADD_MFC:
336                 case MRT_DEL_MFC:
337                 case MRT_VERSION:
338                 case MRT_ASSERT:
339                         error = ip_mrouter_set(so, sopt);
340                         break;
341
342                 default:
343                         error = ip_ctloutput(so, sopt);
344                         break;
345                 }
346                 break;
347         }
348
349         return (error);
350 }
351
352 /*
353  * This function exists solely to receive the PRC_IFDOWN messages which
354  * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
355  * and calls in_ifadown() to remove all routes corresponding to that address.
356  * It also receives the PRC_IFUP messages from if_up() and reinstalls the
357  * interface routes.
358  */
359 void
360 rip_ctlinput(cmd, sa, vip)
361         int cmd;
362         struct sockaddr *sa;
363         void *vip;
364 {
365         struct in_ifaddr *ia;
366         struct ifnet *ifp;
367         int err;
368         int flags;
369
370         switch (cmd) {
371         case PRC_IFDOWN:
372                 for (ia = in_ifaddrhead.tqh_first; ia;
373                      ia = ia->ia_link.tqe_next) {
374                         if (ia->ia_ifa.ifa_addr == sa
375                             && (ia->ia_flags & IFA_ROUTE)) {
376                                 /*
377                                  * in_ifscrub kills the interface route.
378                                  */
379                                 in_ifscrub(ia->ia_ifp, ia);
380                                 /*
381                                  * in_ifadown gets rid of all the rest of
382                                  * the routes.  This is not quite the right
383                                  * thing to do, but at least if we are running
384                                  * a routing process they will come back.
385                                  */
386                                 in_ifadown(&ia->ia_ifa);
387                                 break;
388                         }
389                 }
390                 break;
391
392         case PRC_IFUP:
393                 for (ia = in_ifaddrhead.tqh_first; ia;
394                      ia = ia->ia_link.tqe_next) {
395                         if (ia->ia_ifa.ifa_addr == sa)
396                                 break;
397                 }
398                 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
399                         return;
400                 flags = RTF_UP;
401                 ifp = ia->ia_ifa.ifa_ifp;
402
403                 if ((ifp->if_flags & IFF_LOOPBACK)
404                     || (ifp->if_flags & IFF_POINTOPOINT))
405                         flags |= RTF_HOST;
406
407                 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
408                 if (err == 0)
409                         ia->ia_flags |= IFA_ROUTE;
410                 break;
411         }
412 }
413
414 u_long  rip_sendspace = RIPSNDQ;
415 u_long  rip_recvspace = RIPRCVQ;
416
417 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
418     &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
419 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
420     &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
421
422 static int
423 rip_attach(struct socket *so, int proto, struct proc *p)
424 {
425         struct inpcb *inp;
426         int error, s;
427
428         inp = sotoinpcb(so);
429         if (inp)
430                 panic("rip_attach");
431         if (p && (error = suser(p)) != 0)
432                 return error;
433
434         s = splnet();
435         error = in_pcballoc(so, &ripcbinfo, p);
436         splx(s);
437         if (error)
438                 return error;
439         error = soreserve(so, rip_sendspace, rip_recvspace);
440         if (error)
441                 return error;
442         inp = (struct inpcb *)so->so_pcb;
443         inp->inp_ip_p = proto;
444         return 0;
445 }
446
447 static int
448 rip_detach(struct socket *so)
449 {
450         struct inpcb *inp;
451
452         inp = sotoinpcb(so);
453         if (inp == 0)
454                 panic("rip_detach");
455         if (so == ip_mrouter)
456                 ip_mrouter_done();
457         ip_rsvp_force_done(so);
458         if (so == ip_rsvpd)
459                 ip_rsvp_done();
460         in_pcbdetach(inp);
461         return 0;
462 }
463
464 static int
465 rip_abort(struct socket *so)
466 {
467         soisdisconnected(so);
468         return rip_detach(so);
469 }
470
471 static int
472 rip_disconnect(struct socket *so)
473 {
474         if ((so->so_state & SS_ISCONNECTED) == 0)
475                 return ENOTCONN;
476         return rip_abort(so);
477 }
478
479 static int
480 rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
481 {
482         struct inpcb *inp = sotoinpcb(so);
483         struct sockaddr_in *addr = (struct sockaddr_in *)nam;
484
485         if (nam->sa_len != sizeof(*addr))
486                 return EINVAL;
487
488         if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
489                                     (addr->sin_family != AF_IMPLINK)) ||
490             (addr->sin_addr.s_addr &&
491              ifa_ifwithaddr((struct sockaddr *)addr) == 0))
492                 return EADDRNOTAVAIL;
493         inp->inp_laddr = addr->sin_addr;
494         return 0;
495 }
496
497 static int
498 rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
499 {
500         struct inpcb *inp = sotoinpcb(so);
501         struct sockaddr_in *addr = (struct sockaddr_in *)nam;
502
503         if (nam->sa_len != sizeof(*addr))
504                 return EINVAL;
505         if (TAILQ_EMPTY(&ifnet))
506                 return EADDRNOTAVAIL;
507         if ((addr->sin_family != AF_INET) &&
508             (addr->sin_family != AF_IMPLINK))
509                 return EAFNOSUPPORT;
510         inp->inp_faddr = addr->sin_addr;
511         soisconnected(so);
512         return 0;
513 }
514
515 static int
516 rip_shutdown(struct socket *so)
517 {
518         socantsendmore(so);
519         return 0;
520 }
521
522 static int
523 rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
524          struct mbuf *control, struct proc *p)
525 {
526         struct inpcb *inp = sotoinpcb(so);
527         register u_long dst;
528
529         if (so->so_state & SS_ISCONNECTED) {
530                 if (nam) {
531                         m_freem(m);
532                         return EISCONN;
533                 }
534                 dst = inp->inp_faddr.s_addr;
535         } else {
536                 if (nam == NULL) {
537                         m_freem(m);
538                         return ENOTCONN;
539                 }
540                 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
541         }
542         return rip_output(m, so, dst);
543 }
544
545 static int
546 rip_pcblist SYSCTL_HANDLER_ARGS
547 {
548         int error, i, n, s;
549         struct inpcb *inp, **inp_list;
550         inp_gen_t gencnt;
551         struct xinpgen xig;
552
553         /*
554          * The process of preparing the TCB list is too time-consuming and
555          * resource-intensive to repeat twice on every request.
556          */
557         if (req->oldptr == 0) {
558                 n = ripcbinfo.ipi_count;
559                 req->oldidx = 2 * (sizeof xig)
560                         + (n + n/8) * sizeof(struct xinpcb);
561                 return 0;
562         }
563
564         if (req->newptr != 0)
565                 return EPERM;
566
567         /*
568          * OK, now we're committed to doing something.
569          */
570         s = splnet();
571         gencnt = ripcbinfo.ipi_gencnt;
572         n = ripcbinfo.ipi_count;
573         splx(s);
574
575         xig.xig_len = sizeof xig;
576         xig.xig_count = n;
577         xig.xig_gen = gencnt;
578         xig.xig_sogen = so_gencnt;
579         error = SYSCTL_OUT(req, &xig, sizeof xig);
580         if (error)
581                 return error;
582
583         inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
584         if (inp_list == 0)
585                 return ENOMEM;
586         
587         s = splnet();
588         for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
589              inp = inp->inp_list.le_next) {
590                 if (inp->inp_gencnt <= gencnt)
591                         inp_list[i++] = inp;
592         }
593         splx(s);
594         n = i;
595
596         error = 0;
597         for (i = 0; i < n; i++) {
598                 inp = inp_list[i];
599                 if (inp->inp_gencnt <= gencnt) {
600                         struct xinpcb xi;
601                         xi.xi_len = sizeof xi;
602                         /* XXX should avoid extra copy */
603                         bcopy(inp, &xi.xi_inp, sizeof *inp);
604                         if (inp->inp_socket)
605                                 sotoxsocket(inp->inp_socket, &xi.xi_socket);
606                         error = SYSCTL_OUT(req, &xi, sizeof xi);
607                 }
608         }
609         if (!error) {
610                 /*
611                  * Give the user an updated idea of our state.
612                  * If the generation differs from what we told
613                  * her before, she knows that something happened
614                  * while we were processing this request, and it
615                  * might be necessary to retry.
616                  */
617                 s = splnet();
618                 xig.xig_gen = ripcbinfo.ipi_gencnt;
619                 xig.xig_sogen = so_gencnt;
620                 xig.xig_count = ripcbinfo.ipi_count;
621                 splx(s);
622                 error = SYSCTL_OUT(req, &xig, sizeof xig);
623         }
624         free(inp_list, M_TEMP);
625         return error;
626 }
627
628 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
629             rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
630
631 struct pr_usrreqs rip_usrreqs = {
632         rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
633         pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
634         pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
635         pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
636         in_setsockaddr, sosend, soreceive, sopoll
637 };