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