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