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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libnetworking/] [netinet/] [ip_divert.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1026 ivang
/*
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
 *      ip_divert.c,v 1.1 1998/08/19 21:32:20 joel Exp
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
 */
74
u_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
 */
81
u_short ip_divert_ignore;
82
 
83
/* Internal variables */
84
 
85
static struct inpcbhead divcb;
86
static struct inpcbinfo divcbinfo;
87
 
88
static u_long   div_sendspace = DIVSNDQ;        /* XXX sysctl ? */
89
static u_long   div_recvspace = DIVRCVQ;        /* XXX sysctl ? */
90
 
91
/* Optimization: have this preinitialized */
92
static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
93
 
94
/* Internal functions */
95
 
96
static 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
 */
102
void
103
div_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
 */
123
void
124
div_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
 */
205
static int
206
div_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
 
262
cantsend:
263
        ip_divert_ignore = 0;
264
        m_freem(m);
265
        return error;
266
}
267
 
268
/*ARGSUSED*/
269
int
270
div_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
        }
378
release:
379
        if (m)
380
                m_freem(m);
381
        return (error);
382
}

powered by: WebSVN 2.1.0

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