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