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 #include <sys/uio.h> 27 28 29 #define HDLC_FLAG_SEQUENCE 0x7e 30 #define HDLC_CONTROL_ESCAPE 0x7d 31 32 #define HDLC_ALL_STATIONS 0xff 33 #define HDLC_UI 0x03 34 35 #define HDLC_HEADER_LENGTH 4 36 37 38 enum dialup_state { 39 DOWN, 40 DIALING, 41 UP, 42 HANGINGUP 43 }; 44 45 struct dialup_device : net_device { 46 int fd; 47 struct termios line_config; 48 dialup_state state; 49 bigtime_t last_closing_flag_sequence_time; 50 bool data_mode; 51 char init_string[64]; 52 char dial_string[64]; 53 char escape_string[8]; 54 bigtime_t escape_silence; 55 char hangup_string[16]; 56 bigtime_t tx_flag_timeout; 57 uint32 rx_accm; 58 uint32 tx_accm[8]; 59 }; 60 61 net_buffer_module_info* gBufferModule; 62 static net_stack_module_info* sStackModule; 63 64 65 // #pragma mark - 66 67 68 static status_t 69 switch_to_command_mode(dialup_device* device) 70 { 71 if (device->state != UP) 72 return B_ERROR; 73 74 if (!device->data_mode) 75 return B_OK; 76 77 snooze(device->escape_silence); 78 79 ssize_t size = write(device->fd, device->escape_string, 80 strlen(device->escape_string)); 81 if (size != (ssize_t)strlen(device->escape_string)) 82 return B_IO_ERROR; 83 84 snooze(device->escape_silence); 85 device->data_mode = false; 86 return B_OK; 87 } 88 89 90 static status_t 91 switch_to_data_mode(dialup_device* device) 92 { 93 if (device->state != UP) 94 return B_ERROR; 95 96 if (device->data_mode) 97 return B_OK; 98 99 // TODO: check if it's needed, as these days any 100 // escaped AT commands switch back to data mode automatically 101 // after their completion... 102 ssize_t size = write(device->fd, "ATO", 3); 103 if (size != 3) 104 return B_IO_ERROR; 105 106 device->data_mode = true; 107 return B_OK; 108 } 109 110 111 static status_t 112 send_command(dialup_device* device, const char* command) 113 { 114 status_t status; 115 if (device->data_mode) { 116 status = switch_to_command_mode(device); 117 if (status != B_OK) 118 return status; 119 } 120 121 ssize_t bytesWritten = write(device->fd, command, strlen(command)); 122 if (bytesWritten != (ssize_t)strlen(command)) 123 return B_IO_ERROR; 124 125 if (write(device->fd, "\r", 1) != 1) 126 return B_IO_ERROR; 127 128 return B_OK; 129 } 130 131 132 static status_t 133 read_command_reply(dialup_device* device, const char* command, 134 char* reply, int replyMaxSize) 135 { 136 if (device->data_mode) 137 return B_ERROR; 138 139 int i = 0; 140 while (i < replyMaxSize) { 141 142 ssize_t bytesRead = read(device->fd, &reply[i], 1); 143 if (bytesRead != 1) 144 return B_IO_ERROR; 145 146 if (reply[i] == '\n') { 147 // filter linefeed char 148 continue; 149 } 150 151 if (reply[i] == '\r') { 152 reply[i] = '\0'; 153 154 // is command reply or command echo (if any) ? 155 if (!strcasecmp(reply, command)) 156 return B_OK; 157 158 // It's command echo line. Just ignore it. 159 i = 0; 160 continue; 161 } 162 i++; 163 } 164 165 // replyMaxSize not large enough to store the full reply line. 166 return B_NO_MEMORY; 167 } 168 169 170 static status_t 171 hangup(dialup_device* device) 172 { 173 if (device->state != UP) 174 return B_ERROR; 175 176 // TODO: turn device's DTR down instead. Or do that too after sending command 177 char reply[8]; 178 179 if (send_command(device, device->hangup_string) != B_OK 180 || read_command_reply(device, device->hangup_string, 181 reply, sizeof(reply)) != B_OK 182 || strcmp(reply, "OK")) 183 return B_ERROR; 184 185 device->state = DOWN; 186 return B_OK; 187 } 188 189 190 // #pragma mark - 191 192 193 status_t 194 dialup_init(const char* name, net_device** _device) 195 { 196 // make sure this is a device in /dev/ports 197 if (strncmp(name, "/dev/ports/", 11)) 198 return B_BAD_VALUE; 199 200 status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule); 201 if (status < B_OK) 202 return status; 203 204 dialup_device* device = new (std::nothrow)dialup_device; 205 if (device == NULL) { 206 put_module(NET_BUFFER_MODULE_NAME); 207 return B_NO_MEMORY; 208 } 209 210 memset(device, 0, sizeof(dialup_device)); 211 212 strcpy(device->name, name); 213 device->flags = IFF_POINTOPOINT; 214 device->type = IFT_PPP; // this device handle RFC 1331 frame format only 215 device->mtu = 1500; 216 device->media = 0; 217 device->header_length = HDLC_HEADER_LENGTH; 218 219 device->fd = -1; 220 device->state = DOWN; 221 device->data_mode = false; 222 device->last_closing_flag_sequence_time = 0; 223 224 // default AT strings 225 strncpy(device->init_string, "ATZ", sizeof(device->init_string)); 226 strncpy(device->dial_string, "ATDT", sizeof(device->dial_string)); 227 strncpy(device->hangup_string, "ATH0", sizeof(device->hangup_string)); 228 229 strncpy(device->escape_string, "+++", sizeof(device->escape_string)); 230 device->escape_silence = 1000000; 231 232 device->tx_flag_timeout = 1000000; 233 234 // default rx & tx Async-Control-Character-Map 235 memset(&device->rx_accm, 0xFF, sizeof(device->rx_accm)); 236 memset(&device->tx_accm, 0xFF, sizeof(device->tx_accm)); 237 238 *_device = device; 239 return B_OK; 240 } 241 242 243 status_t 244 dialup_uninit(net_device* _device) 245 { 246 dialup_device* device = (dialup_device*)_device; 247 delete device; 248 249 put_module(NET_BUFFER_MODULE_NAME); 250 gBufferModule = NULL; 251 return B_OK; 252 } 253 254 255 status_t 256 dialup_up(net_device* _device) 257 { 258 dialup_device* device = (dialup_device*)_device; 259 260 device->fd = open(device->name, O_RDWR); 261 if (device->fd < 0) 262 return errno; 263 264 device->media = IFM_ACTIVE; 265 266 // init port 267 if (ioctl(device->fd, TCGETA, &device->line_config, 268 sizeof(device->line_config)) < 0) 269 goto err; 270 271 // adjust options 272 device->line_config.c_cflag &= ~CBAUD; 273 device->line_config.c_cflag &= CSIZE; 274 device->line_config.c_cflag &= CS8; 275 device->line_config.c_cflag |= B115200; // TODO: make this configurable too... 276 device->line_config.c_cflag |= (CLOCAL | CREAD); 277 device->line_config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 278 device->line_config.c_oflag &= ~OPOST; 279 device->line_config.c_cc[VMIN] = 0; 280 device->line_config.c_cc[VTIME] = 10; 281 282 // set new options 283 if(ioctl(device->fd, TCSETA, &device->line_config, 284 sizeof(device->line_config)) < 0) 285 goto err; 286 287 // init modem & start dialing phase 288 289 char reply[32]; 290 291 if (strlen(device->init_string) > 0) { 292 // Send modem init string 293 if (send_command(device, device->init_string) != B_OK 294 || read_command_reply(device, device->init_string, 295 reply, sizeof(reply)) != B_OK 296 || strcmp(reply, "OK")) { 297 errno = B_IO_ERROR; 298 goto err; 299 } 300 } 301 302 reply[0] = '\0'; 303 304 if (strlen(device->dial_string) > 0) { 305 // Send dialing string 306 device->state = DIALING; 307 if (send_command(device, device->dial_string) != B_OK 308 || read_command_reply(device, device->dial_string, 309 reply, sizeof(reply)) != B_OK 310 || strncmp(reply, "CONNECT", 7)) { 311 errno = B_IO_ERROR; 312 goto err; 313 } 314 } 315 316 device->state = UP; 317 device->data_mode = true; 318 319 device->media |= IFM_FULL_DUPLEX; 320 device->flags |= IFF_LINK; 321 322 device->link_quality = 1000; 323 if (strlen(reply) > 7) { 324 // get speed from "CONNECTxxxx" reply 325 device->link_speed = atoi(&reply[8]); 326 } else { 327 // Set default speed (theorically, it could be 300 bits/s even) 328 device->link_speed = 19200; 329 } 330 331 return B_OK; 332 333 err: 334 close(device->fd); 335 device->fd = -1; 336 device->media = 0; 337 338 return errno; 339 } 340 341 342 void 343 dialup_down(net_device* _device) 344 { 345 dialup_device* device = (dialup_device*)_device; 346 347 if (device->flags & IFF_LINK 348 && hangup(device) == B_OK) 349 device->flags &= ~IFF_LINK; 350 351 close(device->fd); 352 device->fd = -1; 353 device->media = 0; 354 } 355 356 357 status_t 358 dialup_control(net_device* _device, int32 op, void* argument, 359 size_t length) 360 { 361 dialup_device* device = (dialup_device*)_device; 362 return ioctl(device->fd, op, argument, length); 363 } 364 365 366 status_t 367 dialup_send_data(net_device* _device, net_buffer* buffer) 368 { 369 dialup_device* device = (dialup_device*)_device; 370 371 if (device->fd == -1) 372 return B_FILE_ERROR; 373 374 dprintf("try to send HDLC packet of %lu bytes (flags %ld):\n", buffer->size, buffer->flags); 375 376 if (buffer->size < HDLC_HEADER_LENGTH) 377 return B_BAD_VALUE; 378 379 iovec* ioVectors = NULL; 380 iovec* ioVector; 381 uint8* packet = NULL; 382 int packetSize = 0; 383 status_t status; 384 ssize_t bytesWritten; 385 386 uint32 vectorCount = gBufferModule->count_iovecs(buffer); 387 if (vectorCount < 1) { 388 status = B_BAD_VALUE; 389 goto err; 390 } 391 392 ioVectors = (iovec*)malloc(sizeof(iovec)*vectorCount); 393 if (ioVectors == NULL) { 394 status = B_NO_MEMORY; 395 goto err; 396 } 397 gBufferModule->get_iovecs(buffer, ioVectors, vectorCount); 398 399 // encode HDLC packet 400 401 // worst case: begin and end sequence flags plus each payload byte escaped 402 packet = (uint8*)malloc(2 + 2 * buffer->size); 403 if (packet == NULL) { 404 status = B_NO_MEMORY; 405 goto err; 406 } 407 408 // Mark frame start if the prior frame closing flag was sent 409 // more than a second ago. 410 // Otherwise, the prior closing flag sequence is the open flag of this 411 // frame 412 if (device->tx_flag_timeout 413 && system_time() - device->last_closing_flag_sequence_time 414 > device->tx_flag_timeout) { 415 packet[packetSize++] = HDLC_FLAG_SEQUENCE; 416 } 417 418 // encode frame data 419 ioVector = ioVectors; 420 while (vectorCount--) { 421 uint8* data = (uint8*) ioVector->iov_base; 422 for (unsigned int i = 0; i < ioVector->iov_len; i++) { 423 if (data[i] < 0x20 424 || data[i] == HDLC_FLAG_SEQUENCE 425 || data[i] == HDLC_CONTROL_ESCAPE) { 426 // needs escape 427 packet[packetSize++] = HDLC_CONTROL_ESCAPE; 428 packet[packetSize++] = data[i] ^ 0x20; 429 } else 430 packet[packetSize++] = data[i]; 431 } 432 // next io vector 433 ioVector++; 434 } 435 436 // mark frame end 437 packet[packetSize++] = HDLC_FLAG_SEQUENCE; 438 439 // send HDLC packet 440 441 bytesWritten = write(device->fd, packet, packetSize); 442 if (bytesWritten < 0) { 443 status = errno; 444 goto err; 445 } 446 device->last_closing_flag_sequence_time = system_time(); 447 448 device->stats.send.packets++; 449 device->stats.send.bytes += bytesWritten; 450 status = B_OK; 451 goto done; 452 453 err: 454 device->stats.send.errors++; 455 456 done: 457 free(ioVectors); 458 free(packet); 459 return status; 460 } 461 462 463 status_t 464 dialup_receive_data(net_device* _device, net_buffer** _buffer) 465 { 466 dialup_device* device = (dialup_device*)_device; 467 468 if (device->fd == -1) 469 return B_FILE_ERROR; 470 471 net_buffer* buffer = gBufferModule->create(256); 472 if (buffer == NULL) 473 return ENOBUFS; 474 475 status_t status; 476 ssize_t bytesRead; 477 uint8* data = NULL; 478 uint8* packet = (uint8*)malloc(2 + 2 * buffer->size); 479 if (packet == NULL) { 480 status = B_NO_MEMORY; 481 goto err; 482 } 483 484 status = gBufferModule->append_size(buffer, 485 device->mtu + HDLC_HEADER_LENGTH, (void**)&data); 486 if (status == B_OK && data == NULL) { 487 dprintf("scattered I/O is not yet supported by dialup device.\n"); 488 status = B_NOT_SUPPORTED; 489 } 490 if (status < B_OK) 491 goto err; 492 493 while (true) { 494 bytesRead = read(device->fd, data, device->mtu + HDLC_HEADER_LENGTH); 495 if (bytesRead < 0) { 496 // TODO 497 } 498 } 499 500 status = gBufferModule->trim(buffer, bytesRead); 501 if (status < B_OK) { 502 device->stats.receive.dropped++; 503 goto err; 504 } 505 506 device->stats.receive.bytes += bytesRead; 507 device->stats.receive.packets++; 508 509 *_buffer = buffer; 510 status = B_OK; 511 goto done; 512 513 err: 514 gBufferModule->free(buffer); 515 device->stats.receive.errors++; 516 517 done: 518 free(packet); 519 return status; 520 } 521 522 523 status_t 524 dialup_set_mtu(net_device* _device, size_t mtu) 525 { 526 dialup_device* device = (dialup_device*)_device; 527 528 device->mtu = mtu; 529 return B_OK; 530 } 531 532 533 status_t 534 dialup_set_promiscuous(net_device* _device, bool promiscuous) 535 { 536 return B_NOT_SUPPORTED; 537 } 538 539 540 status_t 541 dialup_set_media(net_device* device, uint32 media) 542 { 543 return B_NOT_SUPPORTED; 544 } 545 546 547 status_t 548 dialup_add_multicast(struct net_device* _device, const sockaddr* _address) 549 { 550 return B_NOT_SUPPORTED; 551 } 552 553 554 status_t 555 dialup_remove_multicast(struct net_device* _device, const sockaddr* _address) 556 { 557 return B_NOT_SUPPORTED; 558 } 559 560 561 static status_t 562 dialup_std_ops(int32 op, ...) 563 { 564 switch (op) { 565 case B_MODULE_INIT: 566 { 567 status_t status = get_module(NET_STACK_MODULE_NAME, 568 (module_info**)&sStackModule); 569 if (status < B_OK) 570 return status; 571 572 return B_OK; 573 } 574 575 case B_MODULE_UNINIT: 576 { 577 put_module(NET_STACK_MODULE_NAME); 578 return B_OK; 579 } 580 581 default: 582 return B_ERROR; 583 } 584 } 585 586 587 net_device_module_info sDialUpModule = { 588 { 589 "network/devices/dialup/v1", 590 0, 591 dialup_std_ops 592 }, 593 dialup_init, 594 dialup_uninit, 595 dialup_up, 596 dialup_down, 597 dialup_control, 598 dialup_send_data, 599 dialup_receive_data, 600 dialup_set_mtu, 601 dialup_set_promiscuous, 602 dialup_set_media, 603 dialup_add_multicast, 604 dialup_remove_multicast, 605 }; 606 607 module_info* modules[] = { 608 (module_info*)&sDialUpModule, 609 NULL 610 }; 611