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