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 *)⁡ 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