if_enc.c revision 1.11
1/*	$OpenBSD: if_enc.c,v 1.11 1999/07/05 20:17:05 deraadt Exp $	*/
2
3/*
4 * The authors of this code are John Ioannidis (ji@tla.org),
5 * Angelos D. Keromytis (kermit@csd.uch.gr) and
6 * Niels Provos (provos@physnet.uni-hamburg.de).
7 *
8 * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
9 * in November 1995.
10 *
11 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
12 * by Angelos D. Keromytis.
13 *
14 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
15 * and Niels Provos.
16 *
17 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
18 * and Niels Provos.
19 *
20 * Permission to use, copy, and modify this software without fee
21 * is hereby granted, provided that this entire notice is included in
22 * all copies of any software which is or includes a copy or
23 * modification of this software.
24 * You may use this code under the GNU public license if you so wish. Please
25 * contribute changes back to the authors under this freer than GPL license
26 * so that we may further the use of strong encryption without limitations to
27 * all.
28 *
29 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
31 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
32 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
33 * PURPOSE.
34 */
35
36/*
37 * Encapsulation interface driver.
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45#include <sys/errno.h>
46#include <sys/ioctl.h>
47#include <sys/time.h>
48#include <machine/cpu.h>
49
50#include <net/if.h>
51#include <net/if_types.h>
52#include <net/netisr.h>
53#include <net/route.h>
54#include <net/bpf.h>
55#include <net/if_enc.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#endif
63
64#ifdef ISO
65extern struct ifqueue clnlintrq;
66#endif
67
68#ifdef NS
69extern struct ifqueue nsintrq;
70#endif
71
72#include "bpfilter.h"
73
74struct ifnet encif;
75
76void	encattach __P((int));
77int	encoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
78	    	       struct rtentry *));
79int	encioctl __P((struct ifnet *, u_long, caddr_t));
80void	encrtrequest __P((int, struct rtentry *, struct sockaddr *));
81
82void
83encattach(int nenc)
84{
85	bzero(&encif, sizeof(encif));
86
87	/* We only need one interface anyway under the new mode of operation */
88	encif.if_index = 0;
89
90	encif.if_softc = &encif;
91	sprintf(encif.if_xname, "enc0");
92	encif.if_list.tqe_next = NULL;
93	encif.if_mtu = ENCMTU;
94	encif.if_flags = 0;
95	encif.if_type = IFT_ENC;
96	encif.if_ioctl = encioctl;
97	encif.if_output = encoutput;
98	encif.if_hdrlen = ENC_HDRLEN;
99	encif.if_addrlen = 0;
100	if_attach(&encif);
101
102#if NBPFILTER > 0
103	bpfattach(&encif.if_bpf, &encif, DLT_ENC, ENC_HDRLEN);
104#endif
105}
106
107/*
108 * Shamelessly stolen from looutput()
109 */
110int
111encoutput(ifp, m, dst, rt)
112struct ifnet *ifp;
113register struct mbuf *m;
114struct sockaddr *dst;
115register struct rtentry *rt;
116{
117	register struct ifqueue *ifq = 0;
118	int s, isr;
119
120	if ((m->m_flags & M_PKTHDR) == 0)
121		panic("encoutput(): no HDR");
122
123	ifp->if_lastchange = time;
124	m->m_pkthdr.rcvif = ifp;
125
126	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
127		m_freem(m);
128		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
129		    rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
130	}
131
132	ifp->if_opackets++;
133	ifp->if_obytes += m->m_pkthdr.len;
134
135	switch (dst->sa_family) {
136#ifdef INET
137	case AF_INET:
138		ifq = &ipintrq;
139		isr = NETISR_IP;
140		break;
141#endif
142#ifdef NS
143	case AF_NS:
144		ifq = &nsintrq;
145		isr = NETISR_NS;
146		break;
147#endif
148#ifdef ISO
149	case AF_ISO:
150		ifq = &clnlintrq;
151		isr = NETISR_ISO;
152		break;
153#endif
154	default:
155		m_freem(m);
156		return (EAFNOSUPPORT);
157	}
158
159	s = splimp();
160	if (IF_QFULL(ifq)) {
161		IF_DROP(ifq);
162		m_freem(m);
163		splx(s);
164		return (ENOBUFS);
165	}
166
167	IF_ENQUEUE(ifq, m);
168	schednetisr(isr);
169
170	/* Statistics */
171	ifp->if_ipackets++;
172	ifp->if_ibytes += m->m_pkthdr.len;
173	splx(s);
174	return (0);
175}
176
177/* ARGSUSED */
178void
179encrtrequest(cmd, rt, sa)
180	int cmd;
181	struct rtentry *rt;
182	struct sockaddr *sa;
183{
184	if (rt)
185		rt->rt_rmx.rmx_mtu = ENCMTU;
186}
187
188/* ARGSUSED */
189int
190encioctl(ifp, cmd, data)
191	register struct ifnet *ifp;
192	u_long cmd;
193	caddr_t data;
194{
195	register struct ifaddr *ifa;
196	register int error = 0;
197
198	switch (cmd) {
199	case SIOCSIFADDR:
200		/*
201		 * Everything else is done at a higher level.
202		 */
203		ifp->if_flags |= IFF_UP;
204		ifa = (struct ifaddr *) data;
205		break;
206
207	default:
208		error = EINVAL;
209		break;
210	}
211	return (error);
212}
213