xref: /freebsd/sys/netinet/raw_ip.c (revision 953a3198a35204535cc9d450f04da982a4fea59b)
1 /*
2  * Copyright (c) 1982, 1986, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)raw_ip.c	8.7 (Berkeley) 5/15/95
34  *	$Id: raw_ip.c,v 1.21 1995/07/24 16:33:51 wollman Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/malloc.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/protosw.h>
42 #include <sys/socketvar.h>
43 #include <sys/errno.h>
44 #include <sys/systm.h>
45 #include <sys/queue.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 
57 #include <netinet/ip_fw.h>
58 
59 struct inpcbhead ripcb;
60 struct inpcbinfo ripcbinfo;
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 	LIST_INIT(&ripcb);
79 	ripcbinfo.listhead = &ripcb;
80 	/*
81 	 * XXX We don't use the hash list for raw IP, but it's easier
82 	 * to allocate a one entry hash list than it is to check all
83 	 * over the place for hashbase == NULL.
84 	 */
85 	ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize);
86 }
87 
88 struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
89 /*
90  * Setup generic address and protocol structures
91  * for raw_input routine, then pass them along with
92  * mbuf chain.
93  */
94 void
95 rip_input(m)
96 	struct mbuf *m;
97 {
98 	register struct ip *ip = mtod(m, struct ip *);
99 	register struct inpcb *inp;
100 	struct socket *last = 0;
101 
102 	ripsrc.sin_addr = ip->ip_src;
103 	for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
104 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
105 			continue;
106 		if (inp->inp_laddr.s_addr &&
107                   inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
108 			continue;
109 		if (inp->inp_faddr.s_addr &&
110                   inp->inp_faddr.s_addr != ip->ip_src.s_addr)
111 			continue;
112 		if (last) {
113 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
114 			if (n) {
115 				if (sbappendaddr(&last->so_rcv,
116 				    (struct sockaddr *)&ripsrc, n,
117 				    (struct mbuf *)0) == 0)
118 					/* should notify about lost packet */
119 					m_freem(n);
120 				else
121 					sorwakeup(last);
122 			}
123 		}
124 		last = inp->inp_socket;
125 	}
126 	if (last) {
127 		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
128 		    m, (struct mbuf *)0) == 0)
129 			m_freem(m);
130 		else
131 			sorwakeup(last);
132 	} else {
133 		m_freem(m);
134               ipstat.ips_noproto++;
135               ipstat.ips_delivered--;
136       }
137 }
138 
139 /*
140  * Generate IP header and pass packet to ip_output.
141  * Tack on options user may have setup with control call.
142  */
143 int
144 rip_output(m, so, dst)
145 	register struct mbuf *m;
146 	struct socket *so;
147 	u_long dst;
148 {
149 	register struct ip *ip;
150 	register struct inpcb *inp = sotoinpcb(so);
151 	struct mbuf *opts;
152 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
153 
154 	/*
155 	 * If the user handed us a complete IP packet, use it.
156 	 * Otherwise, allocate an mbuf for a header and fill it in.
157 	 */
158 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
159 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
160 		ip = mtod(m, struct ip *);
161 		ip->ip_tos = 0;
162 		ip->ip_off = 0;
163 		ip->ip_p = inp->inp_ip.ip_p;
164 		ip->ip_len = m->m_pkthdr.len;
165 		ip->ip_src = inp->inp_laddr;
166 		ip->ip_dst.s_addr = dst;
167 		ip->ip_ttl = MAXTTL;
168 		opts = inp->inp_options;
169 	} else {
170 		ip = mtod(m, struct ip *);
171 		if (ip->ip_id == 0)
172 			ip->ip_id = htons(ip_id++);
173 		opts = NULL;
174 		/* XXX prevent ip_output from overwriting header fields */
175 		flags |= IP_RAWOUTPUT;
176 		ipstat.ips_rawout++;
177 	}
178 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
179 }
180 
181 /*
182  * Raw IP socket option processing.
183  */
184 int
185 rip_ctloutput(op, so, level, optname, m)
186 	int op;
187 	struct socket *so;
188 	int level, optname;
189 	struct mbuf **m;
190 {
191 	register struct inpcb *inp = sotoinpcb(so);
192 	register int error;
193 
194 	if (level != IPPROTO_IP) {
195 		if (op == PRCO_SETOPT && *m)
196 			(void)m_free(*m);
197 		return (EINVAL);
198 	}
199 
200 	switch (optname) {
201 
202 	case IP_HDRINCL:
203 		error = 0;
204 		if (op == PRCO_SETOPT) {
205 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
206 				error = EINVAL;
207 			else if (*mtod(*m, int *))
208 				inp->inp_flags |= INP_HDRINCL;
209 			else
210 				inp->inp_flags &= ~INP_HDRINCL;
211 			if (*m)
212 				(void)m_free(*m);
213 		} else {
214 			*m = m_get(M_WAIT, MT_SOOPTS);
215 			(*m)->m_len = sizeof (int);
216 			*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
217 		}
218 		return (error);
219 
220 	case IP_FW_ADD:
221 	case IP_FW_DEL:
222 	case IP_FW_FLUSH:
223 	case IP_FW_POLICY:
224 		if (ip_fw_ctl_ptr==NULL) {
225 			if (*m)
226 				(void)m_free(*m);
227 			return(EINVAL);
228 		}
229 
230 		if (op == PRCO_SETOPT) {
231 			error=(*ip_fw_ctl_ptr)(optname, *m);
232 			if (*m)
233 				(void)m_free(*m);
234 		}
235 		else
236 			error=EINVAL;
237 		return(error);
238 
239 	case IP_ACCT_DEL:
240 	case IP_ACCT_ADD:
241 	case IP_ACCT_CLR:
242 	case IP_ACCT_FLUSH:
243 	case IP_ACCT_ZERO:
244 		if (ip_acct_ctl_ptr==NULL) {
245 			if (*m)
246 				(void)m_free(*m);
247 			return(EINVAL);
248 		}
249 
250 		if (op == PRCO_SETOPT) {
251 			error=(*ip_acct_ctl_ptr)(optname, *m);
252 			if (*m)
253 				(void)m_free(*m);
254 		}
255 		else
256 			error=EINVAL;
257 		return(error);
258 
259 	case IP_RSVP_ON:
260 		return ip_rsvp_init(so);
261 		break;
262 
263 	case IP_RSVP_OFF:
264 		return ip_rsvp_done();
265 		break;
266 
267 	case IP_RSVP_VIF_ON:
268 		return ip_rsvp_vif_init(so, *m);
269 
270 	case IP_RSVP_VIF_OFF:
271 		return ip_rsvp_vif_done(so, *m);
272 
273 	case MRT_INIT:
274 	case MRT_DONE:
275 	case MRT_ADD_VIF:
276 	case MRT_DEL_VIF:
277 	case MRT_ADD_MFC:
278 	case MRT_DEL_MFC:
279 	case MRT_VERSION:
280 	case MRT_ASSERT:
281 		if (op == PRCO_SETOPT) {
282 			error = ip_mrouter_set(optname, so, *m);
283 			if (*m)
284 				(void)m_free(*m);
285 		} else if (op == PRCO_GETOPT) {
286 			error = ip_mrouter_get(optname, so, m);
287 		} else
288 			error = EINVAL;
289 		return (error);
290 	}
291 	return (ip_ctloutput(op, so, level, optname, m));
292 }
293 
294 u_long	rip_sendspace = RIPSNDQ;
295 u_long	rip_recvspace = RIPRCVQ;
296 
297 /*ARGSUSED*/
298 int
299 rip_usrreq(so, req, m, nam, control)
300 	register struct socket *so;
301 	int req;
302 	struct mbuf *m, *nam, *control;
303 {
304 	register int error = 0;
305 	register struct inpcb *inp = sotoinpcb(so);
306 	switch (req) {
307 
308 	case PRU_ATTACH:
309 		if (inp)
310 			panic("rip_attach");
311 		if ((so->so_state & SS_PRIV) == 0) {
312 			error = EACCES;
313 			break;
314 		}
315 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
316 		    (error = in_pcballoc(so, &ripcbinfo)))
317 			break;
318 		inp = (struct inpcb *)so->so_pcb;
319 		inp->inp_ip.ip_p = (int)nam;
320 		break;
321 
322 	case PRU_DISCONNECT:
323 		if ((so->so_state & SS_ISCONNECTED) == 0) {
324 			error = ENOTCONN;
325 			break;
326 		}
327 		/* FALLTHROUGH */
328 	case PRU_ABORT:
329 		soisdisconnected(so);
330 		/* FALLTHROUGH */
331 	case PRU_DETACH:
332 		if (inp == 0)
333 			panic("rip_detach");
334 		if (so == ip_mrouter)
335 			ip_mrouter_done();
336 		ip_rsvp_force_done(so);
337 		if (so == ip_rsvpd)
338 			ip_rsvp_done();
339 		in_pcbdetach(inp);
340 		break;
341 
342 	case PRU_BIND:
343 	    {
344 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
345 
346 		if (nam->m_len != sizeof(*addr)) {
347 			error = EINVAL;
348 			break;
349 		}
350 		if ((ifnet == 0) ||
351 		    ((addr->sin_family != AF_INET) &&
352 		     (addr->sin_family != AF_IMPLINK)) ||
353 		    (addr->sin_addr.s_addr &&
354 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
355 			error = EADDRNOTAVAIL;
356 			break;
357 		}
358 		inp->inp_laddr = addr->sin_addr;
359 		break;
360 	    }
361 	case PRU_CONNECT:
362 	    {
363 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
364 
365 		if (nam->m_len != sizeof(*addr)) {
366 			error = EINVAL;
367 			break;
368 		}
369 		if (ifnet == 0) {
370 			error = EADDRNOTAVAIL;
371 			break;
372 		}
373 		if ((addr->sin_family != AF_INET) &&
374 		     (addr->sin_family != AF_IMPLINK)) {
375 			error = EAFNOSUPPORT;
376 			break;
377 		}
378 		inp->inp_faddr = addr->sin_addr;
379 		soisconnected(so);
380 		break;
381 	    }
382 
383 	case PRU_CONNECT2:
384 		error = EOPNOTSUPP;
385 		break;
386 
387 	/*
388 	 * Mark the connection as being incapable of further input.
389 	 */
390 	case PRU_SHUTDOWN:
391 		socantsendmore(so);
392 		break;
393 
394 	/*
395 	 * Ship a packet out.  The appropriate raw output
396 	 * routine handles any massaging necessary.
397 	 */
398 	case PRU_SEND:
399 	    {
400 		register u_long dst;
401 
402 		if (so->so_state & SS_ISCONNECTED) {
403 			if (nam) {
404 				error = EISCONN;
405 				break;
406 			}
407 			dst = inp->inp_faddr.s_addr;
408 		} else {
409 			if (nam == NULL) {
410 				error = ENOTCONN;
411 				break;
412 			}
413 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
414 		}
415 		error = rip_output(m, so, dst);
416 		m = NULL;
417 		break;
418 	    }
419 
420 	case PRU_SENSE:
421 		/*
422 		 * stat: don't bother with a blocksize.
423 		 */
424 		return (0);
425 
426 	/*
427 	 * Not supported.
428 	 */
429 	case PRU_RCVOOB:
430 	case PRU_RCVD:
431 	case PRU_LISTEN:
432 	case PRU_ACCEPT:
433 	case PRU_SENDOOB:
434 		error = EOPNOTSUPP;
435 		break;
436 
437 	case PRU_SOCKADDR:
438 		in_setsockaddr(inp, nam);
439 		break;
440 
441 	case PRU_PEERADDR:
442 		in_setpeeraddr(inp, nam);
443 		break;
444 
445 	default:
446 		panic("rip_usrreq");
447 	}
448 	if (m != NULL)
449 		m_freem(m);
450 	return (error);
451 }
452