1/* 2 * This is a reverse-engineered driver for mobile WiMAX (802.16e) devices 3 * based on Samsung CMC-730 chip. 4 * Parts of the code in this file are taken from various GPL'd software. 5 * Copyright (C) 2008-2009 Alexander Gordeev <lasaine@lvk.cs.msu.su> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22#include <unistd.h> 23#include <fcntl.h> 24#include <stdlib.h> 25#include <stdio.h> 26#include <string.h> 27#include <errno.h> 28 29#include <sys/ioctl.h> 30#include <sys/socket.h> 31#include <linux/if.h> 32#include <linux/if_arp.h> 33#include <linux/if_ether.h> 34#include <linux/if_tun.h> 35 36#include "wimax.h" 37 38 39/* 40 * Allocate TUN device, returns opened fd. 41 * Stores dev name in the first arg(must be large enough). 42 */ 43static int tun_open_common0(char *dev, int istun) 44{ 45 char tunname[14]; 46 int i, fd, err; 47 48 if( *dev ) { 49 sprintf(tunname, "/dev/%s", dev); 50 return open(tunname, O_RDWR); 51 } 52 53 sprintf(tunname, "/dev/%s", istun ? "tun" : "tap"); 54 err = 0; 55 for(i=0; i < 255; i++){ 56 sprintf(tunname + 8, "%d", i); 57 /* Open device */ 58 if( (fd=open(tunname, O_RDWR)) > 0 ) { 59 strcpy(dev, tunname + 5); 60 return fd; 61 } 62 else if (errno != ENOENT) 63 err = errno; 64 else if (i) /* don't try all 256 devices */ 65 break; 66 } 67 if (err) 68 errno = err; 69 return -1; 70} 71 72#ifndef OTUNSETNOCSUM 73/* pre 2.4.6 compatibility */ 74#define OTUNSETNOCSUM (('T'<< 8) | 200) 75#define OTUNSETDEBUG (('T'<< 8) | 201) 76#define OTUNSETIFF (('T'<< 8) | 202) 77#define OTUNSETPERSIST (('T'<< 8) | 203) 78#define OTUNSETOWNER (('T'<< 8) | 204) 79#endif 80 81static int tun_open_common(char *dev, int istun) 82{ 83 struct ifreq ifr; 84 int fd; 85 86 //if ((fd = open("/dev/net/tun", O_RDWR)) < 0) 87 if ((fd = open("/dev/tun", O_RDWR)) < 0) 88 return tun_open_common0(dev, istun); 89 90 memset(&ifr, 0, sizeof(ifr)); 91 ifr.ifr_flags = (istun ? IFF_TUN : IFF_TAP) | IFF_NO_PI; 92 if (*dev) 93 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 94 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