source: rtems/cpukit/libnetworking/netinet/ip_divert.c @ 0e16fa45

5
Last change on this file since 0e16fa45 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

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