1 /* 2 * Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! \class KPPPInterface 7 \brief The kernel representation of a PPP interface. 8 9 This class is never created by the programmer directly. Instead, the PPP manager 10 kernel module should be used. \n 11 KPPPInterface handles all interface-specific commands from userspace and it 12 passes packets to their receiver or sends them to the device. Additionally, 13 it contains the KPPPLCP object with represents the LCP protocol and the 14 KPPPStateMachine object which represents the state machine. \n 15 All PPP modules are loaded from here. \n 16 Protocols and encapsulators should be added to this class. LCP-specific extensions 17 belong to the KPPPLCP object. \n 18 Multilink support is distributed between KPPPInterface and KPPPStateMachine. 19 */ 20 21 // cstdio must be included before KPPPModule.h/KPPPManager.h because 22 // dprintf is defined twice with different return values, once with 23 // void (KernelExport.h) and once with int (stdio.h). 24 #include <cstdio> 25 #include <cstring> 26 #include <core_funcs.h> 27 28 // now our headers... 29 #include <KPPPInterface.h> 30 31 // our other classes 32 #include <PPPControl.h> 33 #include <KPPPDevice.h> 34 #include <KPPPLCPExtension.h> 35 #include <KPPPOptionHandler.h> 36 #include <KPPPModule.h> 37 #include <KPPPManager.h> 38 #include <KPPPUtils.h> 39 40 // general helper classes not only belonging to us 41 #include <LockerHelper.h> 42 43 // tools only for us :) 44 #include "settings_tools.h" 45 46 // internal modules 47 #include "_KPPPMRUHandler.h" 48 #include "_KPPPAuthenticationHandler.h" 49 #include "_KPPPPFCHandler.h" 50 51 52 // TODO: 53 // - implement timers with support for setting next event instead of receiving timer 54 // events periodically 55 // - add missing settings support (ConnectRetryDelay, etc.) 56 57 58 //! Private structure needed for reconnecting. 59 typedef struct reconnect_info { 60 KPPPInterface *interface; 61 thread_id *thread; 62 uint32 delay; 63 } reconnect_info; 64 65 status_t reconnect_thread(void *data); 66 67 // other functions 68 status_t interface_deleter_thread(void *data); 69 70 71 /*! \brief Creates a new interface. 72 73 \param name Name of the PPP interface description file. 74 \param entry The PPP manager passes an internal structure to the constructor. 75 \param ID The interface's ID. 76 \param settings (Optional): If no name is given you must pass the settings here. 77 \param parent (Optional): Interface's parent (only used for multilink interfaces). 78 */ 79 KPPPInterface::KPPPInterface(const char *name, ppp_interface_entry *entry, 80 ppp_interface_id ID, const driver_settings *settings, KPPPInterface *parent) 81 : 82 KPPPLayer(name, PPP_INTERFACE_LEVEL, 2), 83 fID(ID), 84 fSettings(NULL), 85 fIfnet(NULL), 86 fReconnectThread(-1), 87 fConnectAttempt(1), 88 fConnectRetriesLimit(0), 89 fManager(NULL), 90 fConnectedSince(0), 91 fIdleSince(0), 92 fMRU(1500), 93 fInterfaceMTU(1498), 94 fHeaderLength(2), 95 fParent(NULL), 96 fIsMultilink(false), 97 fAutoReconnect(false), 98 fConnectOnDemand(false), 99 fAskBeforeConnecting(false), 100 fMode(PPP_CLIENT_MODE), 101 fLocalPFCState(PPP_PFC_DISABLED), 102 fPeerPFCState(PPP_PFC_DISABLED), 103 fPFCOptions(0), 104 fDevice(NULL), 105 fFirstProtocol(NULL), 106 fStateMachine(*this), 107 fLCP(*this), 108 fReportManager(StateMachine().fLock), 109 fLock(StateMachine().fLock), 110 fDeleteCounter(0) 111 { 112 entry->interface = this; 113 114 if (name) { 115 // load settings from description file 116 char path[B_PATH_NAME_LENGTH]; 117 sprintf(path, "ptpnet/%s", name); 118 // XXX: TODO: change base path to "/etc/ptpnet" 119 120 void *handle = load_driver_settings(path); 121 if (!handle) { 122 fInitStatus = B_ERROR; 123 return; 124 } 125 126 fSettings = dup_driver_settings(get_driver_settings(handle)); 127 unload_driver_settings(handle); 128 } else 129 fSettings = dup_driver_settings(settings); 130 // use the given settings 131 132 if (!fSettings) { 133 fInitStatus = B_ERROR; 134 return; 135 } 136 137 // add internal modules 138 // LCP 139 if (!AddProtocol(&LCP())) { 140 fInitStatus = B_ERROR; 141 return; 142 } 143 // MRU 144 _KPPPMRUHandler *mruHandler = 145 new _KPPPMRUHandler(*this); 146 if (!LCP().AddOptionHandler(mruHandler) || mruHandler->InitCheck() != B_OK) { 147 ERROR("KPPPInterface: Could not add MRU handler!\n"); 148 delete mruHandler; 149 } 150 // authentication 151 _KPPPAuthenticationHandler *authenticationHandler = 152 new _KPPPAuthenticationHandler(*this); 153 if (!LCP().AddOptionHandler(authenticationHandler) 154 || authenticationHandler->InitCheck() != B_OK) { 155 ERROR("KPPPInterface: Could not add authentication handler!\n"); 156 delete authenticationHandler; 157 } 158 // PFC 159 _KPPPPFCHandler *pfcHandler = 160 new _KPPPPFCHandler(fLocalPFCState, fPeerPFCState, *this); 161 if (!LCP().AddOptionHandler(pfcHandler) || pfcHandler->InitCheck() != B_OK) { 162 ERROR("KPPPInterface: Could not add PFC handler!\n"); 163 delete pfcHandler; 164 } 165 166 // set up connect delays 167 fConnectRetryDelay = 3000; 168 // 3s delay between each new attempt to reconnect 169 fReconnectDelay = 1000; 170 // 1s delay between lost connection and reconnect 171 172 if (get_module(PPP_INTERFACE_MODULE_NAME, (module_info**) &fManager) != B_OK) 173 ERROR("KPPPInterface: Manager module not found!\n"); 174 175 // are we a multilink subinterface? 176 if (parent && parent->IsMultilink()) { 177 fParent = parent; 178 fParent->AddChild(this); 179 fIsMultilink = true; 180 } 181 182 RegisterInterface(); 183 184 if (!fSettings) { 185 fInitStatus = B_ERROR; 186 return; 187 } 188 189 const char *value; 190 191 // get login 192 value = get_settings_value(PPP_USERNAME_KEY, fSettings); 193 fUsername = value ? strdup(value) : strdup(""); 194 value = get_settings_value(PPP_PASSWORD_KEY, fSettings); 195 fPassword = value ? strdup(value) : strdup(""); 196 197 // get DisonnectAfterIdleSince settings 198 value = get_settings_value(PPP_DISONNECT_AFTER_IDLE_SINCE_KEY, fSettings); 199 if (!value) 200 fDisconnectAfterIdleSince = 0; 201 else 202 fDisconnectAfterIdleSince = atoi(value) * 1000; 203 204 if (fDisconnectAfterIdleSince < 0) 205 fDisconnectAfterIdleSince = 0; 206 207 // get mode settings 208 value = get_settings_value(PPP_MODE_KEY, fSettings); 209 if (value && !strcasecmp(value, PPP_SERVER_MODE_VALUE)) 210 fMode = PPP_SERVER_MODE; 211 else 212 fMode = PPP_CLIENT_MODE; 213 // we are a client by default 214 215 SetAutoReconnect( 216 get_boolean_value( 217 get_settings_value(PPP_AUTO_RECONNECT_KEY, fSettings), 218 false) 219 ); 220 // auto reconnect is disabled by default 221 222 fAskBeforeConnecting = get_boolean_value( 223 get_settings_value(PPP_ASK_BEFORE_CONNECTING_KEY, fSettings), false); 224 225 // load all protocols and the device 226 if (!LoadModules(fSettings, 0, fSettings->parameter_count)) { 227 ERROR("KPPPInterface: Error loading modules!\n"); 228 fInitStatus = B_ERROR; 229 } 230 } 231 232 233 //! Destructor: Disconnects and marks interface for deletion. 234 KPPPInterface::~KPPPInterface() 235 { 236 TRACE("KPPPInterface: Destructor\n"); 237 238 // tell protocols to uninit (remove routes, etc.) 239 KPPPProtocol *protocol = FirstProtocol(); 240 for (; protocol; protocol = protocol->NextProtocol()) 241 protocol->Uninit(); 242 243 // make sure we are not accessible by any thread before we continue 244 UnregisterInterface(); 245 246 if (fManager) 247 fManager->RemoveInterface(ID()); 248 249 // Call Down() until we get a lock on an interface that is down. 250 // This lock is not released until we are actually deleted. 251 while (true) { 252 Down(); 253 fLock.Lock(); 254 if (State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE) 255 break; 256 fLock.Unlock(); 257 } 258 259 Report(PPP_DESTRUCTION_REPORT, 0, &fID, sizeof(ppp_interface_id)); 260 // tell all listeners that we are being destroyed 261 262 int32 tmp; 263 send_data_with_timeout(fReconnectThread, 0, NULL, 0, 200); 264 // tell thread that we are being destroyed (200ms timeout) 265 wait_for_thread(fReconnectThread, &tmp); 266 267 while (CountChildren()) 268 delete ChildAt(0); 269 270 delete Device(); 271 272 while (FirstProtocol()) { 273 if (FirstProtocol() == &LCP()) 274 fFirstProtocol = fFirstProtocol->NextProtocol(); 275 else 276 delete FirstProtocol(); 277 // destructor removes protocol from list 278 } 279 280 for (int32 index = 0; index < fModules.CountItems(); index++) { 281 put_module(fModules.ItemAt(index)); 282 delete[] fModules.ItemAt(index); 283 } 284 285 free_driver_settings(fSettings); 286 287 if (Parent()) 288 Parent()->RemoveChild(this); 289 290 if (fManager) 291 put_module(PPP_INTERFACE_MODULE_NAME); 292 } 293 294 295 //! Marks interface for deletion. 296 void 297 KPPPInterface::Delete() 298 { 299 LockerHelper locker(fLock); 300 301 if (fDeleteCounter > 0) 302 return; 303 // only one thread should delete us! 304 305 fDeleteCounter = 1; 306 307 fManager->DeleteInterface(ID()); 308 // This will mark us for deletion. 309 // Any subsequent calls to delete_interface() will do nothing. 310 } 311 312 313 //! Returns if interface was initialized correctly. 314 status_t 315 KPPPInterface::InitCheck() const 316 { 317 if (fInitStatus != B_OK) 318 return fInitStatus; 319 320 if (!fSettings || !fManager) 321 return B_ERROR; 322 323 // sub-interfaces should have a device 324 if (IsMultilink()) { 325 if (Parent() && !fDevice) 326 return B_ERROR; 327 } else if (!fDevice) 328 return B_ERROR; 329 330 return B_OK; 331 } 332 333 334 //! The username used for authentication. 335 const char* 336 KPPPInterface::Username() const 337 { 338 // this data is not available before we authenticate 339 if (Phase() < PPP_AUTHENTICATION_PHASE) 340 return NULL; 341 342 return fUsername; 343 } 344 345 346 //! The password used for authentication. 347 const char* 348 KPPPInterface::Password() const 349 { 350 // this data is not available before we authenticate 351 if (Phase() < PPP_AUTHENTICATION_PHASE) 352 return NULL; 353 354 return fPassword; 355 } 356 357 358 //! Sets interface MRU. 359 bool 360 KPPPInterface::SetMRU(uint32 MRU) 361 { 362 TRACE("KPPPInterface: SetMRU(%ld)\n", MRU); 363 364 if (Device() && MRU > Device()->MTU() - 2) 365 return false; 366 367 LockerHelper locker(fLock); 368 369 fMRU = MRU; 370 371 CalculateInterfaceMTU(); 372 373 return true; 374 } 375 376 377 //! Returns number of bytes spent for protocol overhead. Includes device overhead. 378 uint32 379 KPPPInterface::PacketOverhead() const 380 { 381 uint32 overhead = fHeaderLength + 2; 382 383 if (Device()) 384 overhead += Device()->Overhead(); 385 386 return overhead; 387 } 388 389 390 /*! \brief Allows accessing additional functions. 391 392 This is normally called by userland apps to get information about the interface. 393 394 \param op The op value (see ppp_control_ops enum). 395 \param data (Optional): Additional data may be needed for this op. 396 \param length Length of data. 397 398 \return 399 - \c B_OK: \c Control() was successful. 400 - \c B_ERROR: Either \a length is too small or data is NULL. 401 - \c B_NOT_ALLOWED: Operation not allowed (at this point in time). 402 - \c B_BAD_INDEX: Wrong index (e.g.: when accessing interface submodules). 403 - \c B_BAD_VALUE: Unknown op. 404 - Return value of submodule (when controlling one). 405 */ 406 status_t 407 KPPPInterface::Control(uint32 op, void *data, size_t length) 408 { 409 switch (op) { 410 case PPPC_GET_INTERFACE_INFO: 411 { 412 if (length < sizeof(ppp_interface_info_t) || !data) 413 return B_ERROR; 414 415 ppp_interface_info *info = (ppp_interface_info*) data; 416 memset(info, 0, sizeof(ppp_interface_info_t)); 417 if (Name()) 418 strncpy(info->name, Name(), PPP_HANDLER_NAME_LENGTH_LIMIT); 419 if (Ifnet()) 420 info->if_unit = Ifnet()->if_unit; 421 else 422 info->if_unit = -1; 423 info->mode = Mode(); 424 info->state = State(); 425 info->phase = Phase(); 426 info->localAuthenticationStatus = 427 StateMachine().LocalAuthenticationStatus(); 428 info->peerAuthenticationStatus = 429 StateMachine().PeerAuthenticationStatus(); 430 info->localPFCState = LocalPFCState(); 431 info->peerPFCState = PeerPFCState(); 432 info->pfcOptions = PFCOptions(); 433 info->protocolsCount = CountProtocols(); 434 info->optionHandlersCount = LCP().CountOptionHandlers(); 435 info->LCPExtensionsCount = 0; 436 info->childrenCount = CountChildren(); 437 info->MRU = MRU(); 438 info->interfaceMTU = InterfaceMTU(); 439 info->connectAttempt = fConnectAttempt; 440 info->connectRetriesLimit = fConnectRetriesLimit; 441 info->connectRetryDelay = ConnectRetryDelay(); 442 info->reconnectDelay = ReconnectDelay(); 443 info->connectedSince = ConnectedSince(); 444 info->idleSince = IdleSince(); 445 info->disconnectAfterIdleSince = DisconnectAfterIdleSince(); 446 info->doesConnectOnDemand = DoesConnectOnDemand(); 447 info->doesAutoReconnect = DoesAutoReconnect(); 448 info->hasDevice = Device(); 449 info->isMultilink = IsMultilink(); 450 info->hasParent = Parent(); 451 break; 452 } 453 454 case PPPC_SET_USERNAME: 455 { 456 if (!data) 457 return B_ERROR; 458 459 LockerHelper locker(fLock); 460 // login information can only be changed before we authenticate 461 if (Phase() >= PPP_AUTHENTICATION_PHASE) 462 return B_NOT_ALLOWED; 463 464 free(fUsername); 465 fUsername = data ? strdup((const char*) data) : strdup(""); 466 break; 467 } 468 469 case PPPC_SET_PASSWORD: 470 { 471 if (!data) 472 return B_ERROR; 473 474 LockerHelper locker(fLock); 475 // login information can only be changed before we authenticate 476 if (Phase() >= PPP_AUTHENTICATION_PHASE) 477 return B_NOT_ALLOWED; 478 479 free(fPassword); 480 fPassword = data ? strdup((const char*) data) : strdup(""); 481 break; 482 } 483 484 case PPPC_SET_ASK_BEFORE_CONNECTING: 485 if (length < sizeof(uint32) || !data) 486 return B_ERROR; 487 488 SetAskBeforeConnecting(*((uint32*)data)); 489 break; 490 491 case PPPC_SET_MRU: 492 if (length < sizeof(uint32) || !data) 493 return B_ERROR; 494 495 SetMRU(*((uint32*)data)); 496 break; 497 498 case PPPC_SET_CONNECT_ON_DEMAND: 499 if (length < sizeof(uint32) || !data) 500 return B_ERROR; 501 502 SetConnectOnDemand(*((uint32*)data)); 503 break; 504 505 case PPPC_SET_AUTO_RECONNECT: 506 if (length < sizeof(uint32) || !data) 507 return B_ERROR; 508 509 SetAutoReconnect(*((uint32*)data)); 510 break; 511 512 case PPPC_HAS_INTERFACE_SETTINGS: 513 if (length < sizeof(driver_settings) || !data) 514 return B_ERROR; 515 516 if (equal_interface_settings(Settings(), (driver_settings*) data)) 517 return B_OK; 518 else 519 return B_ERROR; 520 break; 521 522 case PPPC_ENABLE_REPORTS: 523 { 524 if (length < sizeof(ppp_report_request) || !data) 525 return B_ERROR; 526 527 LockerHelper locker(fLock); 528 ppp_report_request *request = (ppp_report_request*) data; 529 // first, we send an initial state report 530 if (request->type == PPP_CONNECTION_REPORT) { 531 ppp_report_packet report; 532 report.type = PPP_CONNECTION_REPORT; 533 report.code = StateMachine().fLastConnectionReportCode; 534 report.length = sizeof(fID); 535 KPPPReportManager::SendReport(request->thread, &report); 536 if (request->flags & PPP_REMOVE_AFTER_REPORT) 537 return B_OK; 538 } 539 ReportManager().EnableReports(request->type, request->thread, 540 request->flags); 541 break; 542 } 543 544 case PPPC_DISABLE_REPORTS: 545 { 546 if (length < sizeof(ppp_report_request) || !data) 547 return B_ERROR; 548 549 ppp_report_request *request = (ppp_report_request*) data; 550 ReportManager().DisableReports(request->type, request->thread); 551 break; 552 } 553 554 case PPPC_GET_STATISTICS: 555 if (length < sizeof(ppp_statistics) || !data) 556 return B_ERROR; 557 558 memcpy(data, &fStatistics, sizeof(ppp_statistics)); 559 break; 560 561 case PPPC_CONTROL_DEVICE: 562 { 563 if (length < sizeof(ppp_control_info) || !data) 564 return B_ERROR; 565 566 ppp_control_info *control = (ppp_control_info*) data; 567 if (control->index != 0 || !Device()) 568 return B_BAD_INDEX; 569 570 return Device()->Control(control->op, control->data, control->length); 571 } 572 573 case PPPC_CONTROL_PROTOCOL: 574 { 575 if (length < sizeof(ppp_control_info) || !data) 576 return B_ERROR; 577 578 ppp_control_info *control = (ppp_control_info*) data; 579 KPPPProtocol *protocol = ProtocolAt(control->index); 580 if (!protocol) 581 return B_BAD_INDEX; 582 583 return protocol->Control(control->op, control->data, control->length); 584 } 585 586 case PPPC_CONTROL_OPTION_HANDLER: 587 { 588 if (length < sizeof(ppp_control_info) || !data) 589 return B_ERROR; 590 591 ppp_control_info *control = (ppp_control_info*) data; 592 KPPPOptionHandler *optionHandler = LCP().OptionHandlerAt(control->index); 593 if (!optionHandler) 594 return B_BAD_INDEX; 595 596 return optionHandler->Control(control->op, control->data, 597 control->length); 598 } 599 600 case PPPC_CONTROL_LCP_EXTENSION: 601 { 602 if (length < sizeof(ppp_control_info) || !data) 603 return B_ERROR; 604 605 ppp_control_info *control = (ppp_control_info*) data; 606 KPPPLCPExtension *lcpExtension = LCP().LCPExtensionAt(control->index); 607 if (!lcpExtension) 608 return B_BAD_INDEX; 609 610 return lcpExtension->Control(control->op, control->data, 611 control->length); 612 } 613 614 case PPPC_CONTROL_CHILD: 615 { 616 if (length < sizeof(ppp_control_info) || !data) 617 return B_ERROR; 618 619 ppp_control_info *control = (ppp_control_info*) data; 620 KPPPInterface *child = ChildAt(control->index); 621 if (!child) 622 return B_BAD_INDEX; 623 624 return child->Control(control->op, control->data, control->length); 625 } 626 627 default: 628 return B_BAD_VALUE; 629 } 630 631 return B_OK; 632 } 633 634 635 /*! \brief Sets a new device for this interface. 636 637 A device add-on should call this method to register itself. The best place to do 638 this is in your module's \c add_to() function. 639 640 \param device The device object. 641 642 \return \c true if successful or \c false otherwise. 643 644 \sa KPPPDevice 645 \sa kppp_module_info 646 */ 647 bool 648 KPPPInterface::SetDevice(KPPPDevice *device) 649 { 650 TRACE("KPPPInterface: SetDevice(%p)\n", device); 651 652 if (device && &device->Interface() != this) 653 return false; 654 655 if (IsMultilink() && !Parent()) 656 return false; 657 // main interfaces do not have devices 658 659 LockerHelper locker(fLock); 660 661 if (Phase() != PPP_DOWN_PHASE) 662 return false; 663 // a running connection may not change 664 665 if (fDevice && (IsUp() || fDevice->IsUp())) 666 Down(); 667 668 fDevice = device; 669 SetNext(device); 670 671 if (fDevice) 672 fMRU = fDevice->MTU() - 2; 673 674 CalculateInterfaceMTU(); 675 CalculateBaudRate(); 676 677 return true; 678 } 679 680 681 /*! \brief Adds a new protocol to this interface. 682 683 NOTE: You can only add protocols in \c PPP_DOWN_PHASE. \n 684 A protocol add-on should call this method to register itself. The best place to do 685 this is in your module's \c add_to() function. 686 687 \param protocol The protocol object. 688 689 \return \c true if successful or \c false otherwise. 690 691 \sa KPPPProtocol 692 \sa kppp_module_info 693 */ 694 bool 695 KPPPInterface::AddProtocol(KPPPProtocol *protocol) 696 { 697 // Find insert position after the last protocol 698 // with the same level. 699 700 TRACE("KPPPInterface: AddProtocol(%X)\n", 701 protocol ? protocol->ProtocolNumber() : 0); 702 703 if (!protocol || &protocol->Interface() != this 704 || protocol->Level() == PPP_INTERFACE_LEVEL) 705 return false; 706 707 LockerHelper locker(fLock); 708 709 if (Phase() != PPP_DOWN_PHASE) 710 return false; 711 // a running connection may not change 712 713 KPPPProtocol *current = fFirstProtocol, *previous = NULL; 714 715 while (current) { 716 if (current->Level() < protocol->Level()) 717 break; 718 719 previous = current; 720 current = current->NextProtocol(); 721 } 722 723 if (!current) { 724 if (!previous) 725 fFirstProtocol = protocol; 726 else 727 previous->SetNextProtocol(protocol); 728 729 // set up the last protocol in the chain 730 protocol->SetNextProtocol(NULL); 731 // this also sets next to NULL 732 protocol->SetNext(this); 733 // we need to set us as the next layer for the last protocol 734 } else { 735 protocol->SetNextProtocol(current); 736 737 if (!previous) 738 fFirstProtocol = protocol; 739 else 740 previous->SetNextProtocol(protocol); 741 } 742 743 if (protocol->Level() < PPP_PROTOCOL_LEVEL) 744 CalculateInterfaceMTU(); 745 746 if (IsUp() || Phase() >= protocol->ActivationPhase()) 747 protocol->Up(); 748 749 return true; 750 } 751 752 753 /*! \brief Removes a protocol from this interface. 754 755 NOTE: You can only remove protocols in \c PPP_DOWN_PHASE. \n 756 A protocol add-on should call this method to remove itself explicitly from the 757 interface. \n 758 Normally, this method is called in KPPPProtocol's destructor. Do not call it 759 yourself unless you know what you do! 760 761 \param protocol The protocol object. 762 763 \return \c true if successful or \c false otherwise. 764 */ 765 bool 766 KPPPInterface::RemoveProtocol(KPPPProtocol *protocol) 767 { 768 TRACE("KPPPInterface: RemoveProtocol(%X)\n", 769 protocol ? protocol->ProtocolNumber() : 0); 770 771 LockerHelper locker(fLock); 772 773 if (Phase() != PPP_DOWN_PHASE) 774 return false; 775 // a running connection may not change 776 777 KPPPProtocol *current = fFirstProtocol, *previous = NULL; 778 779 while (current) { 780 if (current == protocol) { 781 if (!protocol->IsDown()) 782 protocol->Down(); 783 784 if (previous) { 785 previous->SetNextProtocol(current->NextProtocol()); 786 787 // set us as next layer if needed 788 if (!previous->Next()) 789 previous->SetNext(this); 790 } else 791 fFirstProtocol = current->NextProtocol(); 792 793 current->SetNextProtocol(NULL); 794 795 CalculateInterfaceMTU(); 796 797 return true; 798 } 799 800 previous = current; 801 current = current->NextProtocol(); 802 } 803 804 return false; 805 } 806 807 808 //! Returns the number of protocol modules belonging to this interface. 809 int32 810 KPPPInterface::CountProtocols() const 811 { 812 LockerHelper locker(fLock); 813 814 KPPPProtocol *protocol = FirstProtocol(); 815 816 int32 count = 0; 817 for (; protocol; protocol = protocol->NextProtocol()) 818 ++count; 819 820 return count; 821 } 822 823 824 //! Returns the protocol at the given \a index or \c NULL if it could not be found. 825 KPPPProtocol* 826 KPPPInterface::ProtocolAt(int32 index) const 827 { 828 LockerHelper locker(fLock); 829 830 KPPPProtocol *protocol = FirstProtocol(); 831 832 int32 currentIndex = 0; 833 for (; protocol && currentIndex != index; protocol = protocol->NextProtocol()) 834 ++currentIndex; 835 836 return protocol; 837 } 838 839 840 /*! \brief Returns the protocol object responsible for a given protocol number. 841 842 \param protocolNumber The protocol number that the object should handle. 843 \param start (Optional): Start with this protocol. Can be used for iteration. 844 845 \return Either the object that was found or \c NULL. 846 */ 847 KPPPProtocol* 848 KPPPInterface::ProtocolFor(uint16 protocolNumber, KPPPProtocol *start) const 849 { 850 TRACE("KPPPInterface: ProtocolFor(%X)\n", protocolNumber); 851 852 LockerHelper locker(fLock); 853 854 KPPPProtocol *current = start ? start : FirstProtocol(); 855 856 for (; current; current = current->NextProtocol()) { 857 if (current->ProtocolNumber() == protocolNumber 858 || (current->Flags() & PPP_INCLUDES_NCP 859 && (current->ProtocolNumber() & 0x7FFF) 860 == (protocolNumber & 0x7FFF))) 861 return current; 862 } 863 864 return NULL; 865 } 866 867 868 //! Adds a new child interface (used for multilink interfaces). 869 bool 870 KPPPInterface::AddChild(KPPPInterface *child) 871 { 872 TRACE("KPPPInterface: AddChild(%lX)\n", child ? child->ID() : 0); 873 874 if (!child) 875 return false; 876 877 LockerHelper locker(fLock); 878 879 if (fChildren.HasItem(child) || !fChildren.AddItem(child)) 880 return false; 881 882 child->SetParent(this); 883 884 return true; 885 } 886 887 888 //! Removes a new child from this interface (used for multilink interfaces). 889 bool 890 KPPPInterface::RemoveChild(KPPPInterface *child) 891 { 892 TRACE("KPPPInterface: RemoveChild(%lX)\n", child ? child->ID() : 0); 893 894 LockerHelper locker(fLock); 895 896 if (!fChildren.RemoveItem(child)) 897 return false; 898 899 child->SetParent(NULL); 900 901 // parents cannot exist without their children 902 if (CountChildren() == 0 && fManager && Ifnet()) 903 Delete(); 904 905 return true; 906 } 907 908 909 //! Returns the child interface at the given \a index (used for multilink interfaces). 910 KPPPInterface* 911 KPPPInterface::ChildAt(int32 index) const 912 { 913 TRACE("KPPPInterface: ChildAt(%ld)\n", index); 914 915 LockerHelper locker(fLock); 916 917 KPPPInterface *child = fChildren.ItemAt(index); 918 919 if (child == fChildren.GetDefaultItem()) 920 return NULL; 921 922 return child; 923 } 924 925 926 //! Enables or disables the auto-reconnect feture. 927 void 928 KPPPInterface::SetAutoReconnect(bool autoReconnect) 929 { 930 TRACE("KPPPInterface: SetAutoReconnect(%s)\n", autoReconnect ? "true" : "false"); 931 932 if (Mode() != PPP_CLIENT_MODE) 933 return; 934 935 fAutoReconnect = autoReconnect; 936 } 937 938 939 //! Enables or disables the connect-on-demand feature. 940 void 941 KPPPInterface::SetConnectOnDemand(bool connectOnDemand) 942 { 943 // All protocols must check if ConnectOnDemand was enabled/disabled after this 944 // interface went down. This is the only situation where a change is relevant. 945 946 TRACE("KPPPInterface: SetConnectOnDemand(%s)\n", connectOnDemand ? "true" : "false"); 947 948 LockerHelper locker(fLock); 949 950 // Only clients support ConnectOnDemand. 951 if (Mode() != PPP_CLIENT_MODE) { 952 TRACE("KPPPInterface::SetConnectOnDemand(): Wrong mode!\n"); 953 fConnectOnDemand = false; 954 return; 955 } else if (DoesConnectOnDemand() == connectOnDemand) 956 return; 957 958 fConnectOnDemand = connectOnDemand; 959 960 // Do not allow changes when we are disconnected (only main interfaces). 961 // This would make no sense because 962 // - enabling: this cannot happen because hidden interfaces are deleted if they 963 // could not establish a connection (the user cannot access hidden interfaces) 964 // - disabling: the interface disappears as seen from the user, so we delete it 965 if (!Parent() && State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE) { 966 if (!connectOnDemand) 967 Delete(); 968 // as long as the protocols were not configured we can just delete us 969 970 return; 971 } 972 973 // check if we need to set/unset flags 974 if (connectOnDemand) { 975 if (Ifnet()) 976 Ifnet()->if_flags |= IFF_UP; 977 } else if (!connectOnDemand && Phase() < PPP_ESTABLISHED_PHASE) { 978 if (Ifnet()) 979 Ifnet()->if_flags &= ~IFF_UP; 980 } 981 } 982 983 984 //! Sets whether the user is asked before establishing the connection. 985 void 986 KPPPInterface::SetAskBeforeConnecting(bool ask) 987 { 988 LockerHelper locker(fLock); 989 990 bool old = fAskBeforeConnecting; 991 fAskBeforeConnecting = ask; 992 993 if (old && fAskBeforeConnecting == false && State() == PPP_STARTING_STATE 994 && Phase() == PPP_DOWN_PHASE) { 995 locker.UnlockNow(); 996 StateMachine().ContinueOpenEvent(); 997 } 998 } 999 1000 1001 //! Sets Protocol-Field-Compression options. 1002 bool 1003 KPPPInterface::SetPFCOptions(uint8 pfcOptions) 1004 { 1005 TRACE("KPPPInterface: SetPFCOptions(0x%X)\n", pfcOptions); 1006 1007 LockerHelper locker(fLock); 1008 1009 if (PFCOptions() & PPP_FREEZE_PFC_OPTIONS) 1010 return false; 1011 1012 fPFCOptions = pfcOptions; 1013 return true; 1014 } 1015 1016 1017 /*! \brief Brings this interface up. 1018 1019 \c Down() overrides all \c Up() requests. \n 1020 This method runs an asynchronous process (it returns immediately). 1021 1022 \return \c false on error. 1023 */ 1024 bool 1025 KPPPInterface::Up() 1026 { 1027 TRACE("KPPPInterface: Up()\n"); 1028 1029 if (InitCheck() != B_OK || Phase() == PPP_TERMINATION_PHASE) 1030 return false; 1031 1032 if (IsUp()) 1033 return true; 1034 1035 LockerHelper locker(fLock); 1036 StateMachine().OpenEvent(); 1037 1038 return true; 1039 } 1040 1041 1042 /*! \brief Brings this interface down. 1043 1044 \c Down() overrides all \c Up() requests. \n 1045 This method runs an asynchronous process (it returns immediately). 1046 1047 \return \c false on error. 1048 */ 1049 bool 1050 KPPPInterface::Down() 1051 { 1052 TRACE("KPPPInterface: Down()\n"); 1053 1054 if (InitCheck() != B_OK) 1055 return false; 1056 else if (State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE) 1057 return true; 1058 1059 send_data_with_timeout(fReconnectThread, 0, NULL, 0, 200); 1060 // tell the reconnect thread to abort its attempt (if it's still waiting) 1061 1062 LockerHelper locker(fLock); 1063 StateMachine().CloseEvent(); 1064 1065 return true; 1066 } 1067 1068 1069 //! Waits for connection establishment. Returns true if successful. 1070 bool 1071 KPPPInterface::WaitForConnection() 1072 { 1073 TRACE("KPPPInterface: WaitForConnection()\n"); 1074 1075 if (InitCheck() != B_OK) 1076 return false; 1077 1078 ReportManager().EnableReports(PPP_CONNECTION_REPORT, find_thread(NULL)); 1079 1080 ppp_report_packet report; 1081 thread_id sender; 1082 bool successful = false; 1083 while (true) { 1084 if (receive_data(&sender, &report, sizeof(report)) != PPP_REPORT_CODE) 1085 continue; 1086 1087 if (report.type == PPP_DESTRUCTION_REPORT) 1088 break; 1089 else if (report.type != PPP_CONNECTION_REPORT) 1090 continue; 1091 1092 if (report.code == PPP_REPORT_UP_SUCCESSFUL) { 1093 successful = true; 1094 break; 1095 } else if (report.code == PPP_REPORT_DOWN_SUCCESSFUL) 1096 break; 1097 } 1098 1099 ReportManager().DisableReports(PPP_CONNECTION_REPORT, find_thread(NULL)); 1100 return successful; 1101 } 1102 1103 1104 /*! \brief Loads modules specified in the settings structure. 1105 1106 \param settings PPP interface description file format settings. 1107 \param start Index of driver_parameter to start with. 1108 \param count Number of driver_parameters to look at. 1109 1110 \return \c true if successful or \c false otherwise. 1111 */ 1112 bool 1113 KPPPInterface::LoadModules(driver_settings *settings, int32 start, int32 count) 1114 { 1115 TRACE("KPPPInterface: LoadModules()\n"); 1116 1117 if (Phase() != PPP_DOWN_PHASE) 1118 return false; 1119 // a running connection may not change 1120 1121 ppp_module_key_type type; 1122 // which type key was used for loading this module? 1123 1124 const char *name = NULL; 1125 1126 // multilink handling 1127 for (int32 index = start; 1128 index < settings->parameter_count && index < (start + count); index++) { 1129 if (!strcasecmp(settings->parameters[index].name, PPP_MULTILINK_KEY) 1130 && settings->parameters[index].value_count > 0) { 1131 if (!LoadModule(settings->parameters[index].values[0], 1132 &settings->parameters[index], PPP_MULTILINK_KEY_TYPE)) 1133 return false; 1134 break; 1135 } 1136 } 1137 1138 // are we a multilink main interface? 1139 if (IsMultilink() && !Parent()) { 1140 // main interfaces only load the multilink module 1141 // and create a child using their settings 1142 fManager->CreateInterface(settings, ID()); 1143 return true; 1144 } 1145 1146 for (int32 index = start; 1147 index < settings->parameter_count && index < start + count; index++) { 1148 type = PPP_UNDEFINED_KEY_TYPE; 1149 1150 name = settings->parameters[index].name; 1151 1152 if (!strcasecmp(name, PPP_LOAD_MODULE_KEY)) 1153 type = PPP_LOAD_MODULE_KEY_TYPE; 1154 else if (!strcasecmp(name, PPP_DEVICE_KEY)) 1155 type = PPP_DEVICE_KEY_TYPE; 1156 else if (!strcasecmp(name, PPP_PROTOCOL_KEY)) 1157 type = PPP_PROTOCOL_KEY_TYPE; 1158 else if (!strcasecmp(name, PPP_AUTHENTICATOR_KEY)) 1159 type = PPP_AUTHENTICATOR_KEY_TYPE; 1160 1161 if (type >= 0) 1162 for (int32 value_id = 0; value_id < settings->parameters[index].value_count; 1163 value_id++) 1164 if (!LoadModule(settings->parameters[index].values[value_id], 1165 &settings->parameters[index], type)) 1166 return false; 1167 } 1168 1169 return true; 1170 } 1171 1172 1173 /*! \brief Loads a specific module. 1174 1175 \param name Name of the module. 1176 \param parameter Module settings. 1177 \param type Type of module. 1178 1179 \return \c true if successful or \c false otherwise. 1180 */ 1181 bool 1182 KPPPInterface::LoadModule(const char *name, driver_parameter *parameter, 1183 ppp_module_key_type type) 1184 { 1185 TRACE("KPPPInterface: LoadModule(%s)\n", name ? name : "XXX: NO NAME"); 1186 1187 if (Phase() != PPP_DOWN_PHASE) 1188 return false; 1189 // a running connection may not change 1190 1191 if (!name || strlen(name) > B_FILE_NAME_LENGTH) 1192 return false; 1193 1194 char *moduleName = new char[B_PATH_NAME_LENGTH]; 1195 1196 sprintf(moduleName, "%s/%s", PPP_MODULES_PATH, name); 1197 1198 ppp_module_info *module; 1199 if (get_module(moduleName, (module_info**) &module) != B_OK) { 1200 delete[] moduleName; 1201 return false; 1202 } 1203 1204 // add the module to the list of loaded modules 1205 // for putting them on our destruction 1206 fModules.AddItem(moduleName); 1207 1208 return module->add_to(Parent() ? *Parent() : *this, this, parameter, type); 1209 } 1210 1211 1212 //! Always returns true. 1213 bool 1214 KPPPInterface::IsAllowedToSend() const 1215 { 1216 return true; 1217 } 1218 1219 1220 /*! \brief Sends a packet to the device. 1221 1222 This brings the interface up if connect-on-demand is enabled and we are not 1223 connected. \n 1224 PFC encoding is handled here. \n 1225 NOTE: In order to prevent interface destruction while sending you must either 1226 hold a refcount for this interface or make sure it is locked. 1227 1228 \param packet The packet. 1229 \param protocolNumber The packet's protocol number. 1230 1231 \return 1232 - \c B_OK: Sending was successful. 1233 - \c B_ERROR: Some error occured. 1234 */ 1235 status_t 1236 KPPPInterface::Send(struct mbuf *packet, uint16 protocolNumber) 1237 { 1238 TRACE("KPPPInterface: Send(0x%X)\n", protocolNumber); 1239 1240 if (!packet) 1241 return B_ERROR; 1242 1243 // we must pass the basic tests like: 1244 // do we have a device? 1245 // did we load all modules? 1246 if (InitCheck() != B_OK) { 1247 m_freem(packet); 1248 return B_ERROR; 1249 } 1250 1251 // go up if ConnectOnDemand is enabled and we are disconnected 1252 // TODO: our new netstack will simplify ConnectOnDemand handling, so 1253 // we do not have to handle it here 1254 if ((protocolNumber != PPP_LCP_PROTOCOL && DoesConnectOnDemand() 1255 && (Phase() == PPP_DOWN_PHASE 1256 || Phase() == PPP_ESTABLISHMENT_PHASE) 1257 && !Up()) || !WaitForConnection()) { 1258 m_freem(packet); 1259 return B_ERROR; 1260 } 1261 1262 // find the protocol handler for the current protocol number 1263 KPPPProtocol *protocol = ProtocolFor(protocolNumber); 1264 while (protocol && !protocol->IsEnabled()) 1265 protocol = protocol->NextProtocol() ? 1266 ProtocolFor(protocolNumber, protocol->NextProtocol()) : NULL; 1267 1268 #if DEBUG 1269 if (!protocol) 1270 TRACE("KPPPInterface::Send(): no protocol found!\n"); 1271 else if (!Device()->IsUp()) 1272 TRACE("KPPPInterface::Send(): device is not up!\n"); 1273 else if (!protocol->IsEnabled()) 1274 TRACE("KPPPInterface::Send(): protocol not enabled!\n"); 1275 else if (!IsProtocolAllowed(*protocol)) 1276 TRACE("KPPPInterface::Send(): protocol not allowed to send!\n"); 1277 else 1278 TRACE("KPPPInterface::Send(): protocol allowed\n"); 1279 #endif 1280 1281 // make sure that protocol is allowed to send and everything is up 1282 if (!Device()->IsUp() || !protocol || !protocol->IsEnabled() 1283 || !IsProtocolAllowed(*protocol)) { 1284 ERROR("KPPPInterface::Send(): cannot send!\n"); 1285 m_freem(packet); 1286 return B_ERROR; 1287 } 1288 1289 // encode in ppp frame and consider using PFC 1290 if (UseLocalPFC() && protocolNumber & 0xFF00 == 0) { 1291 M_PREPEND(packet, 1); 1292 1293 if (packet == NULL) 1294 return B_ERROR; 1295 1296 uint8 *header = mtod(packet, uint8*); 1297 *header = protocolNumber & 0xFF; 1298 } else { 1299 M_PREPEND(packet, 2); 1300 1301 if (packet == NULL) 1302 return B_ERROR; 1303 1304 // set protocol (the only header field) 1305 protocolNumber = htons(protocolNumber); 1306 uint16 *header = mtod(packet, uint16*); 1307 *header = protocolNumber; 1308 } 1309 1310 // pass to device if we're either not a multilink interface or a child interface 1311 if (!IsMultilink() || Parent()) { 1312 // check if packet is too big for device 1313 uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len : 1314 packet->m_len; 1315 1316 if (length > MRU()) { 1317 m_freem(packet); 1318 return B_ERROR; 1319 } 1320 1321 atomic_add64(&fStatistics.bytesSent, length); 1322 atomic_add64(&fStatistics.packetsSent, 1); 1323 return SendToNext(packet, 0); 1324 // this is normally the device, but there can be something inbetween 1325 } else { 1326 // the multilink protocol should have sent it to some child interface 1327 m_freem(packet); 1328 return B_ERROR; 1329 } 1330 } 1331 1332 1333 /*! \brief Receives a packet. 1334 1335 Encapsulation protocols may use this method to pass encapsulated packets to the 1336 PPP interface. Packets will be handled as if they were raw packets that came 1337 directly from the device via \c ReceiveFromDevice(). \n 1338 If no handler could be found in this interface the parent's \c Receive() method 1339 is called. 1340 1341 \param packet The packet. 1342 \param protocolNumber The packet's protocol number. 1343 1344 \return 1345 - \c B_OK: Receiving was successful. 1346 - \c B_ERROR: Some error occured. 1347 - \c PPP_REJECTED: No protocol handler could be found for this packet. 1348 - \c PPP_DISCARDED: The protocol handler(s) did not handle this packet. 1349 */ 1350 status_t 1351 KPPPInterface::Receive(struct mbuf *packet, uint16 protocolNumber) 1352 { 1353 TRACE("KPPPInterface: Receive(0x%X)\n", protocolNumber); 1354 1355 if (!packet) 1356 return B_ERROR; 1357 1358 LockerHelper locker(fLock); 1359 1360 int32 result = PPP_REJECTED; 1361 // assume we have no handler 1362 1363 // Set our interface as the receiver. 1364 // The real netstack protocols (IP, IPX, etc.) might get confused if our 1365 // interface is a main interface and at the same time not registered 1366 // because then there is no receiver interface. 1367 // PPP NCPs should be aware of that! 1368 if (packet->m_flags & M_PKTHDR && Ifnet() != NULL) 1369 packet->m_pkthdr.rcvif = Ifnet(); 1370 1371 // Find handler and let it parse the packet. 1372 // The handler does need not be up because if we are a server 1373 // the handler might be upped by this packet. 1374 // If authenticating we only allow authentication phase protocols. 1375 KPPPProtocol *protocol = ProtocolFor(protocolNumber); 1376 for (; protocol; 1377 protocol = protocol->NextProtocol() ? 1378 ProtocolFor(protocolNumber, protocol->NextProtocol()) : NULL) { 1379 TRACE("KPPPInterface::Receive(): trying protocol\n"); 1380 1381 if (!protocol->IsEnabled() || !IsProtocolAllowed(*protocol)) 1382 continue; 1383 // skip handler if disabled or not allowed 1384 1385 result = protocol->Receive(packet, protocolNumber); 1386 if (result == PPP_UNHANDLED) 1387 continue; 1388 1389 return result; 1390 } 1391 1392 TRACE("KPPPInterface::Receive(): trying parent\n"); 1393 1394 // maybe the parent interface can handle the packet 1395 if (Parent()) 1396 return Parent()->Receive(packet, protocolNumber); 1397 1398 if (result == PPP_UNHANDLED) { 1399 m_freem(packet); 1400 return PPP_DISCARDED; 1401 } else { 1402 StateMachine().RUCEvent(packet, protocolNumber); 1403 return PPP_REJECTED; 1404 } 1405 } 1406 1407 1408 /*! \brief Receives a base PPP packet from the device. 1409 1410 KPPPDevice should call this method when it receives a packet. \n 1411 PFC decoding is handled here. 1412 1413 \param packet The packet. 1414 1415 \return 1416 - \c B_OK: Receiving was successful. 1417 - \c B_ERROR: Some error occured. 1418 - \c PPP_REJECTED: No protocol handler could be found for this packet. 1419 - \c PPP_DISCARDED: The protocol handler(s) did not handle this packet. 1420 */ 1421 status_t 1422 KPPPInterface::ReceiveFromDevice(struct mbuf *packet) 1423 { 1424 TRACE("KPPPInterface: ReceiveFromDevice()\n"); 1425 1426 if (!packet) 1427 return B_ERROR; 1428 1429 if (InitCheck() != B_OK) { 1430 m_freem(packet); 1431 return B_ERROR; 1432 } 1433 1434 uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len : 1435 packet->m_len; 1436 1437 // decode ppp frame and recognize PFC 1438 uint16 protocolNumber = *mtod(packet, uint8*); 1439 if (protocolNumber & 1) { 1440 m_adj(packet, 1); 1441 } else { 1442 protocolNumber = ntohs(*mtod(packet, uint16*)); 1443 m_adj(packet, 2); 1444 } 1445 1446 atomic_add64(&fStatistics.bytesReceived, length); 1447 atomic_add64(&fStatistics.packetsReceived, 1); 1448 return Receive(packet, protocolNumber); 1449 } 1450 1451 1452 //! Manages Pulse() calls for all add-ons and hanldes idle-disconnection. 1453 void 1454 KPPPInterface::Pulse() 1455 { 1456 LockerHelper locker(fLock); 1457 1458 if (Device()) 1459 Device()->Pulse(); 1460 1461 KPPPProtocol *protocol = FirstProtocol(); 1462 for (; protocol; protocol = protocol->NextProtocol()) 1463 protocol->Pulse(); 1464 1465 uint32 currentTime = real_time_clock(); 1466 if (fUpdateIdleSince) { 1467 fIdleSince = currentTime; 1468 fUpdateIdleSince = false; 1469 } 1470 1471 // check our idle time and disconnect if needed 1472 if (fDisconnectAfterIdleSince > 0 && fIdleSince != 0 1473 && fIdleSince - currentTime >= fDisconnectAfterIdleSince) 1474 StateMachine().CloseEvent(); 1475 } 1476 1477 1478 //! Registers an ifnet structure for this interface. 1479 bool 1480 KPPPInterface::RegisterInterface() 1481 { 1482 TRACE("KPPPInterface: RegisterInterface()\n"); 1483 1484 if (fIfnet) 1485 return true; 1486 // we are already registered 1487 1488 LockerHelper locker(fLock); 1489 1490 // only MainInterfaces get an ifnet 1491 if (IsMultilink() && Parent() && Parent()->RegisterInterface()) 1492 return true; 1493 1494 if (!fManager) 1495 return false; 1496 1497 fIfnet = fManager->RegisterInterface(ID()); 1498 1499 if (!fIfnet) 1500 return false; 1501 1502 if (DoesConnectOnDemand()) 1503 fIfnet->if_flags |= IFF_UP; 1504 1505 CalculateInterfaceMTU(); 1506 CalculateBaudRate(); 1507 1508 return true; 1509 } 1510 1511 1512 //! Unregisters this interface's ifnet structure. 1513 bool 1514 KPPPInterface::UnregisterInterface() 1515 { 1516 TRACE("KPPPInterface: UnregisterInterface()\n"); 1517 1518 if (!fIfnet) 1519 return true; 1520 // we are already unregistered 1521 1522 LockerHelper locker(fLock); 1523 1524 // only MainInterfaces get an ifnet 1525 if (IsMultilink() && Parent()) 1526 return true; 1527 1528 if (!fManager) 1529 return false; 1530 1531 fManager->UnregisterInterface(ID()); 1532 // this will delete fIfnet, so do not access it anymore! 1533 fIfnet = NULL; 1534 1535 return true; 1536 } 1537 1538 1539 //! Called by KPPPManager: manager routes stack ioctls to the corresponding interface. 1540 status_t 1541 KPPPInterface::StackControl(uint32 op, void *data) 1542 { 1543 TRACE("KPPPInterface: StackControl(0x%lX)\n", op); 1544 1545 switch (op) { 1546 default: 1547 return StackControlEachHandler(op, data); 1548 } 1549 1550 return B_OK; 1551 } 1552 1553 1554 //! Utility class used by ControlEachHandler(). 1555 template<class T> 1556 class CallStackControl { 1557 public: 1558 inline CallStackControl(uint32 op, void *data, status_t& result) 1559 : fOp(op), fData(data), fResult(result) {} 1560 inline void operator() (T *item) 1561 { 1562 if (!item || !item->IsEnabled()) 1563 return; 1564 status_t tmp = item->StackControl(fOp, fData); 1565 if (tmp == B_OK && fResult == B_BAD_VALUE) 1566 fResult = B_OK; 1567 else if (tmp != B_BAD_VALUE) 1568 fResult = tmp; 1569 } 1570 private: 1571 uint32 fOp; 1572 void *fData; 1573 status_t& fResult; 1574 }; 1575 1576 /*! \brief This calls Control() with the given parameters for each add-on. 1577 1578 \return 1579 - \c B_OK: All handlers returned B_OK. 1580 - \c B_BAD_VALUE: No handler was found. 1581 - Any other value: Error code which was returned by the last failing handler. 1582 */ 1583 status_t 1584 KPPPInterface::StackControlEachHandler(uint32 op, void *data) 1585 { 1586 TRACE("KPPPInterface: StackControlEachHandler(0x%lX)\n", op); 1587 1588 status_t result = B_BAD_VALUE, tmp; 1589 1590 LockerHelper locker(fLock); 1591 1592 KPPPProtocol *protocol = FirstProtocol(); 1593 for (; protocol; protocol = protocol->NextProtocol()) { 1594 tmp = protocol->StackControl(op, data); 1595 if (tmp == B_OK && result == B_BAD_VALUE) 1596 result = B_OK; 1597 else if (tmp != B_BAD_VALUE) 1598 result = tmp; 1599 } 1600 1601 ForEachItem(LCP().fLCPExtensions, 1602 CallStackControl<KPPPLCPExtension>(op, data, result)); 1603 ForEachItem(LCP().fOptionHandlers, 1604 CallStackControl<KPPPOptionHandler>(op, data, result)); 1605 1606 return result; 1607 } 1608 1609 1610 //! Recalculates the MTU from the MRU (includes encapsulation protocol overheads). 1611 void 1612 KPPPInterface::CalculateInterfaceMTU() 1613 { 1614 TRACE("KPPPInterface: CalculateInterfaceMTU()\n"); 1615 1616 LockerHelper locker(fLock); 1617 1618 fInterfaceMTU = fMRU; 1619 fHeaderLength = 2; 1620 1621 // sum all headers (the protocol field is not counted) 1622 KPPPProtocol *protocol = FirstProtocol(); 1623 for (; protocol; protocol = protocol->NextProtocol()) { 1624 if (protocol->Level() < PPP_PROTOCOL_LEVEL) 1625 fHeaderLength += protocol->Overhead(); 1626 } 1627 1628 fInterfaceMTU -= fHeaderLength; 1629 1630 if (Ifnet()) { 1631 Ifnet()->if_mtu = fInterfaceMTU; 1632 Ifnet()->if_hdrlen = fHeaderLength; 1633 } 1634 1635 if (Parent()) 1636 Parent()->CalculateInterfaceMTU(); 1637 } 1638 1639 1640 //! Recalculates the baud rate. 1641 void 1642 KPPPInterface::CalculateBaudRate() 1643 { 1644 TRACE("KPPPInterface: CalculateBaudRate()\n"); 1645 1646 LockerHelper locker(fLock); 1647 1648 if (!Ifnet()) 1649 return; 1650 1651 if (Device()) 1652 fIfnet->if_baudrate = max_c(Device()->InputTransferRate(), 1653 Device()->OutputTransferRate()); 1654 else { 1655 fIfnet->if_baudrate = 0; 1656 for (int32 index = 0; index < CountChildren(); index++) 1657 if (ChildAt(index)->Ifnet()) 1658 fIfnet->if_baudrate += ChildAt(index)->Ifnet()->if_baudrate; 1659 } 1660 } 1661 1662 1663 //! Reconnects. Waits a given delay (in miliseconds) before reconnecting. 1664 void 1665 KPPPInterface::Reconnect(uint32 delay) 1666 { 1667 TRACE("KPPPInterface: Reconnect(%ld)\n", delay); 1668 1669 LockerHelper locker(fLock); 1670 1671 if (fReconnectThread != -1) 1672 return; 1673 1674 ++fConnectAttempt; 1675 1676 // start a new thread that calls our Up() method 1677 reconnect_info info; 1678 info.interface = this; 1679 info.thread = &fReconnectThread; 1680 info.delay = delay; 1681 1682 fReconnectThread = spawn_kernel_thread(reconnect_thread, 1683 "KPPPInterface: reconnect_thread", B_NORMAL_PRIORITY, NULL); 1684 1685 resume_thread(fReconnectThread); 1686 1687 send_data(fReconnectThread, 0, &info, sizeof(reconnect_info)); 1688 } 1689 1690 1691 status_t 1692 reconnect_thread(void *data) 1693 { 1694 reconnect_info info; 1695 thread_id sender; 1696 int32 code; 1697 1698 receive_data(&sender, &info, sizeof(reconnect_info)); 1699 1700 // we try to receive data instead of snooze, so we can quit on destruction 1701 if (receive_data_with_timeout(&sender, &code, NULL, 0, info.delay) == B_OK) { 1702 *info.thread = -1; 1703 return B_OK; 1704 } 1705 1706 info.interface->Up(); 1707 *info.thread = -1; 1708 1709 return B_OK; 1710 } 1711