1 /*	$OpenBSD: if_faith.c,v 1.17 2003/12/16 20:33:25 markus Exp $	*/
2 /*
3  * Copyright (c) 1982, 1986, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*
31  * derived from
32  *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
33  * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
34  */
35 
36 /*
37  * Loopback interface driver for protocol testing and timing.
38  */
39 #include "faith.h"
40 
41 #if NFAITH > 0
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/ioctl.h>
48 
49 #include <net/if.h>
50 #include <net/if_types.h>
51 #include <net/netisr.h>
52 #include <net/route.h>
53 #include <net/bpf.h>
54 
55 #ifdef	INET
56 #include <netinet/in.h>
57 #include <netinet/in_var.h>
58 #endif
59 
60 #ifdef INET6
61 #ifndef INET
62 #include <netinet/in.h>
63 #endif
64 #include <netinet6/in6_var.h>
65 #endif
66 
67 #include "bpfilter.h"
68 
69 static int faithioctl(struct ifnet *, u_long, caddr_t);
70 int faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
71 	struct rtentry *);
72 static void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
73 
74 void	faithattach(int);
75 int	faith_clone_create(struct if_clone *, int);
76 int	faith_clone_destroy(struct ifnet *ifp);
77 
78 struct if_clone faith_cloner =
79     IF_CLONE_INITIALIZER("faith", faith_clone_create, faith_clone_destroy);
80 
81 #define	FAITHMTU	1500
82 
83 /* ARGSUSED */
84 void
faithattach(faith)85 faithattach(faith)
86 	int faith;
87 {
88 	if_clone_attach(&faith_cloner);
89 }
90 
91 int
faith_clone_create(ifc,unit)92 faith_clone_create(ifc, unit)
93 	struct if_clone *ifc;
94 	int unit;
95 {
96 	struct ifnet *ifp;
97 
98 	ifp = malloc(sizeof(*ifp), M_DEVBUF, M_NOWAIT);
99 	if (!ifp)
100 		return (ENOMEM);
101 	bzero(ifp, sizeof(*ifp));
102 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
103 	    unit);
104 	ifp->if_mtu = FAITHMTU;
105 	/* Change to BROADCAST experimentaly to announce its prefix. */
106 	ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
107 	ifp->if_ioctl = faithioctl;
108 	ifp->if_output = faithoutput;
109 	ifp->if_type = IFT_FAITH;
110 	ifp->if_hdrlen = 0;
111 	ifp->if_addrlen = 0;
112 	if_attach(ifp);
113 	if_alloc_sadl(ifp);
114 #if NBPFILTER > 0
115 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
116 #endif
117 	return (0);
118 }
119 
120 int
faith_clone_destroy(ifp)121 faith_clone_destroy(ifp)
122 	struct ifnet *ifp;
123 {
124 #if NBPFILTER > 0
125 	bpfdetach(ifp);
126 #endif
127 	if_detach(ifp);
128 
129 	free(ifp, M_DEVBUF);
130 	return (0);
131 }
132 
133 int
faithoutput(ifp,m,dst,rt)134 faithoutput(ifp, m, dst, rt)
135 	struct ifnet *ifp;
136 	struct mbuf *m;
137 	struct sockaddr *dst;
138 	struct rtentry *rt;
139 {
140 	int s, isr;
141 	struct ifqueue *ifq = 0;
142 
143 	if ((m->m_flags & M_PKTHDR) == 0)
144 		panic("faithoutput no HDR");
145 #if NBPFILTER > 0
146 	/* BPF write needs to be handled specially */
147 	if (dst->sa_family == AF_UNSPEC) {
148 		dst->sa_family = *(mtod(m, int *));
149 		m->m_len -= sizeof(int);
150 		m->m_pkthdr.len -= sizeof(int);
151 		m->m_data += sizeof(int);
152 	}
153 
154 	if (ifp->if_bpf) {
155 		/*
156 		 * We need to prepend the address family as
157 		 * a four byte field.  Cons up a faith header
158 		 * to pacify bpf.  This is safe because bpf
159 		 * will only read from the mbuf (i.e., it won't
160 		 * try to free it or keep a pointer a to it).
161 		 */
162 		struct mbuf m0;
163 		u_int32_t af = dst->sa_family;
164 
165 		m0.m_flags = 0;
166 		m0.m_next = m;
167 		m0.m_len = 4;
168 		m0.m_data = (char *)&af;
169 
170 		bpf_mtap(ifp->if_bpf, &m0);
171 	}
172 #endif
173 
174 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
175 		m_freem(m);
176 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
177 		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
178 	}
179 	ifp->if_opackets++;
180 	ifp->if_obytes += m->m_pkthdr.len;
181 	switch (dst->sa_family) {
182 #ifdef INET
183 	case AF_INET:
184 		ifq = &ipintrq;
185 		isr = NETISR_IP;
186 		break;
187 #endif
188 #ifdef INET6
189 	case AF_INET6:
190 		ifq = &ip6intrq;
191 		isr = NETISR_IPV6;
192 		break;
193 #endif
194 	default:
195 		m_freem(m);
196 		return EAFNOSUPPORT;
197 	}
198 
199 	/* XXX do we need more sanity checks? */
200 
201 	m->m_pkthdr.rcvif = ifp;
202 	s = splimp();
203 	if (IF_QFULL(ifq)) {
204 		IF_DROP(ifq);
205 		m_freem(m);
206 		splx(s);
207 		return (ENOBUFS);
208 	}
209 	IF_ENQUEUE(ifq, m);
210 	schednetisr_virtual(isr);
211 	ifp->if_ipackets++;
212 	ifp->if_ibytes += m->m_pkthdr.len;
213 	splx(s);
214 	return (0);
215 }
216 
217 /* ARGSUSED */
218 static void
faithrtrequest(cmd,rt,info)219 faithrtrequest(cmd, rt, info)
220 	int cmd;
221 	struct rtentry *rt;
222 	struct rt_addrinfo *info;
223 {
224 	if (rt)
225 		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
226 }
227 
228 /*
229  * Process an ioctl request.
230  */
231 /* ARGSUSED */
232 static int
faithioctl(ifp,cmd,data)233 faithioctl(ifp, cmd, data)
234 	struct ifnet *ifp;
235 	u_long cmd;
236 	caddr_t data;
237 {
238 	struct ifaddr *ifa;
239 	struct ifreq *ifr = (struct ifreq *)data;
240 	int error = 0;
241 
242 	switch (cmd) {
243 
244 	case SIOCSIFADDR:
245 		ifp->if_flags |= IFF_UP | IFF_RUNNING;
246 		ifa = (struct ifaddr *)data;
247 		ifa->ifa_rtrequest = faithrtrequest;
248 		/*
249 		 * Everything else is done at a higher level.
250 		 */
251 		break;
252 
253 	case SIOCADDMULTI:
254 	case SIOCDELMULTI:
255 		if (ifr == 0) {
256 			error = EAFNOSUPPORT;		/* XXX */
257 			break;
258 		}
259 		switch (ifr->ifr_addr.sa_family) {
260 #ifdef INET
261 		case AF_INET:
262 			break;
263 #endif
264 #ifdef INET6
265 		case AF_INET6:
266 			break;
267 #endif
268 
269 		default:
270 			error = EAFNOSUPPORT;
271 			break;
272 		}
273 		break;
274 
275 	case SIOCSIFFLAGS:
276 		break;
277 
278 	default:
279 		error = EINVAL;
280 	}
281 	return (error);
282 }
283 #endif /* NFAITH > 0 */
284