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