xref: /original-bsd/sys/netinet/raw_ip.c (revision 333da485)
1 /*
2  * Copyright (c) 1982, 1986, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)raw_ip.c	8.2 (Berkeley) 01/04/94
8  */
9 
10 #include <sys/param.h>
11 #include <sys/malloc.h>
12 #include <sys/mbuf.h>
13 #include <sys/socket.h>
14 #include <sys/protosw.h>
15 #include <sys/socketvar.h>
16 #include <sys/errno.h>
17 #include <sys/systm.h>
18 
19 #include <net/if.h>
20 #include <net/route.h>
21 
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <netinet/ip_var.h>
26 #include <netinet/ip_mroute.h>
27 #include <netinet/in_pcb.h>
28 
29 struct inpcb rawinpcb;
30 
31 /*
32  * Nominal space allocated to a raw ip socket.
33  */
34 #define	RIPSNDQ		8192
35 #define	RIPRCVQ		8192
36 
37 /*
38  * Raw interface to IP protocol.
39  */
40 
41 /*
42  * Initialize raw connection block q.
43  */
44 void
45 rip_init()
46 {
47 
48 	rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb;
49 }
50 
51 struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
52 /*
53  * Setup generic address and protocol structures
54  * for raw_input routine, then pass them along with
55  * mbuf chain.
56  */
57 void
58 rip_input(m)
59 	struct mbuf *m;
60 {
61 	register struct ip *ip = mtod(m, struct ip *);
62 	register struct inpcb *inp;
63 	struct socket *last = 0;
64 
65 	ripsrc.sin_addr = ip->ip_src;
66 	for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) {
67 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
68 			continue;
69 		if (inp->inp_laddr.s_addr &&
70 		    inp->inp_laddr.s_addr == ip->ip_dst.s_addr)
71 			continue;
72 		if (inp->inp_faddr.s_addr &&
73 		    inp->inp_faddr.s_addr == ip->ip_src.s_addr)
74 			continue;
75 		if (last) {
76 			struct mbuf *n;
77 			if (n = m_copy(m, 0, (int)M_COPYALL)) {
78 				if (sbappendaddr(&last->so_rcv, &ripsrc,
79 				    n, (struct mbuf *)0) == 0)
80 					/* should notify about lost packet */
81 					m_freem(n);
82 				else
83 					sorwakeup(last);
84 			}
85 		}
86 		last = inp->inp_socket;
87 	}
88 	if (last) {
89 		if (sbappendaddr(&last->so_rcv, &ripsrc,
90 		    m, (struct mbuf *)0) == 0)
91 			m_freem(m);
92 		else
93 			sorwakeup(last);
94 	} else {
95 		m_freem(m);
96 		ipstat.ips_noproto++;
97 		ipstat.ips_delivered--;
98 	}
99 }
100 
101 /*
102  * Generate IP header and pass packet to ip_output.
103  * Tack on options user may have setup with control call.
104  */
105 int
106 rip_output(m, so, dst)
107 	register struct mbuf *m;
108 	struct socket *so;
109 	u_long dst;
110 {
111 	register struct ip *ip;
112 	register struct inpcb *inp = sotoinpcb(so);
113 	struct mbuf *opts;
114 	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
115 
116 	/*
117 	 * If the user handed us a complete IP packet, use it.
118 	 * Otherwise, allocate an mbuf for a header and fill it in.
119 	 */
120 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
121 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
122 		ip = mtod(m, struct ip *);
123 		ip->ip_tos = 0;
124 		ip->ip_off = 0;
125 		ip->ip_p = inp->inp_ip.ip_p;
126 		ip->ip_len = m->m_pkthdr.len;
127 		ip->ip_src = inp->inp_laddr;
128 		ip->ip_dst.s_addr = dst;
129 		ip->ip_ttl = MAXTTL;
130 		opts = inp->inp_options;
131 	} else {
132 		ip = mtod(m, struct ip *);
133 		if (ip->ip_id == 0)
134 			ip->ip_id = htons(ip_id++);
135 		opts = NULL;
136 		/* XXX prevent ip_output from overwriting header fields */
137 		flags |= IP_RAWOUTPUT;
138 		ipstat.ips_rawout++;
139 	}
140 	return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
141 }
142 
143 /*
144  * Raw IP socket option processing.
145  */
146 int
147 rip_ctloutput(op, so, level, optname, m)
148 	int op;
149 	struct socket *so;
150 	int level, optname;
151 	struct mbuf **m;
152 {
153 	register struct inpcb *inp = sotoinpcb(so);
154 	register int error;
155 
156 	if (level != IPPROTO_IP)
157 		return (EINVAL);
158 
159 	switch (optname) {
160 
161 	case IP_HDRINCL:
162 		if (op == PRCO_SETOPT || op == PRCO_GETOPT) {
163 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
164 				return (EINVAL);
165 			if (op == PRCO_SETOPT) {
166 				if (*mtod(*m, int *))
167 					inp->inp_flags |= INP_HDRINCL;
168 				else
169 					inp->inp_flags &= ~INP_HDRINCL;
170 				(void)m_free(*m);
171 			} else {
172 				(*m)->m_len = sizeof (int);
173 				*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
174 			}
175 			return (0);
176 		}
177 		break;
178 
179 	case DVMRP_INIT:
180 	case DVMRP_DONE:
181 	case DVMRP_ADD_VIF:
182 	case DVMRP_DEL_VIF:
183 	case DVMRP_ADD_LGRP:
184 	case DVMRP_DEL_LGRP:
185 	case DVMRP_ADD_MRT:
186 	case DVMRP_DEL_MRT:
187 #ifdef MROUTING
188 		if (op == PRCO_SETOPT) {
189 			error = ip_mrouter_cmd(optname, so, *m);
190 			if (*m)
191 				(void)m_free(*m);
192 		} else
193 			error = EINVAL;
194 		return (error);
195 #else
196 		if (op == PRCO_SETOPT && *m)
197 			(void)m_free(*m);
198 		return (EOPNOTSUPP);
199 #endif
200 	}
201 	return (ip_ctloutput(op, so, level, optname, m));
202 }
203 
204 u_long	rip_sendspace = RIPSNDQ;
205 u_long	rip_recvspace = RIPRCVQ;
206 
207 /*ARGSUSED*/
208 int
209 rip_usrreq(so, req, m, nam, control)
210 	register struct socket *so;
211 	int req;
212 	struct mbuf *m, *nam, *control;
213 {
214 	register int error = 0;
215 	register struct inpcb *inp = sotoinpcb(so);
216 #ifdef MROUTING
217 	extern struct socket *ip_mrouter;
218 #endif
219 	switch (req) {
220 
221 	case PRU_ATTACH:
222 		if (inp)
223 			panic("rip_attach");
224 		if ((so->so_state & SS_PRIV) == 0) {
225 			error = EACCES;
226 			break;
227 		}
228 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
229 		    (error = in_pcballoc(so, &rawinpcb)))
230 			break;
231 		inp = (struct inpcb *)so->so_pcb;
232 		inp->inp_ip.ip_p = (int)nam;
233 		break;
234 
235 	case PRU_DISCONNECT:
236 		if ((so->so_state & SS_ISCONNECTED) == 0) {
237 			error = ENOTCONN;
238 			break;
239 		}
240 		/* FALLTHROUGH */
241 	case PRU_ABORT:
242 		soisdisconnected(so);
243 		/* FALLTHROUGH */
244 	case PRU_DETACH:
245 		if (inp == 0)
246 			panic("rip_detach");
247 #ifdef MROUTING
248 		if (so == ip_mrouter)
249 			ip_mrouter_done();
250 #endif
251 		in_pcbdetach(inp);
252 		break;
253 
254 	case PRU_BIND:
255 	    {
256 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
257 
258 		if (nam->m_len != sizeof(*addr)) {
259 			error = EINVAL;
260 			break;
261 		}
262 		if ((ifnet == 0) ||
263 		    ((addr->sin_family != AF_INET) &&
264 		     (addr->sin_family != AF_IMPLINK)) ||
265 		    (addr->sin_addr.s_addr &&
266 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
267 			error = EADDRNOTAVAIL;
268 			break;
269 		}
270 		inp->inp_laddr = addr->sin_addr;
271 		break;
272 	    }
273 	case PRU_CONNECT:
274 	    {
275 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
276 
277 		if (nam->m_len != sizeof(*addr)) {
278 			error = EINVAL;
279 			break;
280 		}
281 		if (ifnet == 0) {
282 			error = EADDRNOTAVAIL;
283 			break;
284 		}
285 		if ((addr->sin_family != AF_INET) &&
286 		     (addr->sin_family != AF_IMPLINK)) {
287 			error = EAFNOSUPPORT;
288 			break;
289 		}
290 		inp->inp_faddr = addr->sin_addr;
291 		soisconnected(so);
292 		break;
293 	    }
294 
295 	case PRU_CONNECT2:
296 		error = EOPNOTSUPP;
297 		break;
298 
299 	/*
300 	 * Mark the connection as being incapable of further input.
301 	 */
302 	case PRU_SHUTDOWN:
303 		socantsendmore(so);
304 		break;
305 
306 	/*
307 	 * Ship a packet out.  The appropriate raw output
308 	 * routine handles any massaging necessary.
309 	 */
310 	case PRU_SEND:
311 	    {
312 		register u_long dst;
313 
314 		if (so->so_state & SS_ISCONNECTED) {
315 			if (nam) {
316 				error = EISCONN;
317 				break;
318 			}
319 			dst = inp->inp_faddr.s_addr;
320 		} else {
321 			if (nam == NULL) {
322 				error = ENOTCONN;
323 				break;
324 			}
325 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
326 		}
327 		error = rip_output(m, so, dst);
328 		m = NULL;
329 		break;
330 	    }
331 
332 	case PRU_SENSE:
333 		/*
334 		 * stat: don't bother with a blocksize.
335 		 */
336 		return (0);
337 
338 	/*
339 	 * Not supported.
340 	 */
341 	case PRU_RCVOOB:
342 	case PRU_RCVD:
343 	case PRU_LISTEN:
344 	case PRU_ACCEPT:
345 	case PRU_SENDOOB:
346 		error = EOPNOTSUPP;
347 		break;
348 
349 	case PRU_SOCKADDR:
350 		in_setsockaddr(inp, nam);
351 		break;
352 
353 	case PRU_PEERADDR:
354 		in_setpeeraddr(inp, nam);
355 		break;
356 
357 	default:
358 		panic("rip_usrreq");
359 	}
360 	if (m != NULL)
361 		m_freem(m);
362 	return (error);
363 }
364