1 /* $NetBSD: ether_bpf.c,v 1.10 2008/12/14 18:46:33 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1998 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 #include "sanamespace.h" 30 31 #include <stdio.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <limits.h> 36 #include <sys/ioctl.h> 37 #include <sys/queue.h> 38 #include <sys/socket.h> 39 #include <net/if.h> 40 #include <net/bpf.h> 41 #include <net/if_dl.h> 42 #include <netinet/in.h> 43 #include <kvm.h> 44 #include <nlist.h> 45 #include <string.h> 46 #include <err.h> 47 #include <errno.h> 48 49 #include <netif/netif_small.h> 50 #include <netif/etherdrv.h> 51 52 #define BPFDEV "/dev/bpf0" 53 54 #define MAXPKT 1536 55 56 /* 57 * Allows to use any configured interface with 58 * standalone network code. Provides the interface used 59 * by i386/stand/lib/netif/netif_small.c. 60 */ 61 62 static int bpf = -1; 63 64 static struct nlist nl[] = { 65 {"_ifnet"}, 66 {NULL} 67 }; 68 69 int 70 EtherInit(char *ha) 71 { 72 int res; 73 u_int val; 74 struct ifreq ifr; 75 kvm_t *kvm; 76 char errbuf[_POSIX2_LINE_MAX]; 77 struct ifnet_head ifh; 78 struct ifnet *ifp; 79 struct ifaddr *ifap = 0; 80 struct sockaddr_dl *sdlp; 81 int sdllen; 82 83 bpf = open(BPFDEV, O_RDWR, 0); 84 if (bpf < 0) { 85 warn("open %s", BPFDEV); 86 return 0; 87 } 88 89 val = MAXPKT; 90 res = ioctl(bpf, BIOCSBLEN, &val); 91 if (res < 0) { 92 warn("ioctl BIOCSBLEN"); 93 return 0; 94 } 95 96 val = 1; 97 res = ioctl(bpf, BIOCIMMEDIATE, &val); 98 if (res < 0) { 99 warn("ioctl BIOCIMMEDIATE"); 100 return 0; 101 } 102 103 val = 1; 104 res = ioctl(bpf, FIONBIO, &val); 105 if (res < 0) { 106 warn("ioctl FIONBIO"); 107 return 0; 108 } 109 110 memcpy(ifr.ifr_name, BPF_IFNAME, IFNAMSIZ); 111 res = ioctl(bpf, BIOCSETIF, &ifr); 112 if (res < 0) { 113 warn("ioctl BIOCSETIF %s", BPF_IFNAME); 114 return 0; 115 } 116 117 kvm = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); 118 if (!kvm) { 119 warnx(errbuf); 120 return 0; 121 } 122 if (kvm_nlist(kvm, nl) < 0) { 123 warnx("nlist failed (%s)", kvm_geterr(kvm)); 124 kvm_close(kvm); 125 return 0; 126 } 127 128 kvm_read(kvm, nl[0].n_value, &ifh, sizeof(struct ifnet_head)); 129 ifp = TAILQ_FIRST(&ifh); 130 while (ifp) { 131 struct ifnet ifnet; 132 kvm_read(kvm, (u_long)ifp, &ifnet, sizeof(struct ifnet)); 133 if (!strcmp(ifnet.if_xname, BPF_IFNAME)) { 134 ifap = IFADDR_FIRST(&ifnet); 135 break; 136 } 137 ifp = IFNET_NEXT(&ifnet); 138 } 139 if (!ifp) { 140 warnx("interface not found"); 141 kvm_close(kvm); 142 return 0; 143 } 144 145 #define _offsetof(t, m) ((int)((void *)&((t *)0)->m)) 146 sdllen = _offsetof(struct sockaddr_dl, 147 sdl_data[0]) + strlen(BPF_IFNAME) + 6; 148 sdlp = malloc(sdllen); 149 150 while (ifap) { 151 struct ifaddr ifaddr; 152 kvm_read(kvm, (u_long)ifap, &ifaddr, sizeof(struct ifaddr)); 153 kvm_read(kvm, (u_long)ifaddr.ifa_addr, sdlp, sdllen); 154 if (sdlp->sdl_family == AF_LINK) { 155 memcpy(ha, CLLADDR(sdlp), 6); 156 break; 157 } 158 ifap = IFADDR_NEXT(&ifaddr); 159 } 160 free(sdlp); 161 kvm_close(kvm); 162 if (!ifap) { 163 warnx("interface hw addr not found"); 164 return 0; 165 } 166 return 1; 167 } 168 169 void 170 EtherStop(void) 171 { 172 173 if (bpf != -1) 174 close(bpf); 175 } 176 177 int 178 EtherSend(char *pkt, int len) 179 { 180 181 if (write(bpf, pkt, len) != len) { 182 warn("EtherSend"); 183 return -1; 184 } 185 return len; 186 } 187 188 static union { 189 struct bpf_hdr h; 190 u_char buf[MAXPKT]; 191 } rbuf; 192 193 int 194 EtherReceive(char *pkt, int maxlen) 195 { 196 int res; 197 198 res = read(bpf, &rbuf, MAXPKT); 199 if (res > 0) { 200 #if 0 201 int i; 202 fprintf(stderr, "got packet, len=%d\n", rbuf.h.bh_caplen); 203 if (rbuf.h.bh_caplen < rbuf.h.bh_datalen) 204 printf("(truncated)\n"); 205 for (i = 0; i < 20; i++) 206 fprintf(stderr, "%02x ", rbuf.buf[rbuf.h.bh_hdrlen + i]); 207 fprintf(stderr, "\n"); 208 #endif 209 if (rbuf.h.bh_caplen > maxlen) 210 return 0; 211 memcpy(pkt, &rbuf.buf[rbuf.h.bh_hdrlen], rbuf.h.bh_caplen); 212 return rbuf.h.bh_caplen; 213 } 214 215 return 0; 216 } 217