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 }