raw_ip.c revision 1.36.10.1 1 /* $NetBSD: raw_ip.c,v 1.36.10.1 1997/10/14 10:29:34 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 | IP_RETURNMTU;
186
187 /*
188 * If the user handed us a complete IP packet, use it.
189 * Otherwise, allocate an mbuf for a header and fill it in.
190 */
191 if ((inp->inp_flags & INP_HDRINCL) == 0) {
192 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
193 m_freem(m);
194 return (EMSGSIZE);
195 }
196 M_PREPEND(m, sizeof(struct ip), M_WAIT);
197 ip = mtod(m, struct ip *);
198 ip->ip_tos = 0;
199 ip->ip_off = 0;
200 ip->ip_p = inp->inp_ip.ip_p;
201 ip->ip_len = m->m_pkthdr.len;
202 ip->ip_src = inp->inp_laddr;
203 ip->ip_dst = inp->inp_faddr;
204 ip->ip_ttl = MAXTTL;
205 opts = inp->inp_options;
206 } else {
207 if (m->m_pkthdr.len > IP_MAXPACKET) {
208 m_freem(m);
209 return (EMSGSIZE);
210 }
211 ip = mtod(m, struct ip *);
212 if (ip->ip_id == 0)
213 ip->ip_id = htons(ip_id++);
214 opts = NULL;
215 /* XXX prevent ip_output from overwriting header fields */
216 flags |= IP_RAWOUTPUT;
217 ipstat.ips_rawout++;
218 }
219 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu));
220 }
221
222 /*
223 * Raw IP socket option processing.
224 */
225 int
226 rip_ctloutput(op, so, level, optname, m)
227 int op;
228 struct socket *so;
229 int level, optname;
230 struct mbuf **m;
231 {
232 register struct inpcb *inp = sotoinpcb(so);
233 int error = 0;
234
235 if (level != IPPROTO_IP) {
236 error = ENOPROTOOPT;
237 if (op == PRCO_SETOPT && *m != 0)
238 (void) m_free(*m);
239 } else switch (op) {
240
241 case PRCO_SETOPT:
242 switch (optname) {
243 case IP_HDRINCL:
244 if (*m == 0 || (*m)->m_len < sizeof (int))
245 error = EINVAL;
246 else {
247 if (*mtod(*m, int *))
248 inp->inp_flags |= INP_HDRINCL;
249 else
250 inp->inp_flags &= ~INP_HDRINCL;
251 }
252 if (*m != 0)
253 (void) m_free(*m);
254 break;
255
256 #ifdef MROUTING
257 case MRT_INIT:
258 case MRT_DONE:
259 case MRT_ADD_VIF:
260 case MRT_DEL_VIF:
261 case MRT_ADD_MFC:
262 case MRT_DEL_MFC:
263 case MRT_ASSERT:
264 error = ip_mrouter_set(so, optname, m);
265 break;
266 #endif
267
268 default:
269 error = ip_ctloutput(op, so, level, optname, m);
270 break;
271 }
272 break;
273
274 case PRCO_GETOPT:
275 switch (optname) {
276 case IP_HDRINCL:
277 *m = m_get(M_WAIT, M_SOOPTS);
278 (*m)->m_len = sizeof (int);
279 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0;
280 break;
281
282 #ifdef MROUTING
283 case MRT_VERSION:
284 case MRT_ASSERT:
285 error = ip_mrouter_get(so, optname, m);
286 break;
287 #endif
288
289 default:
290 error = ip_ctloutput(op, so, level, optname, m);
291 break;
292 }
293 break;
294 }
295 return (error);
296 }
297
298 int
299 rip_bind(inp, nam)
300 struct inpcb *inp;
301 struct mbuf *nam;
302 {
303 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
304
305 if (nam->m_len != sizeof(*addr))
306 return (EINVAL);
307 if (ifnet.tqh_first == 0)
308 return (EADDRNOTAVAIL);
309 if (addr->sin_family != AF_INET &&
310 addr->sin_family != AF_IMPLINK)
311 return (EAFNOSUPPORT);
312 if (!in_nullhost(addr->sin_addr) &&
313 ifa_ifwithaddr(sintosa(addr)) == 0)
314 return (EADDRNOTAVAIL);
315 inp->inp_laddr = addr->sin_addr;
316 return (0);
317 }
318
319 int
320 rip_connect(inp, nam)
321 struct inpcb *inp;
322 struct mbuf *nam;
323 {
324 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
325
326 if (nam->m_len != sizeof(*addr))
327 return (EINVAL);
328 if (ifnet.tqh_first == 0)
329 return (EADDRNOTAVAIL);
330 if (addr->sin_family != AF_INET &&
331 addr->sin_family != AF_IMPLINK)
332 return (EAFNOSUPPORT);
333 inp->inp_faddr = addr->sin_addr;
334 return (0);
335 }
336
337 void
338 rip_disconnect(inp)
339 struct inpcb *inp;
340 {
341
342 inp->inp_faddr = zeroin_addr;
343 }
344
345 u_long rip_sendspace = RIPSNDQ;
346 u_long rip_recvspace = RIPRCVQ;
347
348 /*ARGSUSED*/
349 int
350 rip_usrreq(so, req, m, nam, control, p)
351 register struct socket *so;
352 int req;
353 struct mbuf *m, *nam, *control;
354 struct proc *p;
355 {
356 register struct inpcb *inp;
357 int s;
358 register int error = 0;
359 #ifdef MROUTING
360 extern struct socket *ip_mrouter;
361 #endif
362
363 if (req == PRU_CONTROL)
364 return (in_control(so, (long)m, (caddr_t)nam,
365 (struct ifnet *)control, p));
366
367 s = splsoftnet();
368 inp = sotoinpcb(so);
369 #ifdef DIAGNOSTIC
370 if (req != PRU_SEND && req != PRU_SENDOOB && control)
371 panic("rip_usrreq: unexpected control mbuf");
372 #endif
373 if (inp == 0 && req != PRU_ATTACH) {
374 error = EINVAL;
375 goto release;
376 }
377
378 switch (req) {
379
380 case PRU_ATTACH:
381 if (inp != 0) {
382 error = EISCONN;
383 break;
384 }
385 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
386 error = EACCES;
387 break;
388 }
389 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
390 error = soreserve(so, rip_sendspace, rip_recvspace);
391 if (error)
392 break;
393 }
394 error = in_pcballoc(so, &rawcbtable);
395 if (error)
396 break;
397 inp = sotoinpcb(so);
398 inp->inp_ip.ip_p = (long)nam;
399 break;
400
401 case PRU_DETACH:
402 #ifdef MROUTING
403 if (so == ip_mrouter)
404 ip_mrouter_done();
405 #endif
406 in_pcbdetach(inp);
407 break;
408
409 case PRU_BIND:
410 error = rip_bind(inp, nam);
411 break;
412
413 case PRU_LISTEN:
414 error = EOPNOTSUPP;
415 break;
416
417 case PRU_CONNECT:
418 error = rip_connect(inp, nam);
419 if (error)
420 break;
421 soisconnected(so);
422 break;
423
424 case PRU_CONNECT2:
425 error = EOPNOTSUPP;
426 break;
427
428 case PRU_DISCONNECT:
429 soisdisconnected(so);
430 rip_disconnect(inp);
431 break;
432
433 /*
434 * Mark the connection as being incapable of further input.
435 */
436 case PRU_SHUTDOWN:
437 socantsendmore(so);
438 break;
439
440 case PRU_RCVD:
441 error = EOPNOTSUPP;
442 break;
443
444 /*
445 * Ship a packet out. The appropriate raw output
446 * routine handles any massaging necessary.
447 */
448 case PRU_SEND:
449 if (control && control->m_len) {
450 m_freem(control);
451 m_freem(m);
452 error = EINVAL;
453 break;
454 }
455 {
456 if (nam) {
457 if ((so->so_state & SS_ISCONNECTED) != 0) {
458 error = EISCONN;
459 goto die;
460 }
461 error = rip_connect(inp, nam);
462 if (error) {
463 die:
464 m_freem(m);
465 break;
466 }
467 } else {
468 if ((so->so_state & SS_ISCONNECTED) == 0) {
469 error = ENOTCONN;
470 goto die;
471 }
472 }
473 error = rip_output(m, inp);
474 if (nam)
475 rip_disconnect(inp);
476 }
477 break;
478
479 case PRU_SENSE:
480 /*
481 * stat: don't bother with a blocksize.
482 */
483 splx(s);
484 return (0);
485
486 case PRU_RCVOOB:
487 error = EOPNOTSUPP;
488 break;
489
490 case PRU_SENDOOB:
491 m_freem(control);
492 m_freem(m);
493 error = EOPNOTSUPP;
494 break;
495
496 case PRU_SOCKADDR:
497 in_setsockaddr(inp, nam);
498 break;
499
500 case PRU_PEERADDR:
501 in_setpeeraddr(inp, nam);
502 break;
503
504 default:
505 panic("rip_usrreq");
506 }
507
508 release:
509 splx(s);
510 return (error);
511 }
512