source: rtems/c/src/libnetworking/netinet/ip_divert.c @ 39e6e65a

4.104.114.84.95
Last change on this file since 39e6e65a was 39e6e65a, checked in by Joel Sherrill <joel.sherrill@…>, on 08/19/98 at 21:32:28

Base files

  • Property mode set to 100644
File size: 9.5 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 * 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 *      $Id$
34 */
35
36#include <sys/param.h>
37#include <sys/queue.h>
38#include <sys/malloc.h>
39#include <sys/mbuf.h>
40#include <sys/socket.h>
41#include <sys/protosw.h>
42#include <sys/socketvar.h>
43#include <sys/errno.h>
44#include <sys/systm.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_systm.h>
51#include <netinet/ip.h>
52#include <netinet/in_pcb.h>
53#include <netinet/in_var.h>
54#include <netinet/ip_var.h>
55
56/*
57 * Divert sockets
58 */
59
60/*
61 * Allocate enough space to hold a full IP packet
62 */
63#define DIVSNDQ         (65536 + 100)
64#define DIVRCVQ         (65536 + 100)
65
66/* Global variables */
67
68/*
69 * ip_input() and ip_output() set this secret value before calling us to
70 * let us know which divert port to divert a packet to; this is done so
71 * we can use the existing prototype for struct protosw's pr_input().
72 * This is stored in host order.
73 */
74u_short ip_divert_port;
75
76/*
77 * We set this value to a non-zero port number when we want the call to
78 * ip_fw_chk() in ip_input() or ip_output() to ignore ``divert <port>''
79 * chain entries. This is stored in host order.
80 */
81u_short ip_divert_ignore;
82
83/* Internal variables */
84
85static struct inpcbhead divcb;
86static struct inpcbinfo divcbinfo;
87
88static u_long   div_sendspace = DIVSNDQ;        /* XXX sysctl ? */
89static u_long   div_recvspace = DIVRCVQ;        /* XXX sysctl ? */
90
91/* Optimization: have this preinitialized */
92static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
93
94/* Internal functions */
95
96static int div_output(struct socket *so,
97                struct mbuf *m, struct mbuf *addr, struct mbuf *control);
98
99/*
100 * Initialize divert connection block queue.
101 */
102void
103div_init(void)
104{
105        LIST_INIT(&divcb);
106        divcbinfo.listhead = &divcb;
107        /*
108         * XXX We don't use the hash list for divert IP, but it's easier
109         * to allocate a one entry hash list than it is to check all
110         * over the place for hashbase == NULL.
111         */
112        divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask);
113}
114
115/*
116 * Setup generic address and protocol structures
117 * for div_input routine, then pass them along with
118 * mbuf chain. ip->ip_len is assumed to have had
119 * the header length (hlen) subtracted out already.
120 * We tell whether the packet was incoming or outgoing
121 * by seeing if hlen == 0, which is a hack.
122 */
123void
124div_input(struct mbuf *m, int hlen)
125{
126        struct ip *ip;
127        struct inpcb *inp;
128        struct socket *sa;
129
130        /* Sanity check */
131        if (ip_divert_port == 0)
132                panic("div_input: port is 0");
133
134        /* Assure header */
135        if (m->m_len < sizeof(struct ip) &&
136            (m = m_pullup(m, sizeof(struct ip))) == 0) {
137                return;
138        }
139        ip = mtod(m, struct ip *);
140
141        /* Record divert port */
142        divsrc.sin_port = htons(ip_divert_port);
143
144        /* Restore packet header fields */
145        ip->ip_len += hlen;
146        HTONS(ip->ip_len);
147        HTONS(ip->ip_off);
148
149        /* Record receive interface address, if any */
150        divsrc.sin_addr.s_addr = 0;
151        if (hlen) {
152                struct ifaddr *ifa;
153
154#ifdef DIAGNOSTIC
155                /* Sanity check */
156                if (!(m->m_flags & M_PKTHDR))
157                        panic("div_input: no pkt hdr");
158#endif
159
160                /* More fields affected by ip_input() */
161                HTONS(ip->ip_id);
162
163                /* Find IP address for recieve interface */
164                for (ifa = m->m_pkthdr.rcvif->if_addrlist;
165                    ifa != NULL; ifa = ifa->ifa_next) {
166                        if (ifa->ifa_addr == NULL)
167                                continue;
168                        if (ifa->ifa_addr->sa_family != AF_INET)
169                                continue;
170                        divsrc.sin_addr =
171                            ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
172                        break;
173                }
174        }
175
176        /* Put packet on socket queue, if any */
177        sa = NULL;
178        for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
179                if (inp->inp_lport == htons(ip_divert_port))
180                        sa = inp->inp_socket;
181        }
182        if (sa) {
183                if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc,
184                                m, (struct mbuf *)0) == 0)
185                        m_freem(m);
186                else
187                        sorwakeup(sa);
188        } else {
189                m_freem(m);
190                ipstat.ips_noproto++;
191                ipstat.ips_delivered--;
192        }
193}
194
195/*
196 * Deliver packet back into the IP processing machinery.
197 *
198 * If no address specified, or address is 0.0.0.0, send to ip_output();
199 * otherwise, send to ip_input() and mark as having been received on
200 * the interface with that address.
201 *
202 * If no address specified, or dest port is 0, allow packet to divert
203 * back to this socket; otherwise, don't.
204 */
205static int
206div_output(so, m, addr, control)
207        struct socket *so;
208        register struct mbuf *m;
209        struct mbuf *addr, *control;
210{
211        register struct inpcb *const inp = sotoinpcb(so);
212        register struct ip *const ip = mtod(m, struct ip *);
213        struct sockaddr_in *sin = NULL;
214        int error = 0;
215
216        if (control)
217                m_freem(control);               /* XXX */
218        if (addr)
219                sin = mtod(addr, struct sockaddr_in *);
220
221        /* Loopback avoidance option */
222        ip_divert_ignore = ntohs(inp->inp_lport);
223
224        /* Reinject packet into the system as incoming or outgoing */
225        if (!sin || sin->sin_addr.s_addr == 0) {
226                /* Don't allow both user specified and setsockopt options,
227                   and don't allow packet length sizes that will crash */
228                if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
229                     ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
230                        error = EINVAL;
231                        goto cantsend;
232                }
233
234                /* Convert fields to host order for ip_output() */
235                NTOHS(ip->ip_len);
236                NTOHS(ip->ip_off);
237
238                /* Send packet to output processing */
239                ipstat.ips_rawout++;                    /* XXX */
240                error = ip_output(m, inp->inp_options, &inp->inp_route,
241                        (so->so_options & SO_DONTROUTE) |
242                        IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions);
243        } else {
244                struct ifaddr *ifa;
245
246                /* Find receive interface with the given IP address */
247                sin->sin_port = 0;
248                if ((ifa = ifa_ifwithaddr((struct sockaddr *) sin)) == 0) {
249                        error = EADDRNOTAVAIL;
250                        goto cantsend;
251                }
252                m->m_pkthdr.rcvif = ifa->ifa_ifp;
253
254                /* Send packet to input processing */
255                ip_input(m);
256        }
257
258        /* Reset for next time (and other packets) */
259        ip_divert_ignore = 0;
260        return error;
261
262cantsend:
263        ip_divert_ignore = 0;
264        m_freem(m);
265        return error;
266}
267
268/*ARGSUSED*/
269int
270div_usrreq(so, req, m, nam, control)
271        register struct socket *so;
272        int req;
273        struct mbuf *m, *nam, *control;
274{
275        register int error = 0;
276        register struct inpcb *inp = sotoinpcb(so);
277        int s;
278
279        if (inp == NULL && req != PRU_ATTACH) {
280                error = EINVAL;
281                goto release;
282        }
283        switch (req) {
284
285        case PRU_ATTACH:
286                if (inp)
287                        panic("div_attach");
288                if ((so->so_state & SS_PRIV) == 0) {
289                        error = EACCES;
290                        break;
291                }
292                s = splnet();
293                error = in_pcballoc(so, &divcbinfo);
294                splx(s);
295                if (error)
296                        break;
297                error = soreserve(so, div_sendspace, div_recvspace);
298                if (error)
299                        break;
300                inp = (struct inpcb *)so->so_pcb;
301                inp->inp_ip_p = (int)nam;       /* XXX */
302                inp->inp_flags |= INP_HDRINCL;
303                /* The socket is always "connected" because
304                   we always know "where" to send the packet */
305                so->so_state |= SS_ISCONNECTED;
306                break;
307
308        case PRU_DISCONNECT:
309                if ((so->so_state & SS_ISCONNECTED) == 0) {
310                        error = ENOTCONN;
311                        break;
312                }
313                /* FALLTHROUGH */
314        case PRU_ABORT:
315                soisdisconnected(so);
316                /* FALLTHROUGH */
317        case PRU_DETACH:
318                if (inp == 0)
319                        panic("div_detach");
320                in_pcbdetach(inp);
321                break;
322
323        case PRU_BIND:
324                s = splnet();
325                error = in_pcbbind(inp, nam);
326                splx(s);
327                break;
328
329        /*
330         * Mark the connection as being incapable of further input.
331         */
332        case PRU_SHUTDOWN:
333                socantsendmore(so);
334                break;
335
336        case PRU_SEND:
337                /* Packet must have a header (but that's about it) */
338                if (m->m_len < sizeof (struct ip) ||
339                    (m = m_pullup(m, sizeof (struct ip))) == 0) {
340                        ipstat.ips_toosmall++;
341                        error = EINVAL;
342                        break;
343                }
344
345                /* Send packet */
346                error = div_output(so, m, nam, control);
347                m = NULL;
348                break;
349
350        case PRU_SOCKADDR:
351                in_setsockaddr(inp, nam);
352                break;
353
354        case PRU_SENSE:
355                /*
356                 * stat: don't bother with a blocksize.
357                 */
358                return (0);
359
360        /*
361         * Not supported.
362         */
363        case PRU_CONNECT:
364        case PRU_CONNECT2:
365        case PRU_CONTROL:
366        case PRU_RCVOOB:
367        case PRU_RCVD:
368        case PRU_LISTEN:
369        case PRU_ACCEPT:
370        case PRU_SENDOOB:
371        case PRU_PEERADDR:
372                error = EOPNOTSUPP;
373                break;
374
375        default:
376                panic("div_usrreq");
377        }
378release:
379        if (m)
380                m_freem(m);
381        return (error);
382}
Note: See TracBrowser for help on using the repository browser.