1 /* $OpenBSD: raw_ip.c,v 1.32 2003/12/21 14:57:19 markus 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
rip_init()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
rip_input(struct mbuf * m,...)120 rip_input(struct mbuf *m, ...)
121 {
122 struct ip *ip = mtod(m, struct ip *);
123 struct inpcb *inp;
124 struct socket *last = 0;
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 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
143 if (sbappendaddr(&last->so_rcv,
144 sintosa(&ripsrc), n,
145 (struct mbuf *)0) == 0)
146 /* should notify about lost packet */
147 m_freem(n);
148 else
149 sorwakeup(last);
150 }
151 }
152 last = inp->inp_socket;
153 }
154 if (last) {
155 if (sbappendaddr(&last->so_rcv, sintosa(&ripsrc), m,
156 (struct mbuf *)0) == 0)
157 m_freem(m);
158 else
159 sorwakeup(last);
160 } else {
161 if (ip->ip_p != IPPROTO_ICMP)
162 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
163 else
164 m_freem(m);
165 ipstat.ips_noproto++;
166 ipstat.ips_delivered--;
167 }
168 }
169
170 /*
171 * Generate IP header and pass packet to ip_output.
172 * Tack on options user may have setup with control call.
173 */
174 int
rip_output(struct mbuf * m,...)175 rip_output(struct mbuf *m, ...)
176 {
177 struct socket *so;
178 u_long dst;
179 struct ip *ip;
180 struct inpcb *inp;
181 int flags;
182 va_list ap;
183
184 va_start(ap, m);
185 so = va_arg(ap, struct socket *);
186 dst = va_arg(ap, u_long);
187 va_end(ap);
188
189 inp = sotoinpcb(so);
190 flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
191
192 /*
193 * If the user handed us a complete IP packet, use it.
194 * Otherwise, allocate an mbuf for a header and fill it in.
195 */
196 if ((inp->inp_flags & INP_HDRINCL) == 0) {
197 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
198 m_freem(m);
199 return (EMSGSIZE);
200 }
201 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
202 if (!m)
203 return (ENOBUFS);
204 ip = mtod(m, struct ip *);
205 ip->ip_tos = 0;
206 ip->ip_off = htons(0);
207 ip->ip_p = inp->inp_ip.ip_p;
208 ip->ip_len = htons(m->m_pkthdr.len);
209 ip->ip_src = inp->inp_laddr;
210 ip->ip_dst.s_addr = dst;
211 ip->ip_ttl = MAXTTL;
212 } else {
213 if (m->m_pkthdr.len > IP_MAXPACKET) {
214 m_freem(m);
215 return (EMSGSIZE);
216 }
217 if (m->m_pkthdr.len < sizeof(struct ip)) {
218 m_freem(m);
219 return (EINVAL);
220 }
221 ip = mtod(m, struct ip *);
222 /*
223 * don't allow both user specified and setsockopt options,
224 * and don't allow packet length sizes that will crash
225 */
226 if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) ||
227 ntohs(ip->ip_len) > m->m_pkthdr.len ||
228 ntohs(ip->ip_len) < ip->ip_hl << 2) {
229 m_freem(m);
230 return (EINVAL);
231 }
232 if (ip->ip_id == 0) {
233 ip->ip_id = htons(ip_randomid());
234 }
235 /* XXX prevent ip_output from overwriting header fields */
236 flags |= IP_RAWOUTPUT;
237 ipstat.ips_rawout++;
238 }
239 #ifdef INET6
240 /*
241 * A thought: Even though raw IP shouldn't be able to set IPv6
242 * multicast options, if it does, the last parameter to
243 * ip_output should be guarded against v6/v4 problems.
244 */
245 #endif
246 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
247 inp->inp_moptions, inp));
248 }
249
250 /*
251 * Raw IP socket option processing.
252 */
253 int
rip_ctloutput(op,so,level,optname,m)254 rip_ctloutput(op, so, level, optname, m)
255 int op;
256 struct socket *so;
257 int level, optname;
258 struct mbuf **m;
259 {
260 struct inpcb *inp = sotoinpcb(so);
261 int error;
262
263 if (level != IPPROTO_IP) {
264 if (op == PRCO_SETOPT && *m)
265 (void) m_free(*m);
266 return (EINVAL);
267 }
268
269 switch (optname) {
270
271 case IP_HDRINCL:
272 error = 0;
273 if (op == PRCO_SETOPT) {
274 if (*m == 0 || (*m)->m_len < sizeof (int))
275 error = EINVAL;
276 else if (*mtod(*m, int *))
277 inp->inp_flags |= INP_HDRINCL;
278 else
279 inp->inp_flags &= ~INP_HDRINCL;
280 if (*m)
281 (void)m_free(*m);
282 } else {
283 *m = m_get(M_WAIT, M_SOOPTS);
284 (*m)->m_len = sizeof(int);
285 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
286 }
287 return (error);
288
289 case MRT_INIT:
290 case MRT_DONE:
291 case MRT_ADD_VIF:
292 case MRT_DEL_VIF:
293 case MRT_ADD_MFC:
294 case MRT_DEL_MFC:
295 case MRT_VERSION:
296 case MRT_ASSERT:
297 #ifdef MROUTING
298 switch (op) {
299 case PRCO_SETOPT:
300 error = ip_mrouter_set(optname, so, m);
301 break;
302 case PRCO_GETOPT:
303 error = ip_mrouter_get(optname, so, m);
304 break;
305 default:
306 error = EINVAL;
307 break;
308 }
309 return (error);
310 #else
311 if (op == PRCO_SETOPT && *m)
312 m_free(*m);
313 return (EOPNOTSUPP);
314 #endif
315 }
316 return (ip_ctloutput(op, so, level, optname, m));
317 }
318
319 u_long rip_sendspace = RIPSNDQ;
320 u_long rip_recvspace = RIPRCVQ;
321
322 /*ARGSUSED*/
323 int
rip_usrreq(so,req,m,nam,control)324 rip_usrreq(so, req, m, nam, control)
325 struct socket *so;
326 int req;
327 struct mbuf *m, *nam, *control;
328 {
329 int error = 0;
330 struct inpcb *inp = sotoinpcb(so);
331 #ifdef MROUTING
332 extern struct socket *ip_mrouter;
333 #endif
334 if (req == PRU_CONTROL)
335 return (in_control(so, (u_long)m, (caddr_t)nam,
336 (struct ifnet *)control));
337
338 if (inp == NULL && req != PRU_ATTACH) {
339 error = EINVAL;
340 goto release;
341 }
342
343 switch (req) {
344
345 case PRU_ATTACH:
346 if (inp)
347 panic("rip_attach");
348 if ((so->so_state & SS_PRIV) == 0) {
349 error = EACCES;
350 break;
351 }
352 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
353 (error = in_pcballoc(so, &rawcbtable)))
354 break;
355 inp = (struct inpcb *)so->so_pcb;
356 inp->inp_ip.ip_p = (long)nam;
357 break;
358
359 case PRU_DISCONNECT:
360 if ((so->so_state & SS_ISCONNECTED) == 0) {
361 error = ENOTCONN;
362 break;
363 }
364 /* FALLTHROUGH */
365 case PRU_ABORT:
366 soisdisconnected(so);
367 /* FALLTHROUGH */
368 case PRU_DETACH:
369 if (inp == 0)
370 panic("rip_detach");
371 #ifdef MROUTING
372 if (so == ip_mrouter)
373 ip_mrouter_done();
374 #endif
375 in_pcbdetach(inp);
376 break;
377
378 case PRU_BIND:
379 {
380 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
381
382 if (nam->m_len != sizeof(*addr)) {
383 error = EINVAL;
384 break;
385 }
386 if ((ifnet.tqh_first == 0) ||
387 ((addr->sin_family != AF_INET) &&
388 (addr->sin_family != AF_IMPLINK)) ||
389 (addr->sin_addr.s_addr &&
390 ifa_ifwithaddr(sintosa(addr)) == 0)) {
391 error = EADDRNOTAVAIL;
392 break;
393 }
394 inp->inp_laddr = addr->sin_addr;
395 break;
396 }
397 case PRU_CONNECT:
398 {
399 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
400
401 if (nam->m_len != sizeof(*addr)) {
402 error = EINVAL;
403 break;
404 }
405 if (ifnet.tqh_first == 0) {
406 error = EADDRNOTAVAIL;
407 break;
408 }
409 if ((addr->sin_family != AF_INET) &&
410 (addr->sin_family != AF_IMPLINK)) {
411 error = EAFNOSUPPORT;
412 break;
413 }
414 inp->inp_faddr = addr->sin_addr;
415 soisconnected(so);
416 break;
417 }
418
419 case PRU_CONNECT2:
420 error = EOPNOTSUPP;
421 break;
422
423 /*
424 * Mark the connection as being incapable of further input.
425 */
426 case PRU_SHUTDOWN:
427 socantsendmore(so);
428 break;
429
430 /*
431 * Ship a packet out. The appropriate raw output
432 * routine handles any massaging necessary.
433 */
434 case PRU_SEND:
435 {
436 u_int32_t dst;
437
438 if (so->so_state & SS_ISCONNECTED) {
439 if (nam) {
440 error = EISCONN;
441 break;
442 }
443 dst = inp->inp_faddr.s_addr;
444 } else {
445 if (nam == NULL) {
446 error = ENOTCONN;
447 break;
448 }
449 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
450 }
451 #ifdef IPSEC
452 /* XXX Find an IPsec TDB */
453 #endif
454 error = rip_output(m, so, dst);
455 m = NULL;
456 break;
457 }
458
459 case PRU_SENSE:
460 /*
461 * stat: don't bother with a blocksize.
462 */
463 return (0);
464
465 /*
466 * Not supported.
467 */
468 case PRU_RCVOOB:
469 case PRU_RCVD:
470 case PRU_LISTEN:
471 case PRU_ACCEPT:
472 case PRU_SENDOOB:
473 error = EOPNOTSUPP;
474 break;
475
476 case PRU_SOCKADDR:
477 in_setsockaddr(inp, nam);
478 break;
479
480 case PRU_PEERADDR:
481 in_setpeeraddr(inp, nam);
482 break;
483
484 default:
485 panic("rip_usrreq");
486 }
487 release:
488 if (m != NULL)
489 m_freem(m);
490 return (error);
491 }
492