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