source: rtems/cpukit/libnetworking/netinet/raw_ip.c @ b25b88e7

4.104.11
Last change on this file since b25b88e7 was b25b88e7, checked in by Ralf Corsepius <ralf.corsepius@…>, on Mar 28, 2010 at 5:50:29 AM

Add HAVE_CONFIG_H support to let files receive configure defines.

  • Property mode set to 100644
File size: 11.3 KB
Line 
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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *      @(#)raw_ip.c    8.7 (Berkeley) 5/15/95
30 * $FreeBSD: src/sys/netinet/raw_ip.c,v 1.147 2005/01/07 01:45:45 imp Exp $
31 */
32
33/*
34 *      $Id$
35 */
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40 
41#include "opt_inet6.h"
42#include "opt_ipsec.h"
43#include "opt_mac.h"
44
45#include <sys/param.h>
46#include <rtems/bsd/sys/queue.h>
47#include <sys/malloc.h>
48#include <sys/mbuf.h>
49#include <sys/socket.h>
50#include <sys/protosw.h>
51#include <sys/socketvar.h>
52#include <errno.h>
53#include <sys/systm.h>
54
55#include <net/if.h>
56#include <net/route.h>
57
58#define _IP_VHL
59#include <netinet/in.h>
60#include <netinet/in_systm.h>
61#include <netinet/in_pcb.h>
62#include <netinet/in_var.h>
63#include <netinet/ip.h>
64#include <netinet/ip_var.h>
65#include <netinet/ip_mroute.h>
66
67#include <netinet/ip_fw.h>
68
69#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
70#undef COMPAT_IPFW
71#define COMPAT_IPFW 1
72#else
73#undef COMPAT_IPFW
74#endif
75
76static struct inpcbhead ripcb;
77static struct inpcbinfo ripcbinfo;
78
79/*
80 * Nominal space allocated to a raw ip socket.
81 */
82#define RIPSNDQ         8192
83#define RIPRCVQ         8192
84
85/*
86 * Raw interface to IP protocol.
87 */
88
89/*
90 * Initialize raw connection block q.
91 */
92void
93rip_init(void)
94{
95        LIST_INIT(&ripcb);
96        ripcbinfo.listhead = &ripcb;
97        /*
98         * XXX We don't use the hash list for raw IP, but it's easier
99         * to allocate a one entry hash list than it is to check all
100         * over the place for hashbase == NULL.
101         */
102        ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
103}
104
105static struct   sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET, 0, {0}, {0} };
106/*
107 * Setup generic address and protocol structures
108 * for raw_input routine, then pass them along with
109 * mbuf chain.
110 */
111void
112rip_input(struct mbuf *m, int iphlen)
113{
114        struct ip *ip = mtod(m, struct ip *);
115        register struct inpcb *inp;
116        struct inpcb *last = 0;
117        struct mbuf *opts = 0;
118
119        ripsrc.sin_addr = ip->ip_src;
120        for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
121                if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p)
122                        continue;
123                if (inp->inp_laddr.s_addr &&
124                  inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
125                        continue;
126                if (inp->inp_faddr.s_addr &&
127                  inp->inp_faddr.s_addr != ip->ip_src.s_addr)
128                        continue;
129                if (last) {
130                        struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
131                        if (n) {
132                                if (last->inp_flags & INP_CONTROLOPTS ||
133                                    last->inp_socket->so_options & SO_TIMESTAMP)
134                                    ip_savecontrol(last, &opts, ip, n);
135                                if (sbappendaddr(&last->inp_socket->so_rcv,
136                                    (struct sockaddr *)&ripsrc, n,
137                                    opts) == 0) {
138                                        /* should notify about lost packet */
139                                        m_freem(n);
140                                        if (opts)
141                                            m_freem(opts);
142                                } else
143                                        sorwakeup(last->inp_socket);
144                                opts = 0;
145                        }
146                }
147                last = inp;
148        }
149        if (last) {
150                if (last->inp_flags & INP_CONTROLOPTS ||
151                    last->inp_socket->so_options & SO_TIMESTAMP)
152                        ip_savecontrol(last, &opts, ip, m);
153                if (sbappendaddr(&last->inp_socket->so_rcv,
154                    (struct sockaddr *)&ripsrc, m, opts) == 0) {
155                        m_freem(m);
156                        if (opts)
157                            m_freem(opts);
158                } else
159                        sorwakeup(last->inp_socket);
160        } else {
161                m_freem(m);
162              ipstat.ips_noproto++;
163              ipstat.ips_delivered--;
164      }
165}
166
167/*
168 * Generate IP header and pass packet to ip_output.
169 * Tack on options user may have setup with control call.
170 */
171int
172rip_output(struct mbuf *m, struct socket *so, u_long dst)
173{
174        struct ip *ip;
175        struct inpcb *inp = sotoinpcb(so);
176        int flags = ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) |
177            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#ifdef _IP_VHL
206                if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) 
207                     && inp->inp_options)
208                    || (ip->ip_len > m->m_pkthdr.len)
209                    || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
210#else
211                if (((ip->ip_hl != (sizeof (*ip) >> 2))
212                     && inp->inp_options)
213                    || (ip->ip_len > m->m_pkthdr.len)
214                    || (ip->ip_len < (ip->ip_hl << 2))) {
215#endif
216                        m_freem(m);
217                        return EINVAL;
218                }
219                if (ip->ip_id == 0)
220                        ip->ip_id = htons(ip_id++);
221                /* XXX prevent ip_output from overwriting header fields */
222                flags |= IP_RAWOUTPUT;
223                ipstat.ips_rawout++;
224        }
225        return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
226                          inp->inp_moptions));
227}
228
229/*
230 * Raw IP socket option processing.
231 */
232int
233rip_ctloutput(int op, struct socket *so, int level, int optname,
234        struct mbuf **m)
235{
236        struct inpcb *inp = sotoinpcb(so);
237        int error;
238
239        if (level != IPPROTO_IP) {
240                if (op == PRCO_SETOPT && *m)
241                        (void)m_free(*m);
242                return (EINVAL);
243        }
244
245        switch (optname) {
246
247        case IP_HDRINCL:
248                error = 0;
249                if (op == PRCO_SETOPT) {
250                        if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
251                                error = EINVAL;
252                        else if (*mtod(*m, int *))
253                                inp->inp_flags |= INP_HDRINCL;
254                        else
255                                inp->inp_flags &= ~INP_HDRINCL;
256                        if (*m)
257                                (void)m_free(*m);
258                } else {
259                        *m = m_get(M_WAIT, MT_SOOPTS);
260                        (*m)->m_len = sizeof (int);
261                        *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
262                }
263                return (error);
264
265#ifdef COMPAT_IPFW
266        case IP_FW_GET:
267                if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) {
268                        if (*m) (void)m_free(*m);
269                        return(EINVAL);
270                }
271                return (*ip_fw_ctl_ptr)(optname, m); 
272
273        case IP_FW_ADD:
274        case IP_FW_DEL:
275        case IP_FW_FLUSH:
276        case IP_FW_ZERO:
277                if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) {
278                        if (*m) (void)m_free(*m);
279                        return(EINVAL);
280                }
281                return (*ip_fw_ctl_ptr)(optname, m); 
282
283        case IP_NAT:
284                if (ip_nat_ctl_ptr == NULL) {
285                        if (*m) (void)m_free(*m);
286                        return(EINVAL);
287                }
288                return (*ip_nat_ctl_ptr)(op, m); 
289
290#endif
291        case IP_RSVP_ON:
292                return ip_rsvp_init(so);
293                break;
294
295        case IP_RSVP_OFF:
296                return ip_rsvp_done();
297                break;
298
299        case IP_RSVP_VIF_ON:
300                return ip_rsvp_vif_init(so, *m);
301
302        case IP_RSVP_VIF_OFF:
303                return ip_rsvp_vif_done(so, *m);
304
305        case MRT_INIT:
306        case MRT_DONE:
307        case MRT_ADD_VIF:
308        case MRT_DEL_VIF:
309        case MRT_ADD_MFC:
310        case MRT_DEL_MFC:
311        case MRT_VERSION:
312        case MRT_ASSERT:
313                if (op == PRCO_SETOPT) {
314                        error = ip_mrouter_set(optname, so, *m);
315                        if (*m)
316                                (void)m_free(*m);
317                } else if (op == PRCO_GETOPT) {
318                        error = ip_mrouter_get(optname, so, m);
319                } else
320                        error = EINVAL;
321                return (error);
322        }
323        return (ip_ctloutput(op, so, level, optname, m));
324}
325
326static u_long   rip_sendspace = RIPSNDQ; /* XXX sysctl ? */
327static u_long   rip_recvspace = RIPRCVQ; /* XXX sysctl ? */
328
329/*ARGSUSED*/
330int
331rip_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
332        struct mbuf *control)
333{
334        register int error = 0;
335        register struct inpcb *inp = sotoinpcb(so);
336        int s;
337
338        if (req == PRU_CONTROL)
339                return (in_control(so, (u_long)m, (caddr_t)nam,
340                        (struct ifnet *)control));
341
342        switch (req) {
343
344        case PRU_ATTACH:
345                if (inp)
346                        panic("rip_attach");
347                if ((so->so_state & SS_PRIV) == 0) {
348                        error = EACCES;
349                        break;
350                }
351                s = splnet();
352                error = in_pcballoc(so, &ripcbinfo);
353                splx(s);
354                if (error)
355                        break;
356                error = soreserve(so, rip_sendspace, rip_recvspace);
357                if (error)
358                        break;
359                inp = (struct inpcb *)so->so_pcb;
360                inp->inp_ip_p = (int)nam;
361                break;
362
363        case PRU_DISCONNECT:
364                if ((so->so_state & SS_ISCONNECTED) == 0) {
365                        error = ENOTCONN;
366                        break;
367                }
368                /* FALLTHROUGH */
369        case PRU_ABORT:
370                soisdisconnected(so);
371                /* FALLTHROUGH */
372        case PRU_DETACH:
373                if (inp == 0)
374                        panic("rip_detach");
375                if (so == ip_mrouter)
376                        ip_mrouter_done();
377                ip_rsvp_force_done(so);
378                if (so == ip_rsvpd)
379                        ip_rsvp_done();
380                in_pcbdetach(inp);
381                break;
382
383        case PRU_BIND:
384            {
385                struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
386
387                if (nam->m_len != sizeof(*addr)) {
388                        error = EINVAL;
389                        break;
390                }
391                if ((ifnet == 0) ||
392                    ((addr->sin_family != AF_INET) &&
393                     (addr->sin_family != AF_IMPLINK)) ||
394                    (addr->sin_addr.s_addr &&
395                     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
396                        error = EADDRNOTAVAIL;
397                        break;
398                }
399                inp->inp_laddr = addr->sin_addr;
400                break;
401            }
402        case PRU_CONNECT:
403            {
404                struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
405
406                if (nam->m_len != sizeof(*addr)) {
407                        error = EINVAL;
408                        break;
409                }
410                if (ifnet == 0) {
411                        error = EADDRNOTAVAIL;
412                        break;
413                }
414                if ((addr->sin_family != AF_INET) &&
415                     (addr->sin_family != AF_IMPLINK)) {
416                        error = EAFNOSUPPORT;
417                        break;
418                }
419                inp->inp_faddr = addr->sin_addr;
420                soisconnected(so);
421                break;
422            }
423
424        case PRU_CONNECT2:
425                error = EOPNOTSUPP;
426                break;
427
428        /*
429         * Mark the connection as being incapable of further input.
430         */
431        case PRU_SHUTDOWN:
432                socantsendmore(so);
433                break;
434
435        /*
436         * Ship a packet out.  The appropriate raw output
437         * routine handles any massaging necessary.
438         */
439        case PRU_SEND:
440            {
441                register u_long dst;
442
443                if (so->so_state & SS_ISCONNECTED) {
444                        if (nam) {
445                                error = EISCONN;
446                                break;
447                        }
448                        dst = inp->inp_faddr.s_addr;
449                } else {
450                        if (nam == NULL) {
451                                error = ENOTCONN;
452                                break;
453                        }
454                        dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
455                }
456                error = rip_output(m, so, dst);
457                m = NULL;
458                break;
459            }
460
461        case PRU_SENSE:
462                /*
463                 * stat: don't bother with a blocksize.
464                 */
465                return (0);
466
467        /*
468         * Not supported.
469         */
470        case PRU_RCVOOB:
471        case PRU_RCVD:
472        case PRU_LISTEN:
473        case PRU_ACCEPT:
474        case PRU_SENDOOB:
475                error = EOPNOTSUPP;
476                break;
477
478        case PRU_SOCKADDR:
479                in_setsockaddr(inp, nam);
480                break;
481
482        case PRU_PEERADDR:
483                in_setpeeraddr(inp, nam);
484                break;
485
486        default:
487                panic("rip_usrreq");
488        }
489        if (m != NULL)
490                m_freem(m);
491        return (error);
492}
Note: See TracBrowser for help on using the repository browser.