xref: /freebsd/sys/net/if_gif.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * 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. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * gif.c
34  */
35 
36 #include "opt_inet.h"
37 #include "opt_inet6.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <sys/errno.h>
47 #include <sys/time.h>
48 #include <sys/syslog.h>
49 #include <machine/cpu.h>
50 
51 #include <net/if.h>
52 #include <net/if_types.h>
53 #include <net/netisr.h>
54 #include <net/route.h>
55 #include <net/bpf.h>
56 
57 #ifdef	INET
58 #include <netinet/in.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in_var.h>
61 #include <netinet/ip.h>
62 #include <netinet/in_gif.h>
63 #endif	/* INET */
64 
65 #ifdef INET6
66 #ifndef INET
67 #include <netinet/in.h>
68 #endif
69 #include <netinet6/in6_var.h>
70 #include <netinet/ip6.h>
71 #include <netinet6/ip6_var.h>
72 #include <netinet6/in6_gif.h>
73 #endif /* INET6 */
74 
75 #include <net/if_gif.h>
76 
77 #include "gif.h"
78 
79 #include <net/net_osdep.h>
80 
81 void gifattach __P((void *));
82 
83 /*
84  * gif global variable definitions
85  */
86 int ngif = NGIF;		/* number of interfaces */
87 struct gif_softc *gif = 0;
88 
89 void
90 gifattach(dummy)
91 	void *dummy;
92 {
93 	register struct gif_softc *sc;
94 	register int i;
95 
96 	gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAIT);
97 	bzero(sc, ngif * sizeof(struct gif_softc));
98 	for (i = 0; i < ngif; sc++, i++) {
99 		sc->gif_if.if_name = "gif";
100 		sc->gif_if.if_unit = i;
101 		sc->gif_if.if_mtu    = GIF_MTU;
102 		sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
103 		sc->gif_if.if_ioctl  = gif_ioctl;
104 		sc->gif_if.if_output = gif_output;
105 		sc->gif_if.if_type   = IFT_GIF;
106 		sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen;
107 		if_attach(&sc->gif_if);
108 		bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
109 	}
110 }
111 
112 PSEUDO_SET(gifattach, if_gif);
113 
114 int
115 gif_output(ifp, m, dst, rt)
116 	struct ifnet *ifp;
117 	struct mbuf *m;
118 	struct sockaddr *dst;
119 	struct rtentry *rt;	/* added in net2 */
120 {
121 	register struct gif_softc *sc = (struct gif_softc*)ifp;
122 	int error = 0;
123 	static int called = 0;	/* XXX: MUTEX */
124 	int calllimit = 10;	/* XXX: adhoc */
125 
126 	/*
127 	 * gif may cause infinite recursion calls when misconfigured.
128 	 * We'll prevent this by introducing upper limit.
129 	 * XXX: this mechanism may introduce another problem about
130 	 *      mutual exclusion of the variable CALLED, especially if we
131 	 *      use kernel thread.
132 	 */
133 	if (++called >= calllimit) {
134 		log(LOG_NOTICE,
135 		    "gif_output: recursively called too many times(%d)\n",
136 		    called);
137 		m_freem(m);
138 		error = EIO;	/* is there better errno? */
139 		goto end;
140 	}
141 	getmicrotime(&ifp->if_lastchange);
142 	m->m_flags &= ~(M_BCAST|M_MCAST);
143 	if (!(ifp->if_flags & IFF_UP) ||
144 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
145 		m_freem(m);
146 		error = ENETDOWN;
147 		goto end;
148 	}
149 
150 	if (ifp->if_bpf) {
151 		/*
152 		 * We need to prepend the address family as
153 		 * a four byte field.  Cons up a dummy header
154 		 * to pacify bpf.  This is safe because bpf
155 		 * will only read from the mbuf (i.e., it won't
156 		 * try to free it or keep a pointer a to it).
157 		 */
158 		struct mbuf m0;
159 		u_int af = dst->sa_family;
160 
161 		m0.m_next = m;
162 		m0.m_len = 4;
163 		m0.m_data = (char *)&af;
164 
165 		bpf_mtap(ifp, &m0);
166 	}
167 	ifp->if_opackets++;
168 	ifp->if_obytes += m->m_pkthdr.len;
169 
170 	switch (sc->gif_psrc->sa_family) {
171 #ifdef INET
172 	case AF_INET:
173 		error = in_gif_output(ifp, dst->sa_family, m, rt);
174 		break;
175 #endif
176 #ifdef INET6
177 	case AF_INET6:
178 		error = in6_gif_output(ifp, dst->sa_family, m, rt);
179 		break;
180 #endif
181 	default:
182 		m_freem(m);
183 		error = ENETDOWN;
184 	}
185 
186   end:
187 	called = 0;		/* reset recursion counter */
188 	if (error) ifp->if_oerrors++;
189 	return error;
190 }
191 
192 void
193 gif_input(m, af, gifp)
194 	struct mbuf *m;
195 	int af;
196 	struct ifnet *gifp;
197 {
198 	int s, isr;
199 	register struct ifqueue *ifq = 0;
200 
201 	if (gifp == NULL) {
202 		/* just in case */
203 		m_freem(m);
204 		return;
205 	}
206 
207 	if (m->m_pkthdr.rcvif)
208 		m->m_pkthdr.rcvif = gifp;
209 
210 	if (gifp->if_bpf) {
211 		/*
212 		 * We need to prepend the address family as
213 		 * a four byte field.  Cons up a dummy header
214 		 * to pacify bpf.  This is safe because bpf
215 		 * will only read from the mbuf (i.e., it won't
216 		 * try to free it or keep a pointer a to it).
217 		 */
218 		struct mbuf m0;
219 		u_int af = AF_INET6;
220 
221 		m0.m_next = m;
222 		m0.m_len = 4;
223 		m0.m_data = (char *)&af;
224 
225 		bpf_mtap(gifp, &m0);
226 	}
227 
228 	/*
229 	 * Put the packet to the network layer input queue according to the
230 	 * specified address family.
231 	 * Note: older versions of gif_input directly called network layer
232 	 * input functions, e.g. ip6_input, here. We changed the policy to
233 	 * prevent too many recursive calls of such input functions, which
234 	 * might cause kernel panic. But the change may introduce another
235 	 * problem; if the input queue is full, packets are discarded.
236 	 * We believed it rarely occurs and changed the policy. If we find
237 	 * it occurs more times than we thought, we may change the policy
238 	 * again.
239 	 */
240 	switch (af) {
241 #ifdef INET
242 	case AF_INET:
243 		ifq = &ipintrq;
244 		isr = NETISR_IP;
245 		break;
246 #endif
247 #ifdef INET6
248 	case AF_INET6:
249 		ifq = &ip6intrq;
250 		isr = NETISR_IPV6;
251 		break;
252 #endif
253 	default:
254 		m_freem(m);
255 		return;
256 	}
257 
258 	s = splimp();
259 	if (IF_QFULL(ifq)) {
260 		IF_DROP(ifq);	/* update statistics */
261 		m_freem(m);
262 		splx(s);
263 		return;
264 	}
265 	IF_ENQUEUE(ifq, m);
266 	/* we need schednetisr since the address family may change */
267 	schednetisr(isr);
268 	gifp->if_ipackets++;
269 	gifp->if_ibytes += m->m_pkthdr.len;
270 	splx(s);
271 
272 	return;
273 }
274 
275 
276 int
277 gif_ioctl(ifp, cmd, data)
278 	struct ifnet *ifp;
279 	u_long cmd;
280 	caddr_t data;
281 {
282 	struct gif_softc *sc  = (struct gif_softc*)ifp;
283 	struct ifreq     *ifr = (struct ifreq*)data;
284 	int error = 0, size;
285 	struct sockaddr *sa, *dst, *src;
286 
287 	switch (cmd) {
288 	case SIOCSIFADDR:
289 		break;
290 
291 	case SIOCSIFDSTADDR:
292 		break;
293 
294 	case SIOCADDMULTI:
295 	case SIOCDELMULTI:
296 		break;
297 
298 	case SIOCGIFMTU:
299 		break;
300 	case SIOCSIFMTU:
301 		{
302 			u_long mtu;
303 			mtu = ifr->ifr_mtu;
304 			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
305 				return (EINVAL);
306 			}
307 			ifp->if_mtu = mtu;
308 		}
309 		break;
310 
311 	case SIOCSIFPHYADDR:
312 #ifdef INET6
313 	case SIOCSIFPHYADDR_IN6:
314 #endif /* INET6 */
315 		switch (ifr->ifr_addr.sa_family) {
316 #ifdef INET
317 		case AF_INET:
318 			src = (struct sockaddr *)
319 				&(((struct in_aliasreq *)data)->ifra_addr);
320 			dst = (struct sockaddr *)
321 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
322 
323 			/* only one gif can have dst = INADDR_ANY */
324 #define	satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr)
325 
326 			if (satosaddr(dst) == INADDR_ANY) {
327 				int i;
328 				struct gif_softc *sc2;
329 
330 			  	for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
331 					if (sc2 == sc) continue;
332 					if (sc2->gif_pdst &&
333 					    satosaddr(sc2->gif_pdst)
334 						== INADDR_ANY) {
335 					    error = EADDRNOTAVAIL;
336 					    goto bad;
337 					}
338 				}
339 			}
340 			size = sizeof(struct sockaddr_in);
341 			break;
342 #endif /* INET */
343 #ifdef INET6
344 		case AF_INET6:
345 			src = (struct sockaddr *)
346 				&(((struct in6_aliasreq *)data)->ifra_addr);
347 			dst = (struct sockaddr *)
348 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
349 
350 			/* only one gif can have dst = in6addr_any */
351 #define	satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr)
352 
353 			if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) {
354 				int i;
355 				struct gif_softc *sc2;
356 
357 			  	for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
358 					if (sc2 == sc) continue;
359 					if (sc2->gif_pdst &&
360 					    IN6_IS_ADDR_UNSPECIFIED(
361 						satoin6(sc2->gif_pdst)
362 								    )) {
363 					    error = EADDRNOTAVAIL;
364 					    goto bad;
365 					}
366 				}
367 			}
368 			size = sizeof(struct sockaddr_in6);
369 			break;
370 #endif /* INET6 */
371 		default:
372 			error = EPROTOTYPE;
373 			goto bad;
374 			break;
375 		}
376 		if (sc->gif_psrc != NULL)
377 			free((caddr_t)sc->gif_psrc, M_IFADDR);
378 		if (sc->gif_pdst != NULL)
379 			free((caddr_t)sc->gif_pdst, M_IFADDR);
380 
381 		sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
382 		bzero((caddr_t)sa, size);
383 		bcopy((caddr_t)src, (caddr_t)sa, size);
384 		sc->gif_psrc = sa;
385 
386 		sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
387 		bzero((caddr_t)sa, size);
388 		bcopy((caddr_t)dst, (caddr_t)sa, size);
389 		sc->gif_pdst = sa;
390 
391 		ifp->if_flags |= (IFF_UP|IFF_RUNNING);
392 		{
393 			int s;
394 
395 			s = splnet();
396 			if_up(ifp);		/* send up RTM_IFINFO */
397 			splx(s);
398 		}
399 
400 		break;
401 
402 	case SIOCGIFPSRCADDR:
403 #ifdef INET6
404 	case SIOCGIFPSRCADDR_IN6:
405 #endif /* INET6 */
406 		if (sc->gif_psrc == NULL) {
407 			error = EADDRNOTAVAIL;
408 			goto bad;
409 		}
410 		src = sc->gif_psrc;
411 		switch (sc->gif_psrc->sa_family) {
412 #ifdef INET
413 		case AF_INET:
414 			dst = &ifr->ifr_addr;
415 			size = sizeof(struct sockaddr_in);
416 			break;
417 #endif /* INET */
418 #ifdef INET6
419 		case AF_INET6:
420 			dst = (struct sockaddr *)
421 				&(((struct in6_ifreq *)data)->ifr_addr);
422 			size = sizeof(struct sockaddr_in6);
423 			break;
424 #endif /* INET6 */
425 		default:
426 			error = EADDRNOTAVAIL;
427 			goto bad;
428 		}
429 		bcopy((caddr_t)src, (caddr_t)dst, size);
430 		break;
431 
432 	case SIOCGIFPDSTADDR:
433 #ifdef INET6
434 	case SIOCGIFPDSTADDR_IN6:
435 #endif /* INET6 */
436 		if (sc->gif_pdst == NULL) {
437 			error = EADDRNOTAVAIL;
438 			goto bad;
439 		}
440 		src = sc->gif_pdst;
441 		switch (sc->gif_pdst->sa_family) {
442 #ifdef INET
443 		case AF_INET:
444 			dst = &ifr->ifr_addr;
445 			size = sizeof(struct sockaddr_in);
446 			break;
447 #endif /* INET */
448 #ifdef INET6
449 		case AF_INET6:
450 			dst = (struct sockaddr *)
451 				&(((struct in6_ifreq *)data)->ifr_addr);
452 			size = sizeof(struct sockaddr_in6);
453 			break;
454 #endif /* INET6 */
455 		default:
456 			error = EADDRNOTAVAIL;
457 			goto bad;
458 		}
459 		bcopy((caddr_t)src, (caddr_t)dst, size);
460 		break;
461 
462 	case SIOCSIFFLAGS:
463 		break;
464 
465 	default:
466 		error = EINVAL;
467 		break;
468 	}
469  bad:
470 	return error;
471 }
472