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