/[base]/head/sys/netinet/raw_ip.c
ViewVC logotype

Contents of /head/sys/netinet/raw_ip.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22672 - (show annotations) (download)
Thu Feb 13 19:46:45 1997 UTC (24 years, 1 month ago) by wollman
File MIME type: text/plain
File size: 12836 byte(s)
Provide PRC_IFDOWN and PRC_IFUP support for IP.  Now, when an interface
is administratively downed, all routes to that interface (including the
interface route itself) which are not static will be deleted.  When
it comes back up, and addresses remaining will have their interface routes
re-added.  This solves the problem where, for example, an Ethernet interface
is downed by traffic continues to flow by way of ARP entries.

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$
35 */
36
37 #include <sys/param.h>
38 #include <sys/queue.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 #define _IP_VHL
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_var.h>
56 #include <netinet/ip_var.h>
57 #include <netinet/ip_mroute.h>
58
59 #include <netinet/ip_fw.h>
60
61 #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
62 #undef COMPAT_IPFW
63 #define COMPAT_IPFW 1
64 #else
65 #undef COMPAT_IPFW
66 #endif
67
68 static struct inpcbhead ripcb;
69 static struct inpcbinfo ripcbinfo;
70
71 /*
72 * Nominal space allocated to a raw ip socket.
73 */
74 #define RIPSNDQ 8192
75 #define RIPRCVQ 8192
76
77 /*
78 * Raw interface to IP protocol.
79 */
80
81 /*
82 * Initialize raw connection block q.
83 */
84 void
85 rip_init()
86 {
87 LIST_INIT(&ripcb);
88 ripcbinfo.listhead = &ripcb;
89 /*
90 * XXX We don't use the hash list for raw IP, but it's easier
91 * to allocate a one entry hash list than it is to check all
92 * over the place for hashbase == NULL.
93 */
94 ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize);
95 }
96
97 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
98 /*
99 * Setup generic address and protocol structures
100 * for raw_input routine, then pass them along with
101 * mbuf chain.
102 */
103 void
104 rip_input(m, iphlen)
105 struct mbuf *m;
106 int iphlen;
107 {
108 register struct ip *ip = mtod(m, struct ip *);
109 register struct inpcb *inp;
110 struct inpcb *last = 0;
111 struct mbuf *opts = 0;
112
113 ripsrc.sin_addr = ip->ip_src;
114 for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
115 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
116 continue;
117 if (inp->inp_laddr.s_addr &&
118 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
119 continue;
120 if (inp->inp_faddr.s_addr &&
121 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
122 continue;
123 if (last) {
124 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
125 if (n) {
126 if (last->inp_flags & INP_CONTROLOPTS ||
127 last->inp_socket->so_options & SO_TIMESTAMP)
128 ip_savecontrol(last, &opts, ip, n);
129 if (sbappendaddr(&last->inp_socket->so_rcv,
130 (struct sockaddr *)&ripsrc, n,
131 opts) == 0) {
132 /* should notify about lost packet */
133 m_freem(n);
134 if (opts)
135 m_freem(opts);
136 } else
137 sorwakeup(last->inp_socket);
138 opts = 0;
139 }
140 }
141 last = inp;
142 }
143 if (last) {
144 if (last->inp_flags & INP_CONTROLOPTS ||
145 last->inp_socket->so_options & SO_TIMESTAMP)
146 ip_savecontrol(last, &opts, ip, m);
147 if (sbappendaddr(&last->inp_socket->so_rcv,
148 (struct sockaddr *)&ripsrc, m, opts) == 0) {
149 m_freem(m);
150 if (opts)
151 m_freem(opts);
152 } else
153 sorwakeup(last->inp_socket);
154 } else {
155 m_freem(m);
156 ipstat.ips_noproto++;
157 ipstat.ips_delivered--;
158 }
159 }
160
161 /*
162 * Generate IP header and pass packet to ip_output.
163 * Tack on options user may have setup with control call.
164 */
165 int
166 rip_output(m, so, dst)
167 register struct mbuf *m;
168 struct socket *so;
169 u_long dst;
170 {
171 register struct ip *ip;
172 register struct inpcb *inp = sotoinpcb(so);
173 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
174
175 /*
176 * If the user handed us a complete IP packet, use it.
177 * Otherwise, allocate an mbuf for a header and fill it in.
178 */
179 if ((inp->inp_flags & INP_HDRINCL) == 0) {
180 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
181 m_freem(m);
182 return(EMSGSIZE);
183 }
184 M_PREPEND(m, sizeof(struct ip), M_WAIT);
185 ip = mtod(m, struct ip *);
186 ip->ip_tos = 0;
187 ip->ip_off = 0;
188 ip->ip_p = inp->inp_ip.ip_p;
189 ip->ip_len = m->m_pkthdr.len;
190 ip->ip_src = inp->inp_laddr;
191 ip->ip_dst.s_addr = dst;
192 ip->ip_ttl = MAXTTL;
193 } else {
194 if (m->m_pkthdr.len > IP_MAXPACKET) {
195 m_freem(m);
196 return(EMSGSIZE);
197 }
198 ip = mtod(m, struct ip *);
199 /* don't allow both user specified and setsockopt options,
200 and don't allow packet length sizes that will crash */
201 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
202 && inp->inp_options)
203 || (ip->ip_len > m->m_pkthdr.len)) {
204 m_freem(m);
205 return EINVAL;
206 }
207 if (ip->ip_id == 0)
208 ip->ip_id = htons(ip_id++);
209 /* XXX prevent ip_output from overwriting header fields */
210 flags |= IP_RAWOUTPUT;
211 ipstat.ips_rawout++;
212 }
213 return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
214 inp->inp_moptions));
215 }
216
217 /*
218 * Raw IP socket option processing.
219 */
220 int
221 rip_ctloutput(op, so, level, optname, m)
222 int op;
223 struct socket *so;
224 int level, optname;
225 struct mbuf **m;
226 {
227 register struct inpcb *inp = sotoinpcb(so);
228 register int error;
229
230 if (level != IPPROTO_IP) {
231 if (op == PRCO_SETOPT && *m)
232 (void)m_free(*m);
233 return (EINVAL);
234 }
235
236 switch (optname) {
237
238 case IP_HDRINCL:
239 error = 0;
240 if (op == PRCO_SETOPT) {
241 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
242 error = EINVAL;
243 else if (*mtod(*m, int *))
244 inp->inp_flags |= INP_HDRINCL;
245 else
246 inp->inp_flags &= ~INP_HDRINCL;
247 if (*m)
248 (void)m_free(*m);
249 } else {
250 *m = m_get(M_WAIT, MT_SOOPTS);
251 (*m)->m_len = sizeof (int);
252 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
253 }
254 return (error);
255
256 #ifdef COMPAT_IPFW
257 case IP_FW_GET:
258 if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) {
259 if (*m) (void)m_free(*m);
260 return(EINVAL);
261 }
262 return (*ip_fw_ctl_ptr)(optname, m);
263
264 case IP_FW_ADD:
265 case IP_FW_DEL:
266 case IP_FW_FLUSH:
267 case IP_FW_ZERO:
268 if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) {
269 if (*m) (void)m_free(*m);
270 return(EINVAL);
271 }
272 return (*ip_fw_ctl_ptr)(optname, m);
273
274 case IP_NAT:
275 if (ip_nat_ctl_ptr == NULL) {
276 if (*m) (void)m_free(*m);
277 return(EINVAL);
278 }
279 return (*ip_nat_ctl_ptr)(op, m);
280
281 #endif
282 case IP_RSVP_ON:
283 return ip_rsvp_init(so);
284 break;
285
286 case IP_RSVP_OFF:
287 return ip_rsvp_done();
288 break;
289
290 case IP_RSVP_VIF_ON:
291 return ip_rsvp_vif_init(so, *m);
292
293 case IP_RSVP_VIF_OFF:
294 return ip_rsvp_vif_done(so, *m);
295
296 case MRT_INIT:
297 case MRT_DONE:
298 case MRT_ADD_VIF:
299 case MRT_DEL_VIF:
300 case MRT_ADD_MFC:
301 case MRT_DEL_MFC:
302 case MRT_VERSION:
303 case MRT_ASSERT:
304 if (op == PRCO_SETOPT) {
305 error = ip_mrouter_set(optname, so, *m);
306 if (*m)
307 (void)m_free(*m);
308 } else if (op == PRCO_GETOPT) {
309 error = ip_mrouter_get(optname, so, m);
310 } else
311 error = EINVAL;
312 return (error);
313 }
314 return (ip_ctloutput(op, so, level, optname, m));
315 }
316
317 /*
318 * This function exists solely to receive the PRC_IFDOWN messages which
319 * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
320 * and calls in_ifadown() to remove all routes corresponding to that address.
321 * It also receives the PRC_IFUP messages from if_up() and reinstalls the
322 * interface routes.
323 */
324 void
325 rip_ctlinput(cmd, sa, vip)
326 int cmd;
327 struct sockaddr *sa;
328 void *vip;
329 {
330 struct in_ifaddr *ia;
331 struct ifnet *ifp;
332 int err;
333 int flags;
334
335 switch(cmd) {
336 case PRC_IFDOWN:
337 for (ia = in_ifaddrhead.tqh_first; ia;
338 ia = ia->ia_link.tqe_next) {
339 if (ia->ia_ifa.ifa_addr == sa
340 && (ia->ia_flags & IFA_ROUTE)) {
341 /*
342 * in_ifscrub kills the interface route.
343 */
344 in_ifscrub(ia->ia_ifp, ia);
345 /*
346 * in_ifadown gets rid of all the rest of
347 * the routes. This is not quite the right
348 * thing to do, but at least if we are running
349 * a routing process they will come back.
350 */
351 in_ifadown(&ia->ia_ifa);
352 break;
353 }
354 }
355 break;
356
357 case PRC_IFUP:
358 for (ia = in_ifaddrhead.tqh_first; ia;
359 ia = ia->ia_link.tqe_next) {
360 if (ia->ia_ifa.ifa_addr == sa)
361 break;
362 }
363 if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
364 return;
365 flags = RTF_UP;
366 ifp = ia->ia_ifa.ifa_ifp;
367
368 if ((ifp->if_flags & IFF_LOOPBACK)
369 || (ifp->if_flags & IFF_POINTOPOINT))
370 flags |= RTF_HOST;
371
372 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
373 if (err == 0)
374 ia->ia_flags |= IFA_ROUTE;
375 break;
376 }
377 }
378
379 static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */
380 static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */
381
382 /*ARGSUSED*/
383 int
384 rip_usrreq(so, req, m, nam, control)
385 register struct socket *so;
386 int req;
387 struct mbuf *m, *nam, *control;
388 {
389 register int error = 0;
390 register struct inpcb *inp = sotoinpcb(so);
391
392 if (req == PRU_CONTROL)
393 return (in_control(so, (u_long)m, (caddr_t)nam,
394 (struct ifnet *)control));
395
396 switch (req) {
397
398 case PRU_ATTACH:
399 if (inp)
400 panic("rip_attach");
401 if ((so->so_state & SS_PRIV) == 0) {
402 error = EACCES;
403 break;
404 }
405 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
406 (error = in_pcballoc(so, &ripcbinfo)))
407 break;
408 inp = (struct inpcb *)so->so_pcb;
409 inp->inp_ip.ip_p = (int)nam;
410 break;
411
412 case PRU_DISCONNECT:
413 if ((so->so_state & SS_ISCONNECTED) == 0) {
414 error = ENOTCONN;
415 break;
416 }
417 /* FALLTHROUGH */
418 case PRU_ABORT:
419 soisdisconnected(so);
420 /* FALLTHROUGH */
421 case PRU_DETACH:
422 if (inp == 0)
423 panic("rip_detach");
424 if (so == ip_mrouter)
425 ip_mrouter_done();
426 ip_rsvp_force_done(so);
427 if (so == ip_rsvpd)
428 ip_rsvp_done();
429 in_pcbdetach(inp);
430 break;
431
432 case PRU_BIND:
433 {
434 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
435
436 if (nam->m_len != sizeof(*addr)) {
437 error = EINVAL;
438 break;
439 }
440 if (TAILQ_EMPTY(&ifnet) ||
441 ((addr->sin_family != AF_INET) &&
442 (addr->sin_family != AF_IMPLINK)) ||
443 (addr->sin_addr.s_addr &&
444 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
445 error = EADDRNOTAVAIL;
446 break;
447 }
448 inp->inp_laddr = addr->sin_addr;
449 break;
450 }
451 case PRU_CONNECT:
452 {
453 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
454
455 if (nam->m_len != sizeof(*addr)) {
456 error = EINVAL;
457 break;
458 }
459 if (TAILQ_EMPTY(&ifnet)) {
460 error = EADDRNOTAVAIL;
461 break;
462 }
463 if ((addr->sin_family != AF_INET) &&
464 (addr->sin_family != AF_IMPLINK)) {
465 error = EAFNOSUPPORT;
466 break;
467 }
468 inp->inp_faddr = addr->sin_addr;
469 soisconnected(so);
470 break;
471 }
472
473 case PRU_CONNECT2:
474 error = EOPNOTSUPP;
475 break;
476
477 /*
478 * Mark the connection as being incapable of further input.
479 */
480 case PRU_SHUTDOWN:
481 socantsendmore(so);
482 break;
483
484 /*
485 * Ship a packet out. The appropriate raw output
486 * routine handles any massaging necessary.
487 */
488 case PRU_SEND:
489 {
490 register u_long dst;
491
492 if (so->so_state & SS_ISCONNECTED) {
493 if (nam) {
494 error = EISCONN;
495 break;
496 }
497 dst = inp->inp_faddr.s_addr;
498 } else {
499 if (nam == NULL) {
500 error = ENOTCONN;
501 break;
502 }
503 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
504 }
505 error = rip_output(m, so, dst);
506 m = NULL;
507 break;
508 }
509
510 case PRU_SENSE:
511 /*
512 * stat: don't bother with a blocksize.
513 */
514 return (0);
515
516 /*
517 * Not supported.
518 */
519 case PRU_RCVOOB:
520 case PRU_RCVD:
521 case PRU_LISTEN:
522 case PRU_ACCEPT:
523 case PRU_SENDOOB:
524 error = EOPNOTSUPP;
525 break;
526
527 case PRU_SOCKADDR:
528 in_setsockaddr(inp, nam);
529 break;
530
531 case PRU_PEERADDR:
532 in_setpeeraddr(inp, nam);
533 break;
534
535 default:
536 panic("rip_usrreq");
537 }
538 if (m != NULL)
539 m_freem(m);
540 return (error);
541 }

Properties

Name Value
svn:keywords FreeBSD=%H

  ViewVC Help
Powered by ViewVC 1.1.27