1 /* 2 * Copyright 2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Philippe Houdoin, <phoudoin %at% haiku-os %dot% org> 7 */ 8 9 10 #include <net_buffer.h> 11 #include <net_device.h> 12 #include <net_stack.h> 13 14 #include <KernelExport.h> 15 16 #include <errno.h> 17 #include <net/if.h> 18 #include <net/if_dl.h> 19 #include <net/if_media.h> 20 #include <net/if_types.h> 21 #include <new> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <termios.h> 26 27 #define HDLC_CONTROL_ESCAPE 0x7d 28 #define HDLC_FLAG_SEQUENCE 0x7e 29 #define HDLC_ALL_STATIONS 0xff 30 #define HDLC_UI 0x03 31 32 33 enum dialup_state { 34 DOWN, 35 DIALING, 36 UP, 37 HANGINGUP 38 }; 39 40 struct dialup_device : net_device { 41 int fd; 42 dialup_state state; 43 char* init_string; 44 char* dial_string; 45 char* escape_string; 46 bigtime_t escape_silence; 47 char* hangup_string; 48 }; 49 50 net_buffer_module_info* gBufferModule; 51 static net_stack_module_info* sStackModule; 52 53 // #pragma mark - 54 55 56 status_t 57 dialup_init(const char* name, net_device** _device) 58 { 59 // make sure this is a device in /dev/ports 60 if (strncmp(name, "/dev/ports/", 11)) 61 return B_BAD_VALUE; 62 63 status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule); 64 if (status < B_OK) 65 return status; 66 67 dialup_device* device = new (std::nothrow) dialup_device; 68 if (device == NULL) { 69 put_module(NET_BUFFER_MODULE_NAME); 70 return B_NO_MEMORY; 71 } 72 73 memset(device, 0, sizeof(dialup_device)); 74 75 strcpy(device->name, name); 76 device->flags = IFF_POINTOPOINT; 77 device->type = IFT_PPP; 78 device->mtu = 1502; 79 device->media = 0; 80 device->header_length = 8; // HDLC_HEADER_LENGTH; 81 device->fd = -1; 82 device->state = DOWN; 83 84 // default AT strings 85 device->init_string = strdup("ATZ"); 86 device->dial_string = strdup("ATDT"); 87 device->escape_string = strdup("+++"); 88 device->escape_silence = 1000000; 89 device->hangup_string = strdup("ATH0"); 90 91 *_device = device; 92 return B_OK; 93 } 94 95 96 status_t 97 dialup_uninit(net_device* _device) 98 { 99 dialup_device* device = (dialup_device*)_device; 100 free(device->init_string); 101 free(device->dial_string); 102 free(device->escape_string); 103 free(device->hangup_string); 104 105 delete device; 106 107 put_module(NET_BUFFER_MODULE_NAME); 108 109 return B_OK; 110 } 111 112 113 status_t 114 dialup_up(net_device* _device) 115 { 116 dialup_device* device = (dialup_device*)_device; 117 118 device->fd = open(device->name, O_RDWR); 119 if (device->fd < 0) 120 return errno; 121 122 // init port 123 struct termios options; 124 if (ioctl(device->fd, TCGETA, &options, sizeof(options)) < 0) 125 goto err; 126 127 // adjust options 128 options.c_cflag &= ~CBAUD; 129 options.c_cflag |= B115200; // TODO: make this configurable too... 130 options.c_cflag |= (CLOCAL | CREAD); 131 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 132 options.c_oflag &= ~OPOST; 133 options.c_cc[VMIN] = 0; 134 options.c_cc[VTIME] = 10; 135 136 // set new options 137 if(ioctl(device->fd, TCSETA, &options) < 0) 138 goto err; 139 140 // TODO: init modem & start dialing phase 141 device->state = DIALING; 142 return B_OK; 143 144 err: 145 close(device->fd); 146 device->fd = -1; 147 return errno; 148 } 149 150 151 void 152 dialup_down(net_device* _device) 153 { 154 dialup_device* device = (dialup_device*)_device; 155 156 // TODO: hangup if needed 157 if (device->flags & IFF_LINK) { 158 snooze(device->escape_silence); 159 if (write(device->fd, device->escape_string, 160 strlen(device->escape_string)) > 0) { 161 snooze(device->escape_silence); 162 // TODO: send hangup string and check for OK ack 163 } 164 device->flags &= ~IFF_LINK; 165 } 166 167 close(device->fd); 168 device->fd = -1; 169 } 170 171 172 status_t 173 dialup_control(net_device* _device, int32 op, void* argument, 174 size_t length) 175 { 176 dialup_device* device = (dialup_device*)_device; 177 return ioctl(device->fd, op, argument, length); 178 } 179 180 181 status_t 182 dialup_send_data(net_device* _device, net_buffer* buffer) 183 { 184 return B_NOT_SUPPORTED; 185 } 186 187 188 status_t 189 dialup_receive_data(net_device* _device, net_buffer** _buffer) 190 { 191 dialup_device* device = (dialup_device*)_device; 192 193 if (device->fd == -1) 194 return B_FILE_ERROR; 195 196 return ENOBUFS; 197 } 198 199 200 status_t 201 dialup_set_mtu(net_device* _device, size_t mtu) 202 { 203 dialup_device* device = (dialup_device*)_device; 204 205 device->mtu = mtu; 206 return B_OK; 207 } 208 209 210 status_t 211 dialup_set_promiscuous(net_device* _device, bool promiscuous) 212 { 213 return B_NOT_SUPPORTED; 214 } 215 216 217 status_t 218 dialup_set_media(net_device* device, uint32 media) 219 { 220 return B_NOT_SUPPORTED; 221 } 222 223 224 status_t 225 dialup_add_multicast(struct net_device* _device, const sockaddr* _address) 226 { 227 return B_NOT_SUPPORTED; 228 } 229 230 231 status_t 232 dialup_remove_multicast(struct net_device* _device, const sockaddr* _address) 233 { 234 return B_NOT_SUPPORTED; 235 } 236 237 238 static status_t 239 dialup_std_ops(int32 op, ...) 240 { 241 switch (op) { 242 case B_MODULE_INIT: 243 { 244 status_t status = get_module(NET_STACK_MODULE_NAME, 245 (module_info**)&sStackModule); 246 if (status < B_OK) 247 return status; 248 249 return B_OK; 250 } 251 252 case B_MODULE_UNINIT: 253 { 254 put_module(NET_STACK_MODULE_NAME); 255 return B_OK; 256 } 257 258 default: 259 return B_ERROR; 260 } 261 } 262 263 264 net_device_module_info sDialUpModule = { 265 { 266 "network/devices/dialup/v1", 267 0, 268 dialup_std_ops 269 }, 270 dialup_init, 271 dialup_uninit, 272 dialup_up, 273 dialup_down, 274 dialup_control, 275 dialup_send_data, 276 dialup_receive_data, 277 dialup_set_mtu, 278 dialup_set_promiscuous, 279 dialup_set_media, 280 dialup_add_multicast, 281 dialup_remove_multicast, 282 }; 283 284 module_info* modules[] = { 285 (module_info*)&sDialUpModule, 286 NULL 287 }; 288