1/* 2 * This is a reverse-engineered driver for mobile WiMAX (802.16e) devices 3 * based on GCT Semiconductor GDM7213 & GDM7205 chip. 4 * Copyright (���) 2010 Yaroslav Levandovsky <leyarx@gmail.com> 5 * 6 * Based on madWiMAX driver writed by Alexander Gordeev 7 * Copyright (C) 2008-2009 Alexander Gordeev <lasaine@lvk.cs.msu.su> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24#include <unistd.h> 25#include <fcntl.h> 26#include <stdlib.h> 27#include <stdio.h> 28#include <string.h> 29#include <errno.h> 30 31#include <sys/ioctl.h> 32#include <sys/socket.h> 33#include <linux/if.h> 34#include <linux/if_arp.h> 35#include <linux/if_ether.h> 36#include <linux/if_tun.h> 37 38#include "wimax.h" 39 40 41/* 42 * Allocate TUN device, returns opened fd. 43 * Stores dev name in the first arg(must be large enough). 44 */ 45static int tun_open_common0(char *dev, int istun) 46{ 47 char tunname[14]; 48 int i, fd, err; 49 50 if( *dev ) { 51 sprintf(tunname, "/dev/%s", dev); 52 return open(tunname, O_RDWR); 53 } 54 55 sprintf(tunname, "/dev/%s", istun ? "tun" : "tap"); 56 err = 0; 57 for(i=0; i < 255; i++){ 58 sprintf(tunname + 8, "%d", i); 59 /* Open device */ 60 if( (fd=open(tunname, O_RDWR)) > 0 ) { 61 strcpy(dev, tunname + 5); 62 return fd; 63 } 64 else if (errno != ENOENT) 65 err = errno; 66 else if (i) /* don't try all 256 devices */ 67 break; 68 } 69 if (err) 70 errno = err; 71 return -1; 72} 73 74#ifndef OTUNSETNOCSUM 75/* pre 2.4.6 compatibility */ 76#define OTUNSETNOCSUM (('T'<< 8) | 200) 77#define OTUNSETDEBUG (('T'<< 8) | 201) 78#define OTUNSETIFF (('T'<< 8) | 202) 79#define OTUNSETPERSIST (('T'<< 8) | 203) 80#define OTUNSETOWNER (('T'<< 8) | 204) 81#endif 82 83static int tun_open_common(char *dev, int istun) 84{ 85 struct ifreq ifr; 86 int fd; 87 88 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) 89 return tun_open_common0(dev, istun); 90 91 memset(&ifr, 0, sizeof(ifr)); 92 ifr.ifr_flags = (istun ? IFF_TUN : IFF_TAP) | IFF_NO_PI; 93 if (*dev) 94 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 95 if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) { 96 if (errno == EBADFD) { 97 /* Try old ioctl */ 98 if (ioctl(fd, OTUNSETIFF, (void *) &ifr) < 0) 99 goto failed; 100 } else 101 goto failed; 102 } 103 104 strcpy(dev, ifr.ifr_name); 105 return fd; 106 107failed: 108 close(fd); 109 return -1; 110} 111 112 113int tap_open(char *dev) { return tun_open_common(dev, 0); } 114 115int tap_close(int fd, char *dev) { return close(fd); } 116 117/* Read/write frames from TAP device */ 118int tap_write(int fd, const void *buf, int len) { return write(fd, buf, len); } 119 120int tap_read(int fd, void *buf, int len) { return read(fd, buf, len); } 121 122 123/* Like strncpy but make sure the resulting string is always 0 terminated. */ 124static char *safe_strncpy(char *dst, const char *src, int size) 125{ 126 dst[size-1] = '\0'; 127 return strncpy(dst,src,size-1); 128} 129 130/* Set interface hw adress */ 131int tap_set_hwaddr(int fd, const char *dev, unsigned char *hwaddr) 132{ 133 struct ifreq ifr; 134 135 fd = socket(PF_INET, SOCK_DGRAM, 0); 136 137 /* Fill in the structure */ 138 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 139 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 140 memcpy(&ifr.ifr_hwaddr.sa_data, hwaddr, ETH_ALEN); 141 142 /* call the IOCTL */ 143 if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) { 144 perror("SIOCSIFHWADDR"); 145 return -1; 146 } 147 148 close(fd); 149 return 0; 150} 151 152/* Set interface mtu */ 153int tap_set_mtu(int fd, const char *dev, int mtu) 154{ 155 struct ifreq ifr; 156 157 fd = socket(PF_INET, SOCK_DGRAM, 0); 158 159 /* Fill in the structure */ 160 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 161 ifr.ifr_mtu = mtu; 162 163 /* call the IOCTL */ 164 if ((ioctl(fd, SIOCSIFMTU, &ifr)) < 0) { 165 perror("SIOCSIFMTU"); 166 return -1; 167 } 168 169 close(fd); 170 return 0; 171} 172 173/* Set a certain interface flags. */ 174static int tap_set_flags(const char *dev, short flags) 175{ 176 struct ifreq ifr; 177 int fd; 178 179 fd = socket(PF_INET, SOCK_DGRAM, 0); 180 181 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 182 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { 183 fprintf(stderr, "%s: ERROR while getting interface flags: %s\n", 184 dev, strerror(errno)); 185 return (-1); 186 } 187 188 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 189 ifr.ifr_flags |= flags; 190 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { 191 perror("SIOCSIFFLAGS"); 192 return -1; 193 } 194 195 close(fd); 196 return (0); 197} 198 199/* Clear a certain interface flags. */ 200static int tap_clr_flags(const char *dev, short flags) 201{ 202 struct ifreq ifr; 203 int fd; 204 205 fd = socket(PF_INET, SOCK_DGRAM, 0); 206 207 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 208 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { 209 fprintf(stderr, "%s: ERROR while getting interface flags: %s\n", 210 dev, strerror(errno)); 211 return -1; 212 } 213 214 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 215 ifr.ifr_flags &= ~flags; 216 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { 217 perror("SIOCSIFFLAGS"); 218 return -1; 219 } 220 221 close(fd); 222 return (0); 223} 224 225/* Test if a specified flags is set *//* 226static int tap_test_flag(const char *dev, short flags) 227{ 228 struct ifreq ifr; 229 int fd; 230 231 fd = socket(PF_INET, SOCK_DGRAM, 0); 232 233 safe_strncpy(ifr.ifr_name, dev, IFNAMSIZ); 234 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { 235 fprintf(stderr, "%s: ERROR while testing interface flags: %s\n", 236 dev, strerror(errno)); 237 return -1; 238 } 239 240 close(fd); 241 return (ifr.ifr_flags & flags); 242}*/ 243 244int tap_bring_up(int fd, const char *dev) 245{ 246 return tap_set_flags(dev, IFF_UP); 247} 248 249int tap_bring_down(int fd, const char *dev) 250{ 251 return tap_clr_flags(dev, IFF_UP); 252} 253 254