OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libnetworking/] [netinet/] [ip_divert.c] - Diff between revs 1026 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 1026 Rev 1765
/*
/*
 * Copyright (c) 1982, 1986, 1988, 1993
 * Copyright (c) 1982, 1986, 1988, 1993
 *      The Regents of the University of California.  All rights reserved.
 *      The Regents of the University of California.  All rights reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * modification, are permitted provided that the following conditions
 * are met:
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *    without specific prior written permission.
 *
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * SUCH DAMAGE.
 *
 *
 *      ip_divert.c,v 1.1 1998/08/19 21:32:20 joel Exp
 *      ip_divert.c,v 1.1 1998/08/19 21:32:20 joel Exp
 */
 */
 
 
#include <sys/param.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/protosw.h>
#include <sys/socketvar.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/systm.h>
 
 
#include <net/if.h>
#include <net/if.h>
#include <net/route.h>
#include <net/route.h>
 
 
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/ip_var.h>
 
 
/*
/*
 * Divert sockets
 * Divert sockets
 */
 */
 
 
/*
/*
 * Allocate enough space to hold a full IP packet
 * Allocate enough space to hold a full IP packet
 */
 */
#define DIVSNDQ         (65536 + 100)
#define DIVSNDQ         (65536 + 100)
#define DIVRCVQ         (65536 + 100)
#define DIVRCVQ         (65536 + 100)
 
 
/* Global variables */
/* Global variables */
 
 
/*
/*
 * ip_input() and ip_output() set this secret value before calling us to
 * ip_input() and ip_output() set this secret value before calling us to
 * let us know which divert port to divert a packet to; this is done so
 * let us know which divert port to divert a packet to; this is done so
 * we can use the existing prototype for struct protosw's pr_input().
 * we can use the existing prototype for struct protosw's pr_input().
 * This is stored in host order.
 * This is stored in host order.
 */
 */
u_short ip_divert_port;
u_short ip_divert_port;
 
 
/*
/*
 * We set this value to a non-zero port number when we want the call to
 * We set this value to a non-zero port number when we want the call to
 * ip_fw_chk() in ip_input() or ip_output() to ignore ``divert <port>''
 * ip_fw_chk() in ip_input() or ip_output() to ignore ``divert <port>''
 * chain entries. This is stored in host order.
 * chain entries. This is stored in host order.
 */
 */
u_short ip_divert_ignore;
u_short ip_divert_ignore;
 
 
/* Internal variables */
/* Internal variables */
 
 
static struct inpcbhead divcb;
static struct inpcbhead divcb;
static struct inpcbinfo divcbinfo;
static struct inpcbinfo divcbinfo;
 
 
static u_long   div_sendspace = DIVSNDQ;        /* XXX sysctl ? */
static u_long   div_sendspace = DIVSNDQ;        /* XXX sysctl ? */
static u_long   div_recvspace = DIVRCVQ;        /* XXX sysctl ? */
static u_long   div_recvspace = DIVRCVQ;        /* XXX sysctl ? */
 
 
/* Optimization: have this preinitialized */
/* Optimization: have this preinitialized */
static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
 
 
/* Internal functions */
/* Internal functions */
 
 
static int div_output(struct socket *so,
static int div_output(struct socket *so,
                struct mbuf *m, struct mbuf *addr, struct mbuf *control);
                struct mbuf *m, struct mbuf *addr, struct mbuf *control);
 
 
/*
/*
 * Initialize divert connection block queue.
 * Initialize divert connection block queue.
 */
 */
void
void
div_init(void)
div_init(void)
{
{
        LIST_INIT(&divcb);
        LIST_INIT(&divcb);
        divcbinfo.listhead = &divcb;
        divcbinfo.listhead = &divcb;
        /*
        /*
         * XXX We don't use the hash list for divert IP, but it's easier
         * XXX We don't use the hash list for divert IP, but it's easier
         * to allocate a one entry hash list than it is to check all
         * to allocate a one entry hash list than it is to check all
         * over the place for hashbase == NULL.
         * over the place for hashbase == NULL.
         */
         */
        divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask);
        divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask);
}
}
 
 
/*
/*
 * Setup generic address and protocol structures
 * Setup generic address and protocol structures
 * for div_input routine, then pass them along with
 * for div_input routine, then pass them along with
 * mbuf chain. ip->ip_len is assumed to have had
 * mbuf chain. ip->ip_len is assumed to have had
 * the header length (hlen) subtracted out already.
 * the header length (hlen) subtracted out already.
 * We tell whether the packet was incoming or outgoing
 * We tell whether the packet was incoming or outgoing
 * by seeing if hlen == 0, which is a hack.
 * by seeing if hlen == 0, which is a hack.
 */
 */
void
void
div_input(struct mbuf *m, int hlen)
div_input(struct mbuf *m, int hlen)
{
{
        struct ip *ip;
        struct ip *ip;
        struct inpcb *inp;
        struct inpcb *inp;
        struct socket *sa;
        struct socket *sa;
 
 
        /* Sanity check */
        /* Sanity check */
        if (ip_divert_port == 0)
        if (ip_divert_port == 0)
                panic("div_input: port is 0");
                panic("div_input: port is 0");
 
 
        /* Assure header */
        /* Assure header */
        if (m->m_len < sizeof(struct ip) &&
        if (m->m_len < sizeof(struct ip) &&
            (m = m_pullup(m, sizeof(struct ip))) == 0) {
            (m = m_pullup(m, sizeof(struct ip))) == 0) {
                return;
                return;
        }
        }
        ip = mtod(m, struct ip *);
        ip = mtod(m, struct ip *);
 
 
        /* Record divert port */
        /* Record divert port */
        divsrc.sin_port = htons(ip_divert_port);
        divsrc.sin_port = htons(ip_divert_port);
 
 
        /* Restore packet header fields */
        /* Restore packet header fields */
        ip->ip_len += hlen;
        ip->ip_len += hlen;
        HTONS(ip->ip_len);
        HTONS(ip->ip_len);
        HTONS(ip->ip_off);
        HTONS(ip->ip_off);
 
 
        /* Record receive interface address, if any */
        /* Record receive interface address, if any */
        divsrc.sin_addr.s_addr = 0;
        divsrc.sin_addr.s_addr = 0;
        if (hlen) {
        if (hlen) {
                struct ifaddr *ifa;
                struct ifaddr *ifa;
 
 
#ifdef DIAGNOSTIC
#ifdef DIAGNOSTIC
                /* Sanity check */
                /* Sanity check */
                if (!(m->m_flags & M_PKTHDR))
                if (!(m->m_flags & M_PKTHDR))
                        panic("div_input: no pkt hdr");
                        panic("div_input: no pkt hdr");
#endif
#endif
 
 
                /* More fields affected by ip_input() */
                /* More fields affected by ip_input() */
                HTONS(ip->ip_id);
                HTONS(ip->ip_id);
 
 
                /* Find IP address for recieve interface */
                /* Find IP address for recieve interface */
                for (ifa = m->m_pkthdr.rcvif->if_addrlist;
                for (ifa = m->m_pkthdr.rcvif->if_addrlist;
                    ifa != NULL; ifa = ifa->ifa_next) {
                    ifa != NULL; ifa = ifa->ifa_next) {
                        if (ifa->ifa_addr == NULL)
                        if (ifa->ifa_addr == NULL)
                                continue;
                                continue;
                        if (ifa->ifa_addr->sa_family != AF_INET)
                        if (ifa->ifa_addr->sa_family != AF_INET)
                                continue;
                                continue;
                        divsrc.sin_addr =
                        divsrc.sin_addr =
                            ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
                            ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
                        break;
                        break;
                }
                }
        }
        }
 
 
        /* Put packet on socket queue, if any */
        /* Put packet on socket queue, if any */
        sa = NULL;
        sa = NULL;
        for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
        for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
                if (inp->inp_lport == htons(ip_divert_port))
                if (inp->inp_lport == htons(ip_divert_port))
                        sa = inp->inp_socket;
                        sa = inp->inp_socket;
        }
        }
        if (sa) {
        if (sa) {
                if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc,
                if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc,
                                m, (struct mbuf *)0) == 0)
                                m, (struct mbuf *)0) == 0)
                        m_freem(m);
                        m_freem(m);
                else
                else
                        sorwakeup(sa);
                        sorwakeup(sa);
        } else {
        } else {
                m_freem(m);
                m_freem(m);
                ipstat.ips_noproto++;
                ipstat.ips_noproto++;
                ipstat.ips_delivered--;
                ipstat.ips_delivered--;
        }
        }
}
}
 
 
/*
/*
 * Deliver packet back into the IP processing machinery.
 * Deliver packet back into the IP processing machinery.
 *
 *
 * If no address specified, or address is 0.0.0.0, send to ip_output();
 * If no address specified, or address is 0.0.0.0, send to ip_output();
 * otherwise, send to ip_input() and mark as having been received on
 * otherwise, send to ip_input() and mark as having been received on
 * the interface with that address.
 * the interface with that address.
 *
 *
 * If no address specified, or dest port is 0, allow packet to divert
 * If no address specified, or dest port is 0, allow packet to divert
 * back to this socket; otherwise, don't.
 * back to this socket; otherwise, don't.
 */
 */
static int
static int
div_output(so, m, addr, control)
div_output(so, m, addr, control)
        struct socket *so;
        struct socket *so;
        register struct mbuf *m;
        register struct mbuf *m;
        struct mbuf *addr, *control;
        struct mbuf *addr, *control;
{
{
        register struct inpcb *const inp = sotoinpcb(so);
        register struct inpcb *const inp = sotoinpcb(so);
        register struct ip *const ip = mtod(m, struct ip *);
        register struct ip *const ip = mtod(m, struct ip *);
        struct sockaddr_in *sin = NULL;
        struct sockaddr_in *sin = NULL;
        int error = 0;
        int error = 0;
 
 
        if (control)
        if (control)
                m_freem(control);               /* XXX */
                m_freem(control);               /* XXX */
        if (addr)
        if (addr)
                sin = mtod(addr, struct sockaddr_in *);
                sin = mtod(addr, struct sockaddr_in *);
 
 
        /* Loopback avoidance option */
        /* Loopback avoidance option */
        ip_divert_ignore = ntohs(inp->inp_lport);
        ip_divert_ignore = ntohs(inp->inp_lport);
 
 
        /* Reinject packet into the system as incoming or outgoing */
        /* Reinject packet into the system as incoming or outgoing */
        if (!sin || sin->sin_addr.s_addr == 0) {
        if (!sin || sin->sin_addr.s_addr == 0) {
                /* Don't allow both user specified and setsockopt options,
                /* Don't allow both user specified and setsockopt options,
                   and don't allow packet length sizes that will crash */
                   and don't allow packet length sizes that will crash */
                if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
                if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
                     ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
                     ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
                        error = EINVAL;
                        error = EINVAL;
                        goto cantsend;
                        goto cantsend;
                }
                }
 
 
                /* Convert fields to host order for ip_output() */
                /* Convert fields to host order for ip_output() */
                NTOHS(ip->ip_len);
                NTOHS(ip->ip_len);
                NTOHS(ip->ip_off);
                NTOHS(ip->ip_off);
 
 
                /* Send packet to output processing */
                /* Send packet to output processing */
                ipstat.ips_rawout++;                    /* XXX */
                ipstat.ips_rawout++;                    /* XXX */
                error = ip_output(m, inp->inp_options, &inp->inp_route,
                error = ip_output(m, inp->inp_options, &inp->inp_route,
                        (so->so_options & SO_DONTROUTE) |
                        (so->so_options & SO_DONTROUTE) |
                        IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions);
                        IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions);
        } else {
        } else {
                struct ifaddr *ifa;
                struct ifaddr *ifa;
 
 
                /* Find receive interface with the given IP address */
                /* Find receive interface with the given IP address */
                sin->sin_port = 0;
                sin->sin_port = 0;
                if ((ifa = ifa_ifwithaddr((struct sockaddr *) sin)) == 0) {
                if ((ifa = ifa_ifwithaddr((struct sockaddr *) sin)) == 0) {
                        error = EADDRNOTAVAIL;
                        error = EADDRNOTAVAIL;
                        goto cantsend;
                        goto cantsend;
                }
                }
                m->m_pkthdr.rcvif = ifa->ifa_ifp;
                m->m_pkthdr.rcvif = ifa->ifa_ifp;
 
 
                /* Send packet to input processing */
                /* Send packet to input processing */
                ip_input(m);
                ip_input(m);
        }
        }
 
 
        /* Reset for next time (and other packets) */
        /* Reset for next time (and other packets) */
        ip_divert_ignore = 0;
        ip_divert_ignore = 0;
        return error;
        return error;
 
 
cantsend:
cantsend:
        ip_divert_ignore = 0;
        ip_divert_ignore = 0;
        m_freem(m);
        m_freem(m);
        return error;
        return error;
}
}
 
 
/*ARGSUSED*/
/*ARGSUSED*/
int
int
div_usrreq(so, req, m, nam, control)
div_usrreq(so, req, m, nam, control)
        register struct socket *so;
        register struct socket *so;
        int req;
        int req;
        struct mbuf *m, *nam, *control;
        struct mbuf *m, *nam, *control;
{
{
        register int error = 0;
        register int error = 0;
        register struct inpcb *inp = sotoinpcb(so);
        register struct inpcb *inp = sotoinpcb(so);
        int s;
        int s;
 
 
        if (inp == NULL && req != PRU_ATTACH) {
        if (inp == NULL && req != PRU_ATTACH) {
                error = EINVAL;
                error = EINVAL;
                goto release;
                goto release;
        }
        }
        switch (req) {
        switch (req) {
 
 
        case PRU_ATTACH:
        case PRU_ATTACH:
                if (inp)
                if (inp)
                        panic("div_attach");
                        panic("div_attach");
                if ((so->so_state & SS_PRIV) == 0) {
                if ((so->so_state & SS_PRIV) == 0) {
                        error = EACCES;
                        error = EACCES;
                        break;
                        break;
                }
                }
                s = splnet();
                s = splnet();
                error = in_pcballoc(so, &divcbinfo);
                error = in_pcballoc(so, &divcbinfo);
                splx(s);
                splx(s);
                if (error)
                if (error)
                        break;
                        break;
                error = soreserve(so, div_sendspace, div_recvspace);
                error = soreserve(so, div_sendspace, div_recvspace);
                if (error)
                if (error)
                        break;
                        break;
                inp = (struct inpcb *)so->so_pcb;
                inp = (struct inpcb *)so->so_pcb;
                inp->inp_ip_p = (int)nam;       /* XXX */
                inp->inp_ip_p = (int)nam;       /* XXX */
                inp->inp_flags |= INP_HDRINCL;
                inp->inp_flags |= INP_HDRINCL;
                /* The socket is always "connected" because
                /* The socket is always "connected" because
                   we always know "where" to send the packet */
                   we always know "where" to send the packet */
                so->so_state |= SS_ISCONNECTED;
                so->so_state |= SS_ISCONNECTED;
                break;
                break;
 
 
        case PRU_DISCONNECT:
        case PRU_DISCONNECT:
                if ((so->so_state & SS_ISCONNECTED) == 0) {
                if ((so->so_state & SS_ISCONNECTED) == 0) {
                        error = ENOTCONN;
                        error = ENOTCONN;
                        break;
                        break;
                }
                }
                /* FALLTHROUGH */
                /* FALLTHROUGH */
        case PRU_ABORT:
        case PRU_ABORT:
                soisdisconnected(so);
                soisdisconnected(so);
                /* FALLTHROUGH */
                /* FALLTHROUGH */
        case PRU_DETACH:
        case PRU_DETACH:
                if (inp == 0)
                if (inp == 0)
                        panic("div_detach");
                        panic("div_detach");
                in_pcbdetach(inp);
                in_pcbdetach(inp);
                break;
                break;
 
 
        case PRU_BIND:
        case PRU_BIND:
                s = splnet();
                s = splnet();
                error = in_pcbbind(inp, nam);
                error = in_pcbbind(inp, nam);
                splx(s);
                splx(s);
                break;
                break;
 
 
        /*
        /*
         * Mark the connection as being incapable of further input.
         * Mark the connection as being incapable of further input.
         */
         */
        case PRU_SHUTDOWN:
        case PRU_SHUTDOWN:
                socantsendmore(so);
                socantsendmore(so);
                break;
                break;
 
 
        case PRU_SEND:
        case PRU_SEND:
                /* Packet must have a header (but that's about it) */
                /* Packet must have a header (but that's about it) */
                if (m->m_len < sizeof (struct ip) ||
                if (m->m_len < sizeof (struct ip) ||
                    (m = m_pullup(m, sizeof (struct ip))) == 0) {
                    (m = m_pullup(m, sizeof (struct ip))) == 0) {
                        ipstat.ips_toosmall++;
                        ipstat.ips_toosmall++;
                        error = EINVAL;
                        error = EINVAL;
                        break;
                        break;
                }
                }
 
 
                /* Send packet */
                /* Send packet */
                error = div_output(so, m, nam, control);
                error = div_output(so, m, nam, control);
                m = NULL;
                m = NULL;
                break;
                break;
 
 
        case PRU_SOCKADDR:
        case PRU_SOCKADDR:
                in_setsockaddr(inp, nam);
                in_setsockaddr(inp, nam);
                break;
                break;
 
 
        case PRU_SENSE:
        case PRU_SENSE:
                /*
                /*
                 * stat: don't bother with a blocksize.
                 * stat: don't bother with a blocksize.
                 */
                 */
                return (0);
                return (0);
 
 
        /*
        /*
         * Not supported.
         * Not supported.
         */
         */
        case PRU_CONNECT:
        case PRU_CONNECT:
        case PRU_CONNECT2:
        case PRU_CONNECT2:
        case PRU_CONTROL:
        case PRU_CONTROL:
        case PRU_RCVOOB:
        case PRU_RCVOOB:
        case PRU_RCVD:
        case PRU_RCVD:
        case PRU_LISTEN:
        case PRU_LISTEN:
        case PRU_ACCEPT:
        case PRU_ACCEPT:
        case PRU_SENDOOB:
        case PRU_SENDOOB:
        case PRU_PEERADDR:
        case PRU_PEERADDR:
                error = EOPNOTSUPP;
                error = EOPNOTSUPP;
                break;
                break;
 
 
        default:
        default:
                panic("div_usrreq");
                panic("div_usrreq");
        }
        }
release:
release:
        if (m)
        if (m)
                m_freem(m);
                m_freem(m);
        return (error);
        return (error);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.