if_enc.c revision 1.4
1/*	$OpenBSD: if_enc.c,v 1.4 1997/07/01 22:12:39 provos 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
65struct ifnet enc_softc;
66
67void	encattach __P((int));
68int	encoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
69	    struct rtentry *));
70int	encioctl __P((struct ifnet *, u_long, caddr_t));
71void	encrtrequest __P((int, struct rtentry *, struct sockaddr *));
72
73void
74encattach(int nenc)
75{
76    struct ifaddr *ifa;
77
78    bzero(&enc_softc, sizeof(struct ifnet));
79
80    /* We only need one interface anyway under the new mode of operation */
81    enc_softc.if_index = 0;
82
83    sprintf(enc_softc.if_xname, "enc0");
84
85    enc_softc.if_list.tqe_next = NULL;
86    enc_softc.if_mtu = ENCMTU;
87    enc_softc.if_flags = IFF_LOOPBACK;
88    enc_softc.if_type = IFT_ENC;
89    enc_softc.if_ioctl = encioctl;
90    enc_softc.if_output = encoutput;
91    enc_softc.if_hdrlen = 0;
92    enc_softc.if_addrlen = 0;
93
94    if_attach(&enc_softc);
95
96#if NBPFILTER > 0
97    bpfattach(&(enc_softc.if_bpf), &enc_softc, DLT_NULL, sizeof(u_int32_t));
98#endif
99
100    /* Just a bogus entry */
101    ifa = (struct ifaddr *)malloc(sizeof(struct ifaddr) +
102			sizeof(struct sockaddr), M_IFADDR, M_WAITOK);
103    bzero(ifa, sizeof(struct ifaddr) + sizeof(struct sockaddr));
104    ifa->ifa_addr = ifa->ifa_dstaddr = (struct sockaddr *)(ifa + 1);
105    ifa->ifa_ifp = &enc_softc;
106    TAILQ_INSERT_HEAD(&(enc_softc.if_addrlist), ifa, ifa_list);
107}
108
109/*
110 * Shamelessly stolen from looutput()
111 */
112int
113encoutput(ifp, m, dst, rt)
114struct ifnet *ifp;
115register struct mbuf *m;
116struct sockaddr *dst;
117register struct rtentry *rt;
118{
119    register struct ifqueue *ifq = 0;
120    int s, isr;
121
122    if ((m->m_flags & M_PKTHDR) == 0)
123      panic("encoutput no HDR");
124
125    ifp->if_lastchange = time;
126
127#if NBPFILTER > 0
128    if (ifp->if_bpf)
129    {
130	/*
131	 * We need to prepend the address family as
132	 * a four byte field.  Cons up a dummy header
133	 * to pacify bpf.  This is safe because bpf
134	 * will only read from the mbuf (i.e., it won't
135	 * try to free it or keep a pointer a to it).
136	 */
137	struct mbuf m0;
138	u_int af = dst->sa_family;
139
140	m0.m_next = m;
141	m0.m_len = 4;
142	m0.m_data = (char *)&af;
143
144	bpf_mtap(ifp->if_bpf, &m0);
145    }
146#endif
147
148    m->m_pkthdr.rcvif = ifp;
149
150    if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE))
151    {
152	m_freem(m);
153	return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
154		rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
155    }
156
157    ifp->if_opackets++;
158    ifp->if_obytes += m->m_pkthdr.len;
159
160    switch (dst->sa_family)
161    {
162#ifdef INET
163	case AF_INET:
164	    ifq = &ipintrq;
165	    isr = NETISR_IP;
166	    break;
167#endif
168#ifdef NS
169	case AF_NS:
170	    ifq = &nsintrq;
171	    isr = NETISR_NS;
172	    break;
173#endif
174#ifdef ISO
175	case AF_ISO:
176	    ifq = &clnlintrq;
177	    isr = NETISR_ISO;
178		break;
179#endif
180	default:
181	    m_freem(m);
182	    return (EAFNOSUPPORT);
183    }
184
185    s = splimp();
186
187    if (IF_QFULL(ifq))
188    {
189	IF_DROP(ifq);
190	m_freem(m);
191	splx(s);
192	return (ENOBUFS);
193    }
194
195    IF_ENQUEUE(ifq, m);
196    schednetisr(isr);
197
198    /* Statistics */
199    ifp->if_ipackets++;
200    ifp->if_ibytes += m->m_pkthdr.len;
201
202    splx(s);
203
204    return (0);
205}
206
207/* ARGSUSED */
208void
209encrtrequest(cmd, rt, sa)
210int cmd;
211struct rtentry *rt;
212struct sockaddr *sa;
213{
214    if (rt)
215      rt->rt_rmx.rmx_mtu = ENCMTU;
216}
217
218
219/*
220 * Process an ioctl request.
221 * Also shamelessly stolen from loioctl()
222 */
223
224/* ARGSUSED */
225int
226encioctl(ifp, cmd, data)
227register struct ifnet *ifp;
228u_long cmd;
229caddr_t data;
230{
231    register struct ifaddr *ifa;
232    register int error = 0;
233
234    switch (cmd)
235    {
236	case SIOCSIFADDR:
237	    /*
238	     * Everything else is done at a higher level.
239	     */
240
241	    ifp->if_flags |= IFF_UP;
242	    ifa = (struct ifaddr *)data;
243
244	    break;
245
246	default:
247	    error = EINVAL;
248    }
249
250    return error;
251}
252