Annotation of sys/netinet/raw_ip.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: raw_ip.c,v 1.40 2006/11/25 18:04:44 claudio Exp $ */
2: /* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1982, 1986, 1988, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: *
32: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
33: *
34: * NRL grants permission for redistribution and use in source and binary
35: * forms, with or without modification, of the software and documentation
36: * created at NRL provided that the following conditions are met:
37: *
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgements:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * This product includes software developed at the Information
48: * Technology Division, US Naval Research Laboratory.
49: * 4. Neither the name of the NRL nor the names of its contributors
50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
54: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
56: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
57: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64: *
65: * The views and conclusions contained in the software and documentation
66: * are those of the authors and should not be interpreted as representing
67: * official policies, either expressed or implied, of the US Naval
68: * Research Laboratory (NRL).
69: */
70:
71: #include <sys/param.h>
72: #include <sys/systm.h>
73: #include <sys/mbuf.h>
74: #include <sys/socket.h>
75: #include <sys/protosw.h>
76: #include <sys/socketvar.h>
77:
78: #include <net/if.h>
79: #include <net/route.h>
80:
81: #include <netinet/in.h>
82: #include <netinet/in_systm.h>
83: #include <netinet/ip.h>
84: #include <netinet/ip_mroute.h>
85: #include <netinet/ip_var.h>
86: #include <netinet/in_pcb.h>
87: #include <netinet/in_var.h>
88: #include <netinet/ip_icmp.h>
89:
90: struct inpcbtable rawcbtable;
91:
92: /*
93: * Nominal space allocated to a raw ip socket.
94: */
95: #define RIPSNDQ 8192
96: #define RIPRCVQ 8192
97:
98: /*
99: * Raw interface to IP protocol.
100: */
101:
102: /*
103: * Initialize raw connection block q.
104: */
105: void
106: rip_init()
107: {
108:
109: in_pcbinit(&rawcbtable, 1);
110: }
111:
112: struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
113:
114: /*
115: * Setup generic address and protocol structures
116: * for raw_input routine, then pass them along with
117: * mbuf chain.
118: */
119: void
120: rip_input(struct mbuf *m, ...)
121: {
122: struct ip *ip = mtod(m, struct ip *);
123: struct inpcb *inp, *last = NULL;
124: struct mbuf *opts = NULL;
125:
126: ripsrc.sin_addr = ip->ip_src;
127: CIRCLEQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
128: #ifdef INET6
129: if (inp->inp_flags & INP_IPV6)
130: continue;
131: #endif
132: if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
133: continue;
134: if (inp->inp_laddr.s_addr &&
135: inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
136: continue;
137: if (inp->inp_faddr.s_addr &&
138: inp->inp_faddr.s_addr != ip->ip_src.s_addr)
139: continue;
140: if (last) {
141: struct mbuf *n;
142:
143: if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
144: if (last->inp_flags & INP_CONTROLOPTS)
145: ip_savecontrol(last, &opts, ip, n);
146: if (sbappendaddr(&last->inp_socket->so_rcv,
147: sintosa(&ripsrc), n, opts) == 0) {
148: /* should notify about lost packet */
149: m_freem(n);
150: if (opts)
151: m_freem(opts);
152: } else
153: sorwakeup(last->inp_socket);
154: opts = NULL;
155: }
156: }
157: last = inp;
158: }
159: if (last) {
160: if (last->inp_flags & INP_CONTROLOPTS)
161: ip_savecontrol(last, &opts, ip, m);
162: if (sbappendaddr(&last->inp_socket->so_rcv, sintosa(&ripsrc), m,
163: opts) == 0) {
164: m_freem(m);
165: if (opts)
166: m_freem(opts);
167: } else
168: sorwakeup(last->inp_socket);
169: } else {
170: if (ip->ip_p != IPPROTO_ICMP)
171: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
172: else
173: m_freem(m);
174: ipstat.ips_noproto++;
175: ipstat.ips_delivered--;
176: }
177: }
178:
179: /*
180: * Generate IP header and pass packet to ip_output.
181: * Tack on options user may have setup with control call.
182: */
183: int
184: rip_output(struct mbuf *m, ...)
185: {
186: struct socket *so;
187: u_long dst;
188: struct ip *ip;
189: struct inpcb *inp;
190: int flags;
191: va_list ap;
192:
193: va_start(ap, m);
194: so = va_arg(ap, struct socket *);
195: dst = va_arg(ap, u_long);
196: va_end(ap);
197:
198: inp = sotoinpcb(so);
199: flags = (so->so_options & (SO_DONTROUTE|SO_JUMBO)) | IP_ALLOWBROADCAST;
200:
201: /*
202: * If the user handed us a complete IP packet, use it.
203: * Otherwise, allocate an mbuf for a header and fill it in.
204: */
205: if ((inp->inp_flags & INP_HDRINCL) == 0) {
206: if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
207: m_freem(m);
208: return (EMSGSIZE);
209: }
210: M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
211: if (!m)
212: return (ENOBUFS);
213: ip = mtod(m, struct ip *);
214: ip->ip_tos = inp->inp_ip.ip_tos;
215: ip->ip_off = htons(0);
216: ip->ip_p = inp->inp_ip.ip_p;
217: ip->ip_len = htons(m->m_pkthdr.len);
218: ip->ip_src = inp->inp_laddr;
219: ip->ip_dst.s_addr = dst;
220: ip->ip_ttl = inp->inp_ip.ip_ttl ? inp->inp_ip.ip_ttl : MAXTTL;
221: } else {
222: if (m->m_pkthdr.len > IP_MAXPACKET) {
223: m_freem(m);
224: return (EMSGSIZE);
225: }
226: if (m->m_pkthdr.len < sizeof(struct ip)) {
227: m_freem(m);
228: return (EINVAL);
229: }
230: ip = mtod(m, struct ip *);
231: /*
232: * don't allow both user specified and setsockopt options,
233: * and don't allow packet length sizes that will crash
234: */
235: if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) ||
236: ntohs(ip->ip_len) > m->m_pkthdr.len ||
237: ntohs(ip->ip_len) < ip->ip_hl << 2) {
238: m_freem(m);
239: return (EINVAL);
240: }
241: if (ip->ip_id == 0) {
242: ip->ip_id = htons(ip_randomid());
243: }
244: /* XXX prevent ip_output from overwriting header fields */
245: flags |= IP_RAWOUTPUT;
246: ipstat.ips_rawout++;
247: }
248: #ifdef INET6
249: /*
250: * A thought: Even though raw IP shouldn't be able to set IPv6
251: * multicast options, if it does, the last parameter to
252: * ip_output should be guarded against v6/v4 problems.
253: */
254: #endif
255: return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
256: inp->inp_moptions, inp));
257: }
258:
259: /*
260: * Raw IP socket option processing.
261: */
262: int
263: rip_ctloutput(int op, struct socket *so, int level, int optname,
264: struct mbuf **m)
265: {
266: struct inpcb *inp = sotoinpcb(so);
267: int error;
268:
269: if (level != IPPROTO_IP) {
270: if (op == PRCO_SETOPT && *m)
271: (void) m_free(*m);
272: return (EINVAL);
273: }
274:
275: switch (optname) {
276:
277: case IP_HDRINCL:
278: error = 0;
279: if (op == PRCO_SETOPT) {
280: if (*m == 0 || (*m)->m_len < sizeof (int))
281: error = EINVAL;
282: else if (*mtod(*m, int *))
283: inp->inp_flags |= INP_HDRINCL;
284: else
285: inp->inp_flags &= ~INP_HDRINCL;
286: if (*m)
287: (void)m_free(*m);
288: } else {
289: *m = m_get(M_WAIT, M_SOOPTS);
290: (*m)->m_len = sizeof(int);
291: *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
292: }
293: return (error);
294:
295: case MRT_INIT:
296: case MRT_DONE:
297: case MRT_ADD_VIF:
298: case MRT_DEL_VIF:
299: case MRT_ADD_MFC:
300: case MRT_DEL_MFC:
301: case MRT_VERSION:
302: case MRT_ASSERT:
303: case MRT_API_SUPPORT:
304: case MRT_API_CONFIG:
305: case MRT_ADD_BW_UPCALL:
306: case MRT_DEL_BW_UPCALL:
307: #ifdef MROUTING
308: switch (op) {
309: case PRCO_SETOPT:
310: error = ip_mrouter_set(so, optname, m);
311: break;
312: case PRCO_GETOPT:
313: error = ip_mrouter_get(so, optname, m);
314: break;
315: default:
316: error = EINVAL;
317: break;
318: }
319: return (error);
320: #else
321: if (op == PRCO_SETOPT && *m)
322: m_free(*m);
323: return (EOPNOTSUPP);
324: #endif
325: }
326: return (ip_ctloutput(op, so, level, optname, m));
327: }
328:
329: u_long rip_sendspace = RIPSNDQ;
330: u_long rip_recvspace = RIPRCVQ;
331:
332: /*ARGSUSED*/
333: int
334: rip_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
335: struct mbuf *control)
336: {
337: int error = 0;
338: struct inpcb *inp = sotoinpcb(so);
339: #ifdef MROUTING
340: extern struct socket *ip_mrouter;
341: #endif
342: if (req == PRU_CONTROL)
343: return (in_control(so, (u_long)m, (caddr_t)nam,
344: (struct ifnet *)control));
345:
346: if (inp == NULL && req != PRU_ATTACH) {
347: error = EINVAL;
348: goto release;
349: }
350:
351: switch (req) {
352:
353: case PRU_ATTACH:
354: if (inp)
355: panic("rip_attach");
356: if ((so->so_state & SS_PRIV) == 0) {
357: error = EACCES;
358: break;
359: }
360: if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
361: (error = in_pcballoc(so, &rawcbtable)))
362: break;
363: inp = (struct inpcb *)so->so_pcb;
364: inp->inp_ip.ip_p = (long)nam;
365: break;
366:
367: case PRU_DISCONNECT:
368: if ((so->so_state & SS_ISCONNECTED) == 0) {
369: error = ENOTCONN;
370: break;
371: }
372: /* FALLTHROUGH */
373: case PRU_ABORT:
374: soisdisconnected(so);
375: /* FALLTHROUGH */
376: case PRU_DETACH:
377: if (inp == 0)
378: panic("rip_detach");
379: #ifdef MROUTING
380: if (so == ip_mrouter)
381: ip_mrouter_done();
382: #endif
383: in_pcbdetach(inp);
384: break;
385:
386: case PRU_BIND:
387: {
388: struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
389:
390: if (nam->m_len != sizeof(*addr)) {
391: error = EINVAL;
392: break;
393: }
394: if ((TAILQ_EMPTY(&ifnet)) ||
395: ((addr->sin_family != AF_INET) &&
396: (addr->sin_family != AF_IMPLINK)) ||
397: (addr->sin_addr.s_addr &&
398: ifa_ifwithaddr(sintosa(addr)) == 0)) {
399: error = EADDRNOTAVAIL;
400: break;
401: }
402: inp->inp_laddr = addr->sin_addr;
403: break;
404: }
405: case PRU_CONNECT:
406: {
407: struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
408:
409: if (nam->m_len != sizeof(*addr)) {
410: error = EINVAL;
411: break;
412: }
413: if (TAILQ_EMPTY(&ifnet)) {
414: error = EADDRNOTAVAIL;
415: break;
416: }
417: if ((addr->sin_family != AF_INET) &&
418: (addr->sin_family != AF_IMPLINK)) {
419: error = EAFNOSUPPORT;
420: break;
421: }
422: inp->inp_faddr = addr->sin_addr;
423: soisconnected(so);
424: break;
425: }
426:
427: case PRU_CONNECT2:
428: error = EOPNOTSUPP;
429: break;
430:
431: /*
432: * Mark the connection as being incapable of further input.
433: */
434: case PRU_SHUTDOWN:
435: socantsendmore(so);
436: break;
437:
438: /*
439: * Ship a packet out. The appropriate raw output
440: * routine handles any massaging necessary.
441: */
442: case PRU_SEND:
443: {
444: u_int32_t dst;
445:
446: if (so->so_state & SS_ISCONNECTED) {
447: if (nam) {
448: error = EISCONN;
449: break;
450: }
451: dst = inp->inp_faddr.s_addr;
452: } else {
453: if (nam == NULL) {
454: error = ENOTCONN;
455: break;
456: }
457: dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
458: }
459: #ifdef IPSEC
460: /* XXX Find an IPsec TDB */
461: #endif
462: error = rip_output(m, so, dst);
463: m = NULL;
464: break;
465: }
466:
467: case PRU_SENSE:
468: /*
469: * stat: don't bother with a blocksize.
470: */
471: return (0);
472:
473: /*
474: * Not supported.
475: */
476: case PRU_RCVOOB:
477: case PRU_RCVD:
478: case PRU_LISTEN:
479: case PRU_ACCEPT:
480: case PRU_SENDOOB:
481: error = EOPNOTSUPP;
482: break;
483:
484: case PRU_SOCKADDR:
485: in_setsockaddr(inp, nam);
486: break;
487:
488: case PRU_PEERADDR:
489: in_setpeeraddr(inp, nam);
490: break;
491:
492: default:
493: panic("rip_usrreq");
494: }
495: release:
496: if (m != NULL)
497: m_freem(m);
498: return (error);
499: }
CVSweb