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