1 /* 2 * Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! \class PPPManager 7 \brief Allows controlling the PPP stack. 8 9 This class can be used for creating and deleting interfaces. It has methods for 10 requesting PPP stack report messages (e.g.: about newly created interfaces). 11 */ 12 13 #include "PPPManager.h" 14 #include "PPPInterface.h" 15 #include "MessageDriverSettingsUtils.h" 16 17 #include <Directory.h> 18 #include <File.h> 19 #include <Message.h> 20 21 #include <cstring> 22 #include <cstdlib> 23 #include <cstdio> 24 #include <cctype> 25 #include <settings_tools.h> 26 #include <unistd.h> 27 28 #include <net/if.h> 29 30 #include <net/if_media.h> 31 #include <net/if_types.h> 32 33 #include <Message.h> 34 #include <Messenger.h> 35 #include <NetworkDevice.h> 36 #include <NetworkInterface.h> 37 #include <NetworkRoster.h> 38 39 #include <NetServer.h> 40 41 //! Constructor. Does nothing special. 42 PPPManager::PPPManager() 43 { 44 // fFD = open(get_stack_driver_path(), O_RDWR); 45 int family = AF_INET; 46 47 fFD = socket(family, SOCK_DGRAM, 0); 48 49 // FileDescriptorCloser closer(socket); 50 51 // ifaliasreq request; 52 // strlcpy(request.ifra_name, name, IF_NAMESIZE); 53 // request.ifra_index = address.Index(); 54 // request.ifra_flags = address.Flags(); 55 56 // memcpy(&request.ifra_addr, &address.Address().SockAddr(), 57 // address.Address().Length()); 58 // memcpy(&request.ifra_mask, &address.Mask().SockAddr(), 59 // address.Mask().Length()); 60 // memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(), 61 // address.Broadcast().Length()); 62 63 // if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0) 64 // return errno; 65 66 } 67 68 69 //! Destructor. 70 PPPManager::~PPPManager() 71 { 72 if (fFD >= 0) 73 close(fFD); 74 } 75 76 77 //! Sets the default interface. 78 bool 79 PPPManager::SetDefaultInterface(const BString name) 80 { 81 // load current settings and replace value of "default" with <name> 82 BMessage settings; 83 if (!ReadMessageDriverSettings("ptpnet.settings", &settings)) 84 settings.MakeEmpty(); 85 86 BMessage parameter; 87 int32 index = 0; 88 if (FindMessageParameter("default", settings, ¶meter, &index)) 89 settings.RemoveData(MDSU_PARAMETERS, index); 90 91 parameter.MakeEmpty(); 92 if (name != "") { 93 parameter.AddString(MDSU_NAME, "default"); 94 parameter.AddString(MDSU_VALUES, name); 95 settings.AddMessage(MDSU_PARAMETERS, ¶meter); 96 } 97 98 BFile file(PTP_SETTINGS_PATH, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 99 if (file.InitCheck() != B_OK) 100 return false; 101 102 if (WriteMessageDriverSettings(file, settings)) 103 return true; 104 else 105 return false; 106 } 107 108 109 //! Returns the name of the default interface. 110 BString 111 PPPManager::DefaultInterface() 112 { 113 void *handle = load_driver_settings("ptpnet.settings"); 114 BString name = get_driver_parameter(handle, "default", NULL, NULL); 115 unload_driver_settings(handle); 116 return name; 117 } 118 119 120 //! Sets the given BDirectory to the settings folder. 121 bool 122 PPPManager::GetSettingsDirectory(BDirectory *settingsDirectory) 123 { 124 if (settingsDirectory) { 125 BDirectory settings(PTP_INTERFACE_SETTINGS_PATH); 126 if (settings.InitCheck() != B_OK) { 127 create_directory(PTP_INTERFACE_SETTINGS_PATH, 0750); 128 settings.SetTo(PTP_INTERFACE_SETTINGS_PATH); 129 if (settings.InitCheck() != B_OK) 130 return false; 131 } 132 133 *settingsDirectory = settings; 134 } 135 136 return true; 137 } 138 139 140 //! Returns \c B_OK if created successfully and \c B_ERROR otherwise. 141 status_t 142 PPPManager::InitCheck() const 143 { 144 if (fFD < 0) 145 return B_ERROR; 146 else 147 return B_OK; 148 } 149 150 151 /*! \brief Offers an ioctl()-like interface to all functions of the PPP stack. 152 153 \param op Any value of ppp_control_ops. 154 \param data Some ops require you to pass a structure or other data using this 155 argument. 156 \param length Make sure this value is correct (e.g.: size of structure). 157 158 If you cannot find the method that fits your needs or if you want to have direct 159 access to the complete set of PPP functions you should use this method. All 160 other methods call \c Control(), i.e., they are wrappers around this method. 161 */ 162 status_t 163 PPPManager::Control(uint32 op, void *data, size_t length) const 164 { 165 if (InitCheck() != B_OK) 166 return B_ERROR; 167 168 control_net_module_args args; 169 sprintf(args.ifr_name, "%s", "ppp1"); 170 args.name = PPP_INTERFACE_MODULE_NAME; 171 args.op = op; 172 args.data = data; 173 args.length = length; 174 175 return ioctl(fFD, NET_STACK_CONTROL_NET_MODULE, &args); 176 } 177 178 179 /*! \brief Controls a specific PPP module. 180 181 Use this method if you want to access a PPP module. The PPP stack will load it, 182 then call its \c control() function (if it is exported), and finally unload 183 the module. 184 185 \param name The module name. 186 \param op The private control op. 187 \param data Some ops require you to pass a structure or other data using this 188 argument. 189 \param length Make sure this value is correct (e.g.: size of structure). 190 191 \return 192 - \c B_NAME_NOT_FOUND: The module could not be found. 193 - \c B_ERROR: Some error occured. 194 - The module's return value. 195 196 \sa ppp_module_info::control() 197 */ 198 status_t 199 PPPManager::ControlModule(const char *name, uint32 op, void *data, 200 size_t length) const 201 { 202 if (!name) 203 return B_ERROR; 204 205 control_net_module_args args; 206 sprintf(args.ifr_name, "%s", "ppp1"); 207 args.name = name; 208 args.op = op; 209 args.data = data; 210 args.length = length; 211 return Control(PPPC_CONTROL_MODULE, &args, sizeof(args)); 212 } 213 214 215 /*! \brief Creates a nameless interface with the given settings. 216 217 Please use \c CreateInterfaceWithName() instead of this method. 218 219 \return the new interface's ID or \c PPP_UNDEFINED_INTERFACE_ID on failure. 220 */ 221 ppp_interface_id 222 PPPManager::CreateInterface(const driver_settings *settings) const 223 { 224 ppp_interface_description_info info; 225 info.u.settings = settings; 226 227 if (Control(PPPC_CREATE_INTERFACE, &info, sizeof(info)) != B_OK) 228 return PPP_UNDEFINED_INTERFACE_ID; 229 else 230 return info.interface; 231 } 232 233 234 /*! \brief Creates an interface with the given name. 235 236 If the interface already exists its ID will be returned. 237 238 \param name The PPP interface description file's name. 239 240 \return the new interface's ID or \c PPP_UNDEFINED_INTERFACE_ID on failure. 241 */ 242 ppp_interface_id 243 PPPManager::CreateInterfaceWithName(const char *name) const 244 { 245 ppp_interface_id ID = InterfaceWithName(name); 246 247 if (ID != PPP_UNDEFINED_INTERFACE_ID) 248 return ID; 249 250 BNetworkInterface interface(name); 251 if (!interface.Exists()) { 252 // the interface does not exist yet, we have to add it first 253 BNetworkRoster& roster = BNetworkRoster::Default(); 254 255 status_t status = roster.AddInterface(interface); 256 if (status != B_OK) { 257 fprintf(stderr, "PPPManager::CreateInterfaceWithName: Could not add interface: %s\n", 258 strerror(status)); 259 return PPP_UNDEFINED_INTERFACE_ID; 260 } 261 262 return InterfaceWithName(name); 263 } 264 265 return PPP_UNDEFINED_INTERFACE_ID; 266 267 // ppp_interface_description_info info; 268 // info.u.name = name; 269 // 270 // if (Control(PPPC_CREATE_INTERFACE_WITH_NAME, &info, sizeof(info)) != B_OK) 271 // return PPP_UNDEFINED_INTERFACE_ID; 272 // else 273 // return info.interface; 274 275 } 276 277 278 /*! It will remove the complete interface with all 279 of its addresses. 280 */ 281 bool 282 delete_interface(const char* name) 283 { 284 BNetworkInterface interface(name); 285 286 // Delete interface 287 BNetworkRoster& roster = BNetworkRoster::Default(); 288 289 status_t status = roster.RemoveInterface(interface); 290 if (status != B_OK) { 291 fprintf(stderr, "delete_interface: Could not delete interface %s\n", 292 name); 293 return false; 294 } 295 296 return true; 297 } 298 299 300 //! Deletes the interface with the given \a name. 301 bool 302 PPPManager::DeleteInterface(const char* name) const 303 { 304 ppp_interface_id ID = InterfaceWithName(name); 305 306 if (ID == PPP_UNDEFINED_INTERFACE_ID) 307 return false; 308 309 return delete_interface(name); 310 311 } 312 313 314 //! Deletes the interface with the given \a ID. 315 bool 316 PPPManager::DeleteInterface(ppp_interface_id ID) const 317 { 318 if (Control(PPPC_DELETE_INTERFACE, &ID, sizeof(ID)) != B_OK) 319 return false; 320 else 321 return true; 322 } 323 324 325 /*! \brief Returns all interface IDs matching a certain filter rule. 326 327 ATTENTION: You are responsible for deleting (via \c delete) the returned data!\n 328 Use this if you want to iterate over all interfaces. It returns an array of all 329 interface IDs.\c 330 You can specify a filter rule that can be either of: 331 - \c PPP_REGISTERED_INTERFACES (default): Only visible interfaces. 332 - \c PPP_UNREGISTERED_INTERFACES: Only invisible interfaces. 333 - \c PPP_ALL_INTERFACES: All (visible and invisible) interfaces. 334 335 \param count The number of IDs in the returned array is stored here. 336 \param filter The filter rule. 337 338 \return an array of interface IDs or \c NULL on failure. 339 */ 340 ppp_interface_id* 341 PPPManager::Interfaces(int32 *count, 342 ppp_interface_filter filter) const 343 { 344 int32 requestCount; 345 ppp_interface_id *interfaces; 346 347 // loop until we get all interfaces 348 while (true) { 349 requestCount = *count = CountInterfaces(filter); 350 if (*count <= 0) { 351 printf("No interface, count, first round:%ld\n", *count); 352 return NULL; 353 } 354 355 requestCount += 10; 356 // request some more interfaces in case some are added in the mean time 357 interfaces = new ppp_interface_id[requestCount]; 358 // printf("interfaces addr: %p\n, requestCount: %ld", interfaces, requestCount); 359 *count = GetInterfaces(interfaces, requestCount, filter); 360 if (*count <= 0) { 361 printf("No interface, count second round:%ld\n", *count); 362 delete interfaces; 363 return NULL; 364 } 365 366 if (*count < requestCount) 367 break; 368 369 delete interfaces; 370 } 371 372 return interfaces; 373 } 374 375 376 //! Use \c Interfaces() instead of this method. 377 int32 378 PPPManager::GetInterfaces(ppp_interface_id *interfaces, int32 count, 379 ppp_interface_filter filter) const 380 { 381 ppp_get_interfaces_info info; 382 info.interfaces = interfaces; 383 info.count = count; 384 info.filter = filter; 385 386 if (Control(PPPC_GET_INTERFACES, &info, sizeof(info)) != B_OK) 387 return -1; 388 else 389 return info.resultCount; 390 } 391 392 393 //! Returns the ID of the interface with the given settings on success. 394 ppp_interface_id 395 PPPManager::InterfaceWithSettings(const driver_settings *settings) const 396 { 397 ppp_interface_description_info info; 398 info.u.settings = settings; 399 info.interface = PPP_UNDEFINED_INTERFACE_ID; 400 401 Control(PPPC_FIND_INTERFACE_WITH_SETTINGS, &info, sizeof(info)); 402 403 return info.interface; 404 } 405 406 407 //! Returns the ID of the interface with the given if_unit (interface unit). 408 ppp_interface_id 409 PPPManager::InterfaceWithUnit(int32 if_unit) const 410 { 411 int32 count; 412 ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES); 413 414 if (!interfaces) 415 return PPP_UNDEFINED_INTERFACE_ID; 416 417 ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID; 418 PPPInterface interface; 419 ppp_interface_info_t info; 420 421 for (int32 index = 0; index < count; index++) { 422 interface.SetTo(interfaces[index]); 423 if (interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info) 424 && info.info.if_unit == if_unit) { 425 id = interface.ID(); 426 break; 427 } 428 } 429 430 delete interfaces; 431 432 return id; 433 } 434 435 436 //! Returns the ID of the interface with the given name. 437 ppp_interface_id 438 PPPManager::InterfaceWithName(const char *name) const 439 { 440 if (!name) 441 return PPP_UNDEFINED_INTERFACE_ID; 442 443 int32 count; 444 ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES); 445 446 if (!interfaces || count <= 0) { 447 printf("ERROR: Could not get ppp name:%s\n", name); 448 return PPP_UNDEFINED_INTERFACE_ID; 449 } 450 451 // printf("first ID:%ld count:%ld\n", interfaces[0], count); 452 453 ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID; 454 PPPInterface interface; 455 ppp_interface_info_t info; 456 // printf("internal info is at: %p\n", &info); 457 458 for (int32 index = 0; index < count; index++) { 459 interface.SetTo(interfaces[index]); 460 if (interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info) 461 && strlen(info.info.name) > 0 && !strcasecmp(info.info.name, name)) { 462 id = interface.ID(); 463 break; 464 } 465 } 466 467 delete interfaces; 468 469 if (id != PPP_UNDEFINED_INTERFACE_ID) 470 return id; 471 else if (!strncmp(name, "ppp", 3) && strlen(name) > 3 && isdigit(name[3])) 472 return InterfaceWithUnit(atoi(name + 3)); 473 else if (isdigit(name[0])) 474 return atoi(name); 475 else 476 return PPP_UNDEFINED_INTERFACE_ID; 477 } 478 479 480 //! Returns the number of existing interfaces or a negative value on error. 481 bool 482 is_ppp_interface(const char* name) 483 { 484 // size_t length = strlen(name); 485 // if (length < 8) 486 // putchar('\t'); 487 // else 488 // printf("\n\t"); 489 490 // get link level interface for this interface 491 492 BNetworkInterface interface(name); 493 BNetworkAddress linkAddress; 494 status_t status = interface.GetHardwareAddress(linkAddress); 495 if (status == B_OK) { 496 // const char *type = "unknown"; 497 switch (linkAddress.LinkLevelType()) { 498 case IFT_ETHER: 499 // type = "Ethernet"; 500 // printf("%s\n", type); 501 break; 502 case IFT_LOOP: 503 // type = "Local Loopback"; 504 // printf("%s\n", type); 505 break; 506 case IFT_MODEM: 507 // type = "Modem"; 508 // printf("%s\n", type); 509 break; 510 case IFT_PPP: 511 // type = "PPP"; 512 // printf("%s\n", type); 513 return true; 514 break; 515 default: 516 // printf("%s\n", type); 517 ; 518 519 } 520 521 } 522 return false; 523 } 524 525 526 //! Returns the number of ppp interfaces 527 int32 528 count_ppp_interface(void) 529 { 530 int32 count = 0; 531 532 // get a list of all ppp interfaces 533 BNetworkRoster& roster = BNetworkRoster::Default(); 534 535 BNetworkInterface interface; 536 uint32 cookie = 0; 537 538 while (roster.GetNextInterface(&cookie, interface) == B_OK) { 539 if (is_ppp_interface(interface.Name())) 540 count++; 541 } 542 543 return count; 544 } 545 546 547 //! Returns the number of existing interfaces or a negative value on error. 548 int32 549 PPPManager::CountInterfaces(ppp_interface_filter filter) const 550 { 551 // return Control(PPPC_COUNT_INTERFACES, &filter, sizeof(filter)); 552 return count_ppp_interface(); 553 } 554 555 556 /*! \brief Requests report messages from the PPP stack. 557 558 \param type The type of report. 559 \param thread Receiver thread. 560 \param flags Optional flags. 561 562 \return \c true on success \c false otherwise. 563 */ 564 bool 565 PPPManager::EnableReports(ppp_report_type type, thread_id thread, 566 int32 flags) const 567 { 568 ppp_report_request request; 569 request.type = type; 570 request.thread = thread; 571 request.flags = flags; 572 573 return Control(PPPC_ENABLE_REPORTS, &request, sizeof(request)) == B_OK; 574 } 575 576 577 /*! \brief Removes thread from list of report requestors of this interface. 578 579 \param type The type of report. 580 \param thread Receiver thread. 581 582 \return \c true on success \c false otherwise. 583 */ 584 bool 585 PPPManager::DisableReports(ppp_report_type type, thread_id thread) const 586 { 587 ppp_report_request request; 588 request.type = type; 589 request.thread = thread; 590 591 return Control(PPPC_DISABLE_REPORTS, &request, sizeof(request)) == B_OK; 592 } 593