if_enc.c revision 1.3
1/*	$OpenBSD: if_enc.c,v 1.3 1997/02/27 04:05:45 angelos Exp $	*/
2
3/*
4 * The author of this code is John Ioannidis, ji@tla.org,
5 * 	(except when noted otherwise).
6 *
7 * This code was written for BSD/OS in Athens, Greece, in November 1995.
8 *
9 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
10 * by Angelos D. Keromytis, kermit@forthnet.gr.
11 *
12 * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
13 *
14 * Permission to use, copy, and modify this software without fee
15 * is hereby granted, provided that this entire notice is included in
16 * all copies of any software which is or includes a copy or
17 * modification of this software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
21 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
22 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
23 * PURPOSE.
24 */
25
26/*
27 * Encapsulation interface driver.
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/mbuf.h>
34#include <sys/socket.h>
35#include <sys/errno.h>
36#include <sys/ioctl.h>
37#include <sys/time.h>
38#include <machine/cpu.h>
39
40#include <net/if.h>
41#include <net/if_types.h>
42#include <net/netisr.h>
43#include <net/route.h>
44#include <net/bpf.h>
45
46#ifdef	INET
47#include <netinet/in.h>
48#include <netinet/in_systm.h>
49#include <netinet/in_var.h>
50#include <netinet/ip.h>
51#endif
52
53#ifdef ISO
54extern struct ifqueue clnlintrq;
55#endif
56
57#ifdef NS
58extern struct ifqueue nsintrq;
59#endif
60
61#include "bpfilter.h"
62
63#define	ENCMTU	(1024+512)
64
65/*
66 * Called from boot code to establish enc interfaces.
67 */
68
69struct enc_softc
70{
71	struct ifnet enc_if;
72} ;
73
74struct enc_softc *enc_softc;
75
76int nencap;
77
78void	encattach __P((int));
79int	encoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
80	    struct rtentry *));
81int	encioctl __P((struct ifnet *, u_long, caddr_t));
82void	encrtrequest __P((int, struct rtentry *, struct sockaddr *));
83
84void
85encattach(int nenc)
86{
87	register struct enc_softc *enc;
88	register int i = 0;
89
90	nencap = nenc;
91
92	enc_softc = malloc(nenc * sizeof (*enc_softc), M_DEVBUF, M_WAIT);
93	bzero(enc_softc, nenc * sizeof (*enc_softc));
94	for (enc = enc_softc; i < nenc; enc++)
95	{
96		enc->enc_if.if_index = i;
97		sprintf(enc->enc_if.if_xname, "enc%d", i++);
98		enc->enc_if.if_list.tqe_next = NULL;
99		enc->enc_if.if_mtu = ENCMTU;
100		enc->enc_if.if_flags = IFF_LOOPBACK;
101		enc->enc_if.if_type = IFT_ENC;
102		enc->enc_if.if_ioctl = encioctl;
103		enc->enc_if.if_output = encoutput;
104		enc->enc_if.if_hdrlen = 0;
105		enc->enc_if.if_addrlen = 0;
106		if_attach(&enc->enc_if);
107#if NBPFILTER > 0
108		bpfattach(&enc->enc_if.if_bpf, &enc->enc_if, DLT_NULL, sizeof(u_int));
109#endif
110	}
111}
112
113/*
114 * Shamelessly stolen from looutput()
115 */
116int
117encoutput(ifp, m, dst, rt)
118struct ifnet *ifp;
119register struct mbuf *m;
120struct sockaddr *dst;
121register struct rtentry *rt;
122{
123	int s, isr;
124	register struct ifqueue *ifq = 0;
125
126	/* register struct enc_softc *ec = &enc_softc[ifp->if_index]; */
127
128	if ((m->m_flags & M_PKTHDR) == 0)
129		panic("encoutput no HDR");
130	ifp->if_lastchange = time;
131#if NBPFILTER > 0
132	if (ifp->if_bpf) {
133		/*
134		 * We need to prepend the address family as
135		 * a four byte field.  Cons up a dummy header
136		 * to pacify bpf.  This is safe because bpf
137		 * will only read from the mbuf (i.e., it won't
138		 * try to free it or keep a pointer a to it).
139		 */
140		struct mbuf m0;
141		u_int af = dst->sa_family;
142
143		m0.m_next = m;
144		m0.m_len = 4;
145		m0.m_data = (char *)&af;
146
147		bpf_mtap(ifp->if_bpf, &m0);
148	}
149#endif
150	m->m_pkthdr.rcvif = ifp;
151
152	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
153		m_freem(m);
154		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
155		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
156	}
157	ifp->if_opackets++;
158	ifp->if_obytes += m->m_pkthdr.len;
159	switch (dst->sa_family) {
160
161#ifdef INET
162	case AF_INET:
163		ifq = &ipintrq;
164		isr = NETISR_IP;
165		break;
166#endif
167#ifdef NS
168	case AF_NS:
169		ifq = &nsintrq;
170		isr = NETISR_NS;
171		break;
172#endif
173#ifdef ISO
174	case AF_ISO:
175		ifq = &clnlintrq;
176		isr = NETISR_ISO;
177		break;
178#endif
179	default:
180		m_freem(m);
181		return (EAFNOSUPPORT);
182	}
183	s = splimp();
184	if (IF_QFULL(ifq)) {
185		IF_DROP(ifq);
186		m_freem(m);
187		splx(s);
188		return (ENOBUFS);
189	}
190	IF_ENQUEUE(ifq, m);
191	schednetisr(isr);
192	ifp->if_ipackets++;
193	ifp->if_ibytes += m->m_pkthdr.len;
194	splx(s);
195	return (0);
196}
197
198/* ARGSUSED */
199void
200encrtrequest(cmd, rt, sa)
201	int cmd;
202	struct rtentry *rt;
203	struct sockaddr *sa;
204{
205
206	if (rt)
207		rt->rt_rmx.rmx_mtu = ENCMTU;
208}
209
210/*
211 * Process an ioctl request.
212 * Also shamelessly stolen from loioctl()
213 */
214
215/* ARGSUSED */
216int
217encioctl(ifp, cmd, data)
218	register struct ifnet *ifp;
219	u_long cmd;
220	caddr_t data;
221{
222	register struct ifaddr *ifa;
223	register struct ifreq *ifr;
224	register int error = 0;
225
226	switch (cmd)
227	{
228	      case SIOCSIFADDR:
229		ifp->if_flags |= IFF_UP;
230		ifa = (struct ifaddr *)data;
231		/*
232		 * Everything else is done at a higher level.
233		 */
234		break;
235
236		switch (ifr->ifr_addr.sa_family) {
237
238#ifdef INET
239		      case AF_INET:
240			break;
241#endif
242		      case AF_ENCAP:
243			break;
244
245		      default:
246			error = EAFNOSUPPORT;
247			break;
248		}
249		break;
250
251	      default:
252		error = EINVAL;
253	}
254	return error;
255}
256