1/* $NetBSD: pf.c,v 1.11 2009/10/20 00:51:13 snj Exp $ */ 2 3/* 4 * Copyright (c) 1993-95 Mats O Jansson. All rights reserved. 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is partly derived from rarpd. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34#ifndef lint 35__RCSID("$NetBSD: pf.c,v 1.11 2009/10/20 00:51:13 snj Exp $"); 36#endif 37 38#include "os.h" 39 40#include <paths.h> 41#include <sys/uio.h> 42#include <net/bpf.h> 43 44#include "mopdef.h" 45#include "pf.h" 46#include "log.h" 47 48/* 49 * Variables 50 */ 51 52extern int promisc; 53 54/* 55 * Return information to device.c how to open device. 56 * In this case the driver can handle both Ethernet type II and 57 * IEEE 802.3 frames (SNAP) in a single pfOpen. 58 */ 59 60int 61pfTrans(const char *interface) 62{ 63 return TRANS_ETHER+TRANS_8023+TRANS_AND; 64} 65 66/* 67 * Open and initialize packet filter. 68 */ 69 70int 71pfInit(const char *interface, int mode, u_short protocol, int typ) 72{ 73 int fd; 74 struct ifreq ifr; 75 u_int dlt; 76 int immediate; 77 u_int bufsize; 78 const char *device = _PATH_BPF; 79 80 static struct bpf_insn insns[] = { 81 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12), 82 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 4, 0), 83 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20), 84 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 0, 3), 85 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 14), 86 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xaaaa, 0, 1), 87 BPF_STMT(BPF_RET | BPF_K, 1520), 88 BPF_STMT(BPF_RET | BPF_K, 0), 89 }; 90 static struct bpf_program filter = { 91 sizeof insns / sizeof(insns[0]), 92 insns 93 }; 94 95 fd = open(device, mode); 96 if (fd < 0) { 97 mopLogWarn("pfInit: open %s", device); 98 return(-1); 99 } 100 101 /* Set immediate mode so packets are processed as they arrive. */ 102 immediate = 1; 103 if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) { 104 mopLogWarn("pfInit: BIOCIMMEDIATE"); 105 return(-1); 106 } 107 bufsize = 32768; 108 if (ioctl(fd, BIOCSBLEN, &bufsize) < 0) { 109 mopLogWarn("pfInit: BIOCSBLEN(%d)", bufsize); 110 } 111 (void) strncpy(ifr.ifr_name, interface, sizeof ifr.ifr_name); 112 if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) { 113 mopLogWarn("pfInit: BIOCSETIF"); 114 return(-1); 115 } 116 /* Check that the data link layer is an Ethernet; this code won't work 117 * with anything else. */ 118 if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) { 119 mopLogWarn("pfInit: BIOCGDLT"); 120 return(-1); 121 } 122 if (dlt != DLT_EN10MB) { 123 mopLogWarnX("pfInit: %s is not ethernet", device); 124 return(-1); 125 } 126 if (promisc) { 127 /* Set promiscuous mode. */ 128 if (ioctl(fd, BIOCPROMISC, (caddr_t)0) < 0) { 129 mopLogWarn("pfInit: BIOCPROMISC"); 130 return(-1); 131 } 132 } 133 /* Set filter program. */ 134 insns[1].k = protocol; 135 insns[3].k = protocol; 136 137 if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) { 138 mopLogWarn("pfInit: BIOCSETF"); 139 return(-1); 140 } 141 return(fd); 142} 143 144/* 145 * Add a Multicast address to the interface 146 */ 147 148int 149pfAddMulti(int s, const char *interface, const char *addr) 150{ 151 struct ifreq ifr; 152 int fd; 153 154 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); 155 156 ifr.ifr_addr.sa_family = AF_UNSPEC; 157 memmove(ifr.ifr_addr.sa_data, addr, 6); 158 159 /* 160 * open a socket, temporarily, to use for SIOC* ioctls 161 * 162 */ 163 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 164 mopLogWarn("pfAddMulti: socket"); 165 return(-1); 166 } 167 if (ioctl(fd, SIOCADDMULTI, (caddr_t)&ifr) < 0) { 168 mopLogWarn("pfAddMulti: SIOCADDMULTI"); 169 close(fd); 170 return(-1); 171 } 172 close(fd); 173 174 return(0); 175} 176 177/* 178 * Delete a Multicast address from the interface 179 */ 180 181int 182pfDelMulti(int s, const char *interface, const char *addr) 183{ 184 struct ifreq ifr; 185 int fd; 186 187 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); 188 189 ifr.ifr_addr.sa_family = AF_UNSPEC; 190 memmove(ifr.ifr_addr.sa_data, addr, 6); 191 192 /* 193 * open a socket, temporarily, to use for SIOC* ioctls 194 * 195 */ 196 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 197 mopLogWarn("pfDelMulti: socket"); 198 return(-1); 199 } 200 if (ioctl(fd, SIOCDELMULTI, (caddr_t)&ifr) < 0) { 201 mopLogWarn("pfAddMulti: SIOCDELMULTI"); 202 close(fd); 203 return(-1); 204 } 205 close(fd); 206 207 return(0); 208} 209 210/* 211 * read a packet 212 */ 213 214int 215pfRead(int fd, u_char *buf, int len) 216{ 217 return(read(fd, buf, len)); 218} 219 220/* 221 * write a packet 222 */ 223 224int 225pfWrite(int fd, const u_char *buf, int len, int trans) 226{ 227 228 struct iovec iov[2]; 229 230 switch (trans) { 231 case TRANS_8023: 232 iov[0].iov_base = (caddr_t)__UNCONST(buf); 233 iov[0].iov_len = 22; 234 iov[1].iov_base = (caddr_t)__UNCONST(buf+22); 235 iov[1].iov_len = len-22; 236 break; 237 default: 238 iov[0].iov_base = (caddr_t)__UNCONST(buf); 239 iov[0].iov_len = 14; 240 iov[1].iov_base = (caddr_t)__UNCONST(buf+14); 241 iov[1].iov_len = len-14; 242 break; 243 } 244 245 if (writev(fd, iov, 2) == len) 246 return(len); 247 248 return(-1); 249} 250 251