Deleted Added
full compact
raw_ip.c (67893) raw_ip.c (70254)
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
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 * $FreeBSD: head/sys/netinet/raw_ip.c 67893 2000-10-29 16:06:56Z phk $
34 * $FreeBSD: head/sys/netinet/raw_ip.c 70254 2000-12-21 21:44:31Z bmilekic $
35 */
36
37#include "opt_inet6.h"
38#include "opt_ipsec.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/mbuf.h>
45#include <sys/protosw.h>
46#include <sys/socket.h>
47#include <sys/socketvar.h>
48#include <sys/sysctl.h>
49
50#include <vm/vm_zone.h>
51
52#include <net/if.h>
53#include <net/route.h>
54
55#define _IP_VHL
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/ip.h>
59#include <netinet/in_pcb.h>
60#include <netinet/in_var.h>
61#include <netinet/ip_var.h>
62#include <netinet/ip_mroute.h>
63
64#include <netinet/ip_fw.h>
65
66#ifdef IPSEC
67#include <netinet6/ipsec.h>
68#endif /*IPSEC*/
69
70#include "opt_ipdn.h"
71#ifdef DUMMYNET
72#include <netinet/ip_dummynet.h>
73#endif
74
75struct inpcbhead ripcb;
76struct inpcbinfo ripcbinfo;
77
78/*
79 * Nominal space allocated to a raw ip socket.
80 */
81#define RIPSNDQ 8192
82#define RIPRCVQ 8192
83
84/*
85 * Raw interface to IP protocol.
86 */
87
88/*
89 * Initialize raw connection block q.
90 */
91void
92rip_init()
93{
94 LIST_INIT(&ripcb);
95 ripcbinfo.listhead = &ripcb;
96 /*
97 * XXX We don't use the hash list for raw IP, but it's easier
98 * to allocate a one entry hash list than it is to check all
99 * over the place for hashbase == NULL.
100 */
101 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
102 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
103 ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb),
104 maxsockets, ZONE_INTERRUPT, 0);
105}
106
107static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
108/*
109 * Setup generic address and protocol structures
110 * for raw_input routine, then pass them along with
111 * mbuf chain.
112 */
113void
114rip_input(m, off, proto)
115 struct mbuf *m;
116 int off, proto;
117{
118 register struct ip *ip = mtod(m, struct ip *);
119 register struct inpcb *inp;
120 struct inpcb *last = 0;
121 struct mbuf *opts = 0;
122
123 ripsrc.sin_addr = ip->ip_src;
124 LIST_FOREACH(inp, &ripcb, inp_list) {
125#ifdef INET6
126 if ((inp->inp_vflag & INP_IPV4) == 0)
127 continue;
128#endif
129 if (inp->inp_ip_p && inp->inp_ip_p != proto)
130 continue;
131 if (inp->inp_laddr.s_addr &&
132 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
133 continue;
134 if (inp->inp_faddr.s_addr &&
135 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
136 continue;
137 if (last) {
138 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
139 if (n) {
140 if (last->inp_flags & INP_CONTROLOPTS ||
141 last->inp_socket->so_options & SO_TIMESTAMP)
142 ip_savecontrol(last, &opts, ip, n);
143 if (sbappendaddr(&last->inp_socket->so_rcv,
144 (struct sockaddr *)&ripsrc, n,
145 opts) == 0) {
146 /* should notify about lost packet */
147 m_freem(n);
148 if (opts)
149 m_freem(opts);
150 } else
151 sorwakeup(last->inp_socket);
152 opts = 0;
153 }
154 }
155 last = inp;
156 }
157 if (last) {
158 if (last->inp_flags & INP_CONTROLOPTS ||
159 last->inp_socket->so_options & SO_TIMESTAMP)
160 ip_savecontrol(last, &opts, ip, m);
161 if (sbappendaddr(&last->inp_socket->so_rcv,
162 (struct sockaddr *)&ripsrc, m, opts) == 0) {
163 m_freem(m);
164 if (opts)
165 m_freem(opts);
166 } else
167 sorwakeup(last->inp_socket);
168 } else {
169 m_freem(m);
170 ipstat.ips_noproto++;
171 ipstat.ips_delivered--;
172 }
173}
174
175/*
176 * Generate IP header and pass packet to ip_output.
177 * Tack on options user may have setup with control call.
178 */
179int
180rip_output(m, so, dst)
181 struct mbuf *m;
182 struct socket *so;
183 u_long dst;
184{
185 register struct ip *ip;
186 register struct inpcb *inp = sotoinpcb(so);
187 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
188
189 /*
190 * If the user handed us a complete IP packet, use it.
191 * Otherwise, allocate an mbuf for a header and fill it in.
192 */
193 if ((inp->inp_flags & INP_HDRINCL) == 0) {
194 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
195 m_freem(m);
196 return(EMSGSIZE);
197 }
35 */
36
37#include "opt_inet6.h"
38#include "opt_ipsec.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/mbuf.h>
45#include <sys/protosw.h>
46#include <sys/socket.h>
47#include <sys/socketvar.h>
48#include <sys/sysctl.h>
49
50#include <vm/vm_zone.h>
51
52#include <net/if.h>
53#include <net/route.h>
54
55#define _IP_VHL
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/ip.h>
59#include <netinet/in_pcb.h>
60#include <netinet/in_var.h>
61#include <netinet/ip_var.h>
62#include <netinet/ip_mroute.h>
63
64#include <netinet/ip_fw.h>
65
66#ifdef IPSEC
67#include <netinet6/ipsec.h>
68#endif /*IPSEC*/
69
70#include "opt_ipdn.h"
71#ifdef DUMMYNET
72#include <netinet/ip_dummynet.h>
73#endif
74
75struct inpcbhead ripcb;
76struct inpcbinfo ripcbinfo;
77
78/*
79 * Nominal space allocated to a raw ip socket.
80 */
81#define RIPSNDQ 8192
82#define RIPRCVQ 8192
83
84/*
85 * Raw interface to IP protocol.
86 */
87
88/*
89 * Initialize raw connection block q.
90 */
91void
92rip_init()
93{
94 LIST_INIT(&ripcb);
95 ripcbinfo.listhead = &ripcb;
96 /*
97 * XXX We don't use the hash list for raw IP, but it's easier
98 * to allocate a one entry hash list than it is to check all
99 * over the place for hashbase == NULL.
100 */
101 ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
102 ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
103 ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb),
104 maxsockets, ZONE_INTERRUPT, 0);
105}
106
107static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
108/*
109 * Setup generic address and protocol structures
110 * for raw_input routine, then pass them along with
111 * mbuf chain.
112 */
113void
114rip_input(m, off, proto)
115 struct mbuf *m;
116 int off, proto;
117{
118 register struct ip *ip = mtod(m, struct ip *);
119 register struct inpcb *inp;
120 struct inpcb *last = 0;
121 struct mbuf *opts = 0;
122
123 ripsrc.sin_addr = ip->ip_src;
124 LIST_FOREACH(inp, &ripcb, inp_list) {
125#ifdef INET6
126 if ((inp->inp_vflag & INP_IPV4) == 0)
127 continue;
128#endif
129 if (inp->inp_ip_p && inp->inp_ip_p != proto)
130 continue;
131 if (inp->inp_laddr.s_addr &&
132 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
133 continue;
134 if (inp->inp_faddr.s_addr &&
135 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
136 continue;
137 if (last) {
138 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
139 if (n) {
140 if (last->inp_flags & INP_CONTROLOPTS ||
141 last->inp_socket->so_options & SO_TIMESTAMP)
142 ip_savecontrol(last, &opts, ip, n);
143 if (sbappendaddr(&last->inp_socket->so_rcv,
144 (struct sockaddr *)&ripsrc, n,
145 opts) == 0) {
146 /* should notify about lost packet */
147 m_freem(n);
148 if (opts)
149 m_freem(opts);
150 } else
151 sorwakeup(last->inp_socket);
152 opts = 0;
153 }
154 }
155 last = inp;
156 }
157 if (last) {
158 if (last->inp_flags & INP_CONTROLOPTS ||
159 last->inp_socket->so_options & SO_TIMESTAMP)
160 ip_savecontrol(last, &opts, ip, m);
161 if (sbappendaddr(&last->inp_socket->so_rcv,
162 (struct sockaddr *)&ripsrc, m, opts) == 0) {
163 m_freem(m);
164 if (opts)
165 m_freem(opts);
166 } else
167 sorwakeup(last->inp_socket);
168 } else {
169 m_freem(m);
170 ipstat.ips_noproto++;
171 ipstat.ips_delivered--;
172 }
173}
174
175/*
176 * Generate IP header and pass packet to ip_output.
177 * Tack on options user may have setup with control call.
178 */
179int
180rip_output(m, so, dst)
181 struct mbuf *m;
182 struct socket *so;
183 u_long dst;
184{
185 register struct ip *ip;
186 register struct inpcb *inp = sotoinpcb(so);
187 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
188
189 /*
190 * If the user handed us a complete IP packet, use it.
191 * Otherwise, allocate an mbuf for a header and fill it in.
192 */
193 if ((inp->inp_flags & INP_HDRINCL) == 0) {
194 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
195 m_freem(m);
196 return(EMSGSIZE);
197 }
198 M_PREPEND(m, sizeof(struct ip), M_WAIT);
198 M_PREPEND(m, sizeof(struct ip), M_TRYWAIT);
199 ip = mtod(m, struct ip *);
200 ip->ip_tos = 0;
201 ip->ip_off = 0;
202 ip->ip_p = inp->inp_ip_p;
203 ip->ip_len = m->m_pkthdr.len;
204 ip->ip_src = inp->inp_laddr;
205 ip->ip_dst.s_addr = dst;
206 ip->ip_ttl = MAXTTL;
207 } else {
208 if (m->m_pkthdr.len > IP_MAXPACKET) {
209 m_freem(m);
210 return(EMSGSIZE);
211 }
212 ip = mtod(m, struct ip *);
213 /* don't allow both user specified and setsockopt options,
214 and don't allow packet length sizes that will crash */
215 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
216 && inp->inp_options)
217 || (ip->ip_len > m->m_pkthdr.len)
218 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
219 m_freem(m);
220 return EINVAL;
221 }
222 if (ip->ip_id == 0)
223 ip->ip_id = htons(ip_id++);
224 /* XXX prevent ip_output from overwriting header fields */
225 flags |= IP_RAWOUTPUT;
226 ipstat.ips_rawout++;
227 }
228
229#ifdef IPSEC
230 ipsec_setsocket(m, so);
231#endif /*IPSEC*/
232
233 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
234 inp->inp_moptions));
235}
236
237/*
238 * Raw IP socket option processing.
239 */
240int
241rip_ctloutput(so, sopt)
242 struct socket *so;
243 struct sockopt *sopt;
244{
245 struct inpcb *inp = sotoinpcb(so);
246 int error, optval;
247
248 if (sopt->sopt_level != IPPROTO_IP)
249 return (EINVAL);
250
251 error = 0;
252
253 switch (sopt->sopt_dir) {
254 case SOPT_GET:
255 switch (sopt->sopt_name) {
256 case IP_HDRINCL:
257 optval = inp->inp_flags & INP_HDRINCL;
258 error = sooptcopyout(sopt, &optval, sizeof optval);
259 break;
260
261 case IP_FW_ADD:
262 case IP_FW_GET:
263 if (ip_fw_ctl_ptr == 0)
264 error = ENOPROTOOPT;
265 else
266 error = ip_fw_ctl_ptr(sopt);
267 break;
268
269#ifdef DUMMYNET
270 case IP_DUMMYNET_GET:
271 if (ip_dn_ctl_ptr == NULL)
272 error = ENOPROTOOPT ;
273 else
274 error = ip_dn_ctl_ptr(sopt);
275 break ;
276#endif /* DUMMYNET */
277
278 case MRT_INIT:
279 case MRT_DONE:
280 case MRT_ADD_VIF:
281 case MRT_DEL_VIF:
282 case MRT_ADD_MFC:
283 case MRT_DEL_MFC:
284 case MRT_VERSION:
285 case MRT_ASSERT:
286 error = ip_mrouter_get(so, sopt);
287 break;
288
289 default:
290 error = ip_ctloutput(so, sopt);
291 break;
292 }
293 break;
294
295 case SOPT_SET:
296 switch (sopt->sopt_name) {
297 case IP_HDRINCL:
298 error = sooptcopyin(sopt, &optval, sizeof optval,
299 sizeof optval);
300 if (error)
301 break;
302 if (optval)
303 inp->inp_flags |= INP_HDRINCL;
304 else
305 inp->inp_flags &= ~INP_HDRINCL;
306 break;
307
308 case IP_FW_ADD:
309 case IP_FW_DEL:
310 case IP_FW_FLUSH:
311 case IP_FW_ZERO:
312 case IP_FW_RESETLOG:
313 if (ip_fw_ctl_ptr == 0)
314 error = ENOPROTOOPT;
315 else
316 error = ip_fw_ctl_ptr(sopt);
317 break;
318
319#ifdef DUMMYNET
320 case IP_DUMMYNET_CONFIGURE:
321 case IP_DUMMYNET_DEL:
322 case IP_DUMMYNET_FLUSH:
323 if (ip_dn_ctl_ptr == NULL)
324 error = ENOPROTOOPT ;
325 else
326 error = ip_dn_ctl_ptr(sopt);
327 break ;
328#endif
329
330 case IP_RSVP_ON:
331 error = ip_rsvp_init(so);
332 break;
333
334 case IP_RSVP_OFF:
335 error = ip_rsvp_done();
336 break;
337
338 /* XXX - should be combined */
339 case IP_RSVP_VIF_ON:
340 error = ip_rsvp_vif_init(so, sopt);
341 break;
342
343 case IP_RSVP_VIF_OFF:
344 error = ip_rsvp_vif_done(so, sopt);
345 break;
346
347 case MRT_INIT:
348 case MRT_DONE:
349 case MRT_ADD_VIF:
350 case MRT_DEL_VIF:
351 case MRT_ADD_MFC:
352 case MRT_DEL_MFC:
353 case MRT_VERSION:
354 case MRT_ASSERT:
355 error = ip_mrouter_set(so, sopt);
356 break;
357
358 default:
359 error = ip_ctloutput(so, sopt);
360 break;
361 }
362 break;
363 }
364
365 return (error);
366}
367
368/*
369 * This function exists solely to receive the PRC_IFDOWN messages which
370 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
371 * and calls in_ifadown() to remove all routes corresponding to that address.
372 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
373 * interface routes.
374 */
375void
376rip_ctlinput(cmd, sa, vip)
377 int cmd;
378 struct sockaddr *sa;
379 void *vip;
380{
381 struct in_ifaddr *ia;
382 struct ifnet *ifp;
383 int err;
384 int flags;
385
386 switch (cmd) {
387 case PRC_IFDOWN:
388 for (ia = in_ifaddrhead.tqh_first; ia;
389 ia = ia->ia_link.tqe_next) {
390 if (ia->ia_ifa.ifa_addr == sa
391 && (ia->ia_flags & IFA_ROUTE)) {
392 /*
393 * in_ifscrub kills the interface route.
394 */
395 in_ifscrub(ia->ia_ifp, ia);
396 /*
397 * in_ifadown gets rid of all the rest of
398 * the routes. This is not quite the right
399 * thing to do, but at least if we are running
400 * a routing process they will come back.
401 */
402 in_ifadown(&ia->ia_ifa);
403 break;
404 }
405 }
406 break;
407
408 case PRC_IFUP:
409 for (ia = in_ifaddrhead.tqh_first; ia;
410 ia = ia->ia_link.tqe_next) {
411 if (ia->ia_ifa.ifa_addr == sa)
412 break;
413 }
414 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
415 return;
416 flags = RTF_UP;
417 ifp = ia->ia_ifa.ifa_ifp;
418
419 if ((ifp->if_flags & IFF_LOOPBACK)
420 || (ifp->if_flags & IFF_POINTOPOINT))
421 flags |= RTF_HOST;
422
423 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
424 if (err == 0)
425 ia->ia_flags |= IFA_ROUTE;
426 break;
427 }
428}
429
430u_long rip_sendspace = RIPSNDQ;
431u_long rip_recvspace = RIPRCVQ;
432
433SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
434 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
435SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
436 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
437
438static int
439rip_attach(struct socket *so, int proto, struct proc *p)
440{
441 struct inpcb *inp;
442 int error, s;
443
444 inp = sotoinpcb(so);
445 if (inp)
446 panic("rip_attach");
447 if (p && (error = suser(p)) != 0)
448 return error;
449
450 error = soreserve(so, rip_sendspace, rip_recvspace);
451 if (error)
452 return error;
453 s = splnet();
454 error = in_pcballoc(so, &ripcbinfo, p);
455 splx(s);
456 if (error)
457 return error;
458 inp = (struct inpcb *)so->so_pcb;
459 inp->inp_vflag |= INP_IPV4;
460 inp->inp_ip_p = proto;
461#ifdef IPSEC
462 error = ipsec_init_policy(so, &inp->inp_sp);
463 if (error != 0) {
464 in_pcbdetach(inp);
465 return error;
466 }
467#endif /*IPSEC*/
468 return 0;
469}
470
471static int
472rip_detach(struct socket *so)
473{
474 struct inpcb *inp;
475
476 inp = sotoinpcb(so);
477 if (inp == 0)
478 panic("rip_detach");
479 if (so == ip_mrouter)
480 ip_mrouter_done();
481 ip_rsvp_force_done(so);
482 if (so == ip_rsvpd)
483 ip_rsvp_done();
484 in_pcbdetach(inp);
485 return 0;
486}
487
488static int
489rip_abort(struct socket *so)
490{
491 soisdisconnected(so);
492 return rip_detach(so);
493}
494
495static int
496rip_disconnect(struct socket *so)
497{
498 if ((so->so_state & SS_ISCONNECTED) == 0)
499 return ENOTCONN;
500 return rip_abort(so);
501}
502
503static int
504rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
505{
506 struct inpcb *inp = sotoinpcb(so);
507 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
508
509 if (nam->sa_len != sizeof(*addr))
510 return EINVAL;
511
512 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
513 (addr->sin_family != AF_IMPLINK)) ||
514 (addr->sin_addr.s_addr &&
515 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
516 return EADDRNOTAVAIL;
517 inp->inp_laddr = addr->sin_addr;
518 return 0;
519}
520
521static int
522rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
523{
524 struct inpcb *inp = sotoinpcb(so);
525 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
526
527 if (nam->sa_len != sizeof(*addr))
528 return EINVAL;
529 if (TAILQ_EMPTY(&ifnet))
530 return EADDRNOTAVAIL;
531 if ((addr->sin_family != AF_INET) &&
532 (addr->sin_family != AF_IMPLINK))
533 return EAFNOSUPPORT;
534 inp->inp_faddr = addr->sin_addr;
535 soisconnected(so);
536 return 0;
537}
538
539static int
540rip_shutdown(struct socket *so)
541{
542 socantsendmore(so);
543 return 0;
544}
545
546static int
547rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
548 struct mbuf *control, struct proc *p)
549{
550 struct inpcb *inp = sotoinpcb(so);
551 register u_long dst;
552
553 if (so->so_state & SS_ISCONNECTED) {
554 if (nam) {
555 m_freem(m);
556 return EISCONN;
557 }
558 dst = inp->inp_faddr.s_addr;
559 } else {
560 if (nam == NULL) {
561 m_freem(m);
562 return ENOTCONN;
563 }
564 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
565 }
566 return rip_output(m, so, dst);
567}
568
569static int
570rip_pcblist(SYSCTL_HANDLER_ARGS)
571{
572 int error, i, n, s;
573 struct inpcb *inp, **inp_list;
574 inp_gen_t gencnt;
575 struct xinpgen xig;
576
577 /*
578 * The process of preparing the TCB list is too time-consuming and
579 * resource-intensive to repeat twice on every request.
580 */
581 if (req->oldptr == 0) {
582 n = ripcbinfo.ipi_count;
583 req->oldidx = 2 * (sizeof xig)
584 + (n + n/8) * sizeof(struct xinpcb);
585 return 0;
586 }
587
588 if (req->newptr != 0)
589 return EPERM;
590
591 /*
592 * OK, now we're committed to doing something.
593 */
594 s = splnet();
595 gencnt = ripcbinfo.ipi_gencnt;
596 n = ripcbinfo.ipi_count;
597 splx(s);
598
599 xig.xig_len = sizeof xig;
600 xig.xig_count = n;
601 xig.xig_gen = gencnt;
602 xig.xig_sogen = so_gencnt;
603 error = SYSCTL_OUT(req, &xig, sizeof xig);
604 if (error)
605 return error;
606
607 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
608 if (inp_list == 0)
609 return ENOMEM;
610
611 s = splnet();
612 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
613 inp = inp->inp_list.le_next) {
614 if (inp->inp_gencnt <= gencnt)
615 inp_list[i++] = inp;
616 }
617 splx(s);
618 n = i;
619
620 error = 0;
621 for (i = 0; i < n; i++) {
622 inp = inp_list[i];
623 if (inp->inp_gencnt <= gencnt) {
624 struct xinpcb xi;
625 xi.xi_len = sizeof xi;
626 /* XXX should avoid extra copy */
627 bcopy(inp, &xi.xi_inp, sizeof *inp);
628 if (inp->inp_socket)
629 sotoxsocket(inp->inp_socket, &xi.xi_socket);
630 error = SYSCTL_OUT(req, &xi, sizeof xi);
631 }
632 }
633 if (!error) {
634 /*
635 * Give the user an updated idea of our state.
636 * If the generation differs from what we told
637 * her before, she knows that something happened
638 * while we were processing this request, and it
639 * might be necessary to retry.
640 */
641 s = splnet();
642 xig.xig_gen = ripcbinfo.ipi_gencnt;
643 xig.xig_sogen = so_gencnt;
644 xig.xig_count = ripcbinfo.ipi_count;
645 splx(s);
646 error = SYSCTL_OUT(req, &xig, sizeof xig);
647 }
648 free(inp_list, M_TEMP);
649 return error;
650}
651
652SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
653 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
654
655struct pr_usrreqs rip_usrreqs = {
656 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
657 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
658 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
659 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
660 in_setsockaddr, sosend, soreceive, sopoll
661};
199 ip = mtod(m, struct ip *);
200 ip->ip_tos = 0;
201 ip->ip_off = 0;
202 ip->ip_p = inp->inp_ip_p;
203 ip->ip_len = m->m_pkthdr.len;
204 ip->ip_src = inp->inp_laddr;
205 ip->ip_dst.s_addr = dst;
206 ip->ip_ttl = MAXTTL;
207 } else {
208 if (m->m_pkthdr.len > IP_MAXPACKET) {
209 m_freem(m);
210 return(EMSGSIZE);
211 }
212 ip = mtod(m, struct ip *);
213 /* don't allow both user specified and setsockopt options,
214 and don't allow packet length sizes that will crash */
215 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
216 && inp->inp_options)
217 || (ip->ip_len > m->m_pkthdr.len)
218 || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
219 m_freem(m);
220 return EINVAL;
221 }
222 if (ip->ip_id == 0)
223 ip->ip_id = htons(ip_id++);
224 /* XXX prevent ip_output from overwriting header fields */
225 flags |= IP_RAWOUTPUT;
226 ipstat.ips_rawout++;
227 }
228
229#ifdef IPSEC
230 ipsec_setsocket(m, so);
231#endif /*IPSEC*/
232
233 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
234 inp->inp_moptions));
235}
236
237/*
238 * Raw IP socket option processing.
239 */
240int
241rip_ctloutput(so, sopt)
242 struct socket *so;
243 struct sockopt *sopt;
244{
245 struct inpcb *inp = sotoinpcb(so);
246 int error, optval;
247
248 if (sopt->sopt_level != IPPROTO_IP)
249 return (EINVAL);
250
251 error = 0;
252
253 switch (sopt->sopt_dir) {
254 case SOPT_GET:
255 switch (sopt->sopt_name) {
256 case IP_HDRINCL:
257 optval = inp->inp_flags & INP_HDRINCL;
258 error = sooptcopyout(sopt, &optval, sizeof optval);
259 break;
260
261 case IP_FW_ADD:
262 case IP_FW_GET:
263 if (ip_fw_ctl_ptr == 0)
264 error = ENOPROTOOPT;
265 else
266 error = ip_fw_ctl_ptr(sopt);
267 break;
268
269#ifdef DUMMYNET
270 case IP_DUMMYNET_GET:
271 if (ip_dn_ctl_ptr == NULL)
272 error = ENOPROTOOPT ;
273 else
274 error = ip_dn_ctl_ptr(sopt);
275 break ;
276#endif /* DUMMYNET */
277
278 case MRT_INIT:
279 case MRT_DONE:
280 case MRT_ADD_VIF:
281 case MRT_DEL_VIF:
282 case MRT_ADD_MFC:
283 case MRT_DEL_MFC:
284 case MRT_VERSION:
285 case MRT_ASSERT:
286 error = ip_mrouter_get(so, sopt);
287 break;
288
289 default:
290 error = ip_ctloutput(so, sopt);
291 break;
292 }
293 break;
294
295 case SOPT_SET:
296 switch (sopt->sopt_name) {
297 case IP_HDRINCL:
298 error = sooptcopyin(sopt, &optval, sizeof optval,
299 sizeof optval);
300 if (error)
301 break;
302 if (optval)
303 inp->inp_flags |= INP_HDRINCL;
304 else
305 inp->inp_flags &= ~INP_HDRINCL;
306 break;
307
308 case IP_FW_ADD:
309 case IP_FW_DEL:
310 case IP_FW_FLUSH:
311 case IP_FW_ZERO:
312 case IP_FW_RESETLOG:
313 if (ip_fw_ctl_ptr == 0)
314 error = ENOPROTOOPT;
315 else
316 error = ip_fw_ctl_ptr(sopt);
317 break;
318
319#ifdef DUMMYNET
320 case IP_DUMMYNET_CONFIGURE:
321 case IP_DUMMYNET_DEL:
322 case IP_DUMMYNET_FLUSH:
323 if (ip_dn_ctl_ptr == NULL)
324 error = ENOPROTOOPT ;
325 else
326 error = ip_dn_ctl_ptr(sopt);
327 break ;
328#endif
329
330 case IP_RSVP_ON:
331 error = ip_rsvp_init(so);
332 break;
333
334 case IP_RSVP_OFF:
335 error = ip_rsvp_done();
336 break;
337
338 /* XXX - should be combined */
339 case IP_RSVP_VIF_ON:
340 error = ip_rsvp_vif_init(so, sopt);
341 break;
342
343 case IP_RSVP_VIF_OFF:
344 error = ip_rsvp_vif_done(so, sopt);
345 break;
346
347 case MRT_INIT:
348 case MRT_DONE:
349 case MRT_ADD_VIF:
350 case MRT_DEL_VIF:
351 case MRT_ADD_MFC:
352 case MRT_DEL_MFC:
353 case MRT_VERSION:
354 case MRT_ASSERT:
355 error = ip_mrouter_set(so, sopt);
356 break;
357
358 default:
359 error = ip_ctloutput(so, sopt);
360 break;
361 }
362 break;
363 }
364
365 return (error);
366}
367
368/*
369 * This function exists solely to receive the PRC_IFDOWN messages which
370 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
371 * and calls in_ifadown() to remove all routes corresponding to that address.
372 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
373 * interface routes.
374 */
375void
376rip_ctlinput(cmd, sa, vip)
377 int cmd;
378 struct sockaddr *sa;
379 void *vip;
380{
381 struct in_ifaddr *ia;
382 struct ifnet *ifp;
383 int err;
384 int flags;
385
386 switch (cmd) {
387 case PRC_IFDOWN:
388 for (ia = in_ifaddrhead.tqh_first; ia;
389 ia = ia->ia_link.tqe_next) {
390 if (ia->ia_ifa.ifa_addr == sa
391 && (ia->ia_flags & IFA_ROUTE)) {
392 /*
393 * in_ifscrub kills the interface route.
394 */
395 in_ifscrub(ia->ia_ifp, ia);
396 /*
397 * in_ifadown gets rid of all the rest of
398 * the routes. This is not quite the right
399 * thing to do, but at least if we are running
400 * a routing process they will come back.
401 */
402 in_ifadown(&ia->ia_ifa);
403 break;
404 }
405 }
406 break;
407
408 case PRC_IFUP:
409 for (ia = in_ifaddrhead.tqh_first; ia;
410 ia = ia->ia_link.tqe_next) {
411 if (ia->ia_ifa.ifa_addr == sa)
412 break;
413 }
414 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
415 return;
416 flags = RTF_UP;
417 ifp = ia->ia_ifa.ifa_ifp;
418
419 if ((ifp->if_flags & IFF_LOOPBACK)
420 || (ifp->if_flags & IFF_POINTOPOINT))
421 flags |= RTF_HOST;
422
423 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
424 if (err == 0)
425 ia->ia_flags |= IFA_ROUTE;
426 break;
427 }
428}
429
430u_long rip_sendspace = RIPSNDQ;
431u_long rip_recvspace = RIPRCVQ;
432
433SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
434 &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
435SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
436 &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
437
438static int
439rip_attach(struct socket *so, int proto, struct proc *p)
440{
441 struct inpcb *inp;
442 int error, s;
443
444 inp = sotoinpcb(so);
445 if (inp)
446 panic("rip_attach");
447 if (p && (error = suser(p)) != 0)
448 return error;
449
450 error = soreserve(so, rip_sendspace, rip_recvspace);
451 if (error)
452 return error;
453 s = splnet();
454 error = in_pcballoc(so, &ripcbinfo, p);
455 splx(s);
456 if (error)
457 return error;
458 inp = (struct inpcb *)so->so_pcb;
459 inp->inp_vflag |= INP_IPV4;
460 inp->inp_ip_p = proto;
461#ifdef IPSEC
462 error = ipsec_init_policy(so, &inp->inp_sp);
463 if (error != 0) {
464 in_pcbdetach(inp);
465 return error;
466 }
467#endif /*IPSEC*/
468 return 0;
469}
470
471static int
472rip_detach(struct socket *so)
473{
474 struct inpcb *inp;
475
476 inp = sotoinpcb(so);
477 if (inp == 0)
478 panic("rip_detach");
479 if (so == ip_mrouter)
480 ip_mrouter_done();
481 ip_rsvp_force_done(so);
482 if (so == ip_rsvpd)
483 ip_rsvp_done();
484 in_pcbdetach(inp);
485 return 0;
486}
487
488static int
489rip_abort(struct socket *so)
490{
491 soisdisconnected(so);
492 return rip_detach(so);
493}
494
495static int
496rip_disconnect(struct socket *so)
497{
498 if ((so->so_state & SS_ISCONNECTED) == 0)
499 return ENOTCONN;
500 return rip_abort(so);
501}
502
503static int
504rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
505{
506 struct inpcb *inp = sotoinpcb(so);
507 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
508
509 if (nam->sa_len != sizeof(*addr))
510 return EINVAL;
511
512 if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
513 (addr->sin_family != AF_IMPLINK)) ||
514 (addr->sin_addr.s_addr &&
515 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
516 return EADDRNOTAVAIL;
517 inp->inp_laddr = addr->sin_addr;
518 return 0;
519}
520
521static int
522rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
523{
524 struct inpcb *inp = sotoinpcb(so);
525 struct sockaddr_in *addr = (struct sockaddr_in *)nam;
526
527 if (nam->sa_len != sizeof(*addr))
528 return EINVAL;
529 if (TAILQ_EMPTY(&ifnet))
530 return EADDRNOTAVAIL;
531 if ((addr->sin_family != AF_INET) &&
532 (addr->sin_family != AF_IMPLINK))
533 return EAFNOSUPPORT;
534 inp->inp_faddr = addr->sin_addr;
535 soisconnected(so);
536 return 0;
537}
538
539static int
540rip_shutdown(struct socket *so)
541{
542 socantsendmore(so);
543 return 0;
544}
545
546static int
547rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
548 struct mbuf *control, struct proc *p)
549{
550 struct inpcb *inp = sotoinpcb(so);
551 register u_long dst;
552
553 if (so->so_state & SS_ISCONNECTED) {
554 if (nam) {
555 m_freem(m);
556 return EISCONN;
557 }
558 dst = inp->inp_faddr.s_addr;
559 } else {
560 if (nam == NULL) {
561 m_freem(m);
562 return ENOTCONN;
563 }
564 dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
565 }
566 return rip_output(m, so, dst);
567}
568
569static int
570rip_pcblist(SYSCTL_HANDLER_ARGS)
571{
572 int error, i, n, s;
573 struct inpcb *inp, **inp_list;
574 inp_gen_t gencnt;
575 struct xinpgen xig;
576
577 /*
578 * The process of preparing the TCB list is too time-consuming and
579 * resource-intensive to repeat twice on every request.
580 */
581 if (req->oldptr == 0) {
582 n = ripcbinfo.ipi_count;
583 req->oldidx = 2 * (sizeof xig)
584 + (n + n/8) * sizeof(struct xinpcb);
585 return 0;
586 }
587
588 if (req->newptr != 0)
589 return EPERM;
590
591 /*
592 * OK, now we're committed to doing something.
593 */
594 s = splnet();
595 gencnt = ripcbinfo.ipi_gencnt;
596 n = ripcbinfo.ipi_count;
597 splx(s);
598
599 xig.xig_len = sizeof xig;
600 xig.xig_count = n;
601 xig.xig_gen = gencnt;
602 xig.xig_sogen = so_gencnt;
603 error = SYSCTL_OUT(req, &xig, sizeof xig);
604 if (error)
605 return error;
606
607 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
608 if (inp_list == 0)
609 return ENOMEM;
610
611 s = splnet();
612 for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
613 inp = inp->inp_list.le_next) {
614 if (inp->inp_gencnt <= gencnt)
615 inp_list[i++] = inp;
616 }
617 splx(s);
618 n = i;
619
620 error = 0;
621 for (i = 0; i < n; i++) {
622 inp = inp_list[i];
623 if (inp->inp_gencnt <= gencnt) {
624 struct xinpcb xi;
625 xi.xi_len = sizeof xi;
626 /* XXX should avoid extra copy */
627 bcopy(inp, &xi.xi_inp, sizeof *inp);
628 if (inp->inp_socket)
629 sotoxsocket(inp->inp_socket, &xi.xi_socket);
630 error = SYSCTL_OUT(req, &xi, sizeof xi);
631 }
632 }
633 if (!error) {
634 /*
635 * Give the user an updated idea of our state.
636 * If the generation differs from what we told
637 * her before, she knows that something happened
638 * while we were processing this request, and it
639 * might be necessary to retry.
640 */
641 s = splnet();
642 xig.xig_gen = ripcbinfo.ipi_gencnt;
643 xig.xig_sogen = so_gencnt;
644 xig.xig_count = ripcbinfo.ipi_count;
645 splx(s);
646 error = SYSCTL_OUT(req, &xig, sizeof xig);
647 }
648 free(inp_list, M_TEMP);
649 return error;
650}
651
652SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
653 rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
654
655struct pr_usrreqs rip_usrreqs = {
656 rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
657 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
658 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
659 pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
660 in_setsockaddr, sosend, soreceive, sopoll
661};