1 /* $NetBSD: pf-linux2.c,v 1.1 2016/06/08 01:11:49 christos Exp $ */ 2 3 /* 4 * General Purpose AppleTalk Packet Filter Interface 5 * 6 * Copyright (c) 1992-1995, The University of Melbourne. 7 * All Rights Reserved. Permission to redistribute or 8 * use any part of this software for any purpose must 9 * be obtained in writing from the copyright owner. 10 * 11 * This software is supplied "as is" without express 12 * or implied warranty. 13 * 14 * djh@munnari.OZ.AU 15 * 16 * Supports: 17 * Linux SOCK_PACKET 18 * 19 * 20 * Modified for use with the linux-mopd port by Karl Maftoum 21 * u963870@student.canberra.edu.au 22 * 23 */ 24 25 #include "port.h" 26 __RCSID("$NetBSD: pf-linux2.c,v 1.1 2016/06/08 01:11:49 christos Exp $"); 27 28 /* 29 * include header files 30 * 31 */ 32 33 #include <stdio.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <sys/types.h> 37 #include <sys/time.h> 38 #include <sys/ioctl.h> 39 #include <sys/file.h> 40 #include <sys/socket.h> 41 #include <net/if.h> 42 #include <sys/errno.h> 43 #include <linux/if_ether.h> 44 #include <netdb.h> 45 #include <ctype.h> 46 #include <string.h> 47 48 #define MOPDEF_SUPRESS_EXTERN 49 #include "mopdef.h" 50 51 /* 52 * definitions 53 * 54 */ 55 56 #define READBUFSIZ 4096 57 #define NUMRDS 32 58 59 struct RDS { 60 u_short dataLen; 61 u_char *dataPtr; 62 }; 63 64 /* 65 * variables 66 * 67 */ 68 69 struct socklist { 70 int iflen; 71 struct sockaddr sa; 72 } socklist[32]; 73 74 struct ifreq ifr; 75 extern int errno; 76 extern int promisc; 77 78 struct RDS RDS[NUMRDS]; 79 static int setup_pf(int, int, u_short); 80 81 /* 82 * Open and initialize packet filter 83 * for a particular protocol type. 84 * 85 */ 86 87 88 int 89 pfInit(char *interface, u_short protocol, int typ, int mode) 90 { 91 int s; 92 int ioarg; 93 char device[64]; 94 unsigned long if_flags; 95 96 97 { u_short prot; 98 99 prot = ((typ == TRANS_8023) ? htons(ETH_P_802_2) : htons(protocol)); 100 if ((s = socket(AF_INET, SOCK_PACKET, prot)) < 0) { 101 perror(interface); 102 return(-1); 103 } 104 if (s >= 32) { 105 close(s); 106 return(-1); 107 } 108 } 109 110 /* 111 * set filter for protocol and type (IPTalk, Phase 1/2) 112 * 113 */ 114 115 if (setup_pf(s, protocol, typ) < 0) 116 return(-1); 117 118 /* 119 * set options, bind to underlying interface 120 * 121 */ 122 123 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); 124 125 /* record socket interface name and length */ 126 strncpy(socklist[s].sa.sa_data, interface, sizeof(socklist[s].sa.sa_data)); 127 socklist[s].iflen = strlen(interface); 128 129 return(s); 130 } 131 132 /* 133 * establish protocol filter 134 * 135 */ 136 137 static int 138 setup_pf(int s, int typ, u_short prot) 139 { 140 int ioarg; 141 u_short offset; 142 return(0); 143 } 144 145 /* 146 * get the interface ethernet address 147 * 148 */ 149 150 int 151 pfEthAddr(int s, char *interface, u_char *addr) 152 { 153 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) -1); 154 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0; 155 ifr.ifr_addr.sa_family = AF_INET; 156 if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { 157 perror("SIOCGIFHWADDR"); 158 return(-1); 159 } 160 memcpy((char *)addr, ifr.ifr_hwaddr.sa_data, 6); 161 return(0); 162 } 163 164 /* 165 * add a multicast address to the interface 166 * 167 */ 168 169 int 170 pfAddMulti(int s, char *interface, u_char *addr) 171 { 172 int sock; 173 174 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) - 1); 175 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0; 176 177 ifr.ifr_addr.sa_family = AF_UNSPEC; 178 bcopy((char *)addr, ifr.ifr_addr.sa_data, 6); 179 180 /* 181 * open a socket, temporarily, to use for SIOC* ioctls 182 * 183 */ 184 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 185 perror("socket()"); 186 return(-1); 187 } 188 if (ioctl(sock, SIOCADDMULTI, (caddr_t)&ifr) < 0) { 189 perror("SIOCADDMULTI"); 190 close(sock); 191 return(-1); 192 } 193 close(sock); 194 195 return(0); 196 } 197 198 /* 199 * delete a multicast address from the interface 200 * 201 */ 202 203 int 204 pfDelMulti(int s, char *interface, u_char *addr) 205 { 206 int sock; 207 208 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) - 1); 209 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0; 210 211 ifr.ifr_addr.sa_family = AF_UNSPEC; 212 bcopy((char *)addr, ifr.ifr_addr.sa_data, 6); 213 214 /* 215 * open a socket, temporarily, to use for SIOC* ioctls 216 * 217 */ 218 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 219 perror("socket()"); 220 return(-1); 221 } 222 if (ioctl(sock, SIOCDELMULTI, (caddr_t)&ifr) < 0) { 223 perror("SIOCDELMULTI"); 224 close(sock); 225 return(-1); 226 } 227 close(sock); 228 229 return(0); 230 } 231 232 /* 233 * return 1 if ethernet interface capable of multiple opens 234 * 235 */ 236 237 int 238 eth_mopen(int phase) 239 { 240 if (phase == 2) 241 return(0); 242 return(1); 243 } 244 245 /* 246 * read a packet 247 * Read Data Structure describes packet(s) received 248 * 249 */ 250 251 252 253 254 int 255 pfRead(int fd, u_char *buf, int len) 256 { 257 int i, cc; 258 259 int fromlen; 260 struct sockaddr sa; 261 262 RDS[0].dataLen = 0; 263 fromlen = sizeof(struct sockaddr); 264 265 if ((cc = recvfrom(fd, (char *)buf, len, 0, &sa, &fromlen)) <= 0) 266 return(cc); 267 268 /* check if from right interface */ 269 for (i = socklist[fd].iflen-1; i >= 0; i--) 270 if (sa.sa_data[i] != socklist[fd].sa.sa_data[i]) 271 return(0); 272 273 RDS[0].dataLen = cc; 274 RDS[0].dataPtr = buf; 275 RDS[1].dataLen = 0; 276 277 return(cc); 278 } 279 280 /* 281 * write a packet 282 * 283 */ 284 285 int 286 pfWrite(int fd, u_char *buf, int len) 287 { 288 289 if (sendto(fd, buf, len, 0, &socklist[fd].sa, sizeof(struct sockaddr)) == len) 290 return(len); 291 292 return(-1); 293 } 294 295 /* 296 * Return information to device.c how to open device. 297 * In this case the driver can handle both Ethernet type II and 298 * IEEE 802.3 frames (SNAP) in a single pfOpen. 299 */ 300 301 int 302 pfTrans(char *interface) 303 { 304 return TRANS_ETHER+TRANS_8023; 305 } 306