1 /* 2 * Copyright 2003-2005, 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 <cctype> 24 #include <settings_tools.h> 25 #include <unistd.h> 26 #include "_libppputils.h" 27 28 29 //! Constructor. Does nothing special. 30 PPPManager::PPPManager() 31 { 32 fFD = open(get_stack_driver_path(), O_RDWR); 33 } 34 35 36 //! Destructor. 37 PPPManager::~PPPManager() 38 { 39 if(fFD >= 0) 40 close(fFD); 41 } 42 43 44 //! Sets the default interface. 45 bool 46 PPPManager::SetDefaultInterface(const BString name) 47 { 48 // load current settings and replace value of "default" with <name> 49 BMessage settings; 50 if(!ReadMessageDriverSettings("ptpnet.settings", &settings)) 51 settings.MakeEmpty(); 52 53 BMessage parameter; 54 int32 index = 0; 55 if(FindMessageParameter("default", settings, ¶meter, &index)) 56 settings.RemoveData(MDSU_PARAMETERS, index); 57 58 parameter.MakeEmpty(); 59 if(name != "") { 60 parameter.AddString(MDSU_NAME, "default"); 61 parameter.AddString(MDSU_VALUES, name); 62 settings.AddMessage(MDSU_PARAMETERS, ¶meter); 63 } 64 65 BFile file(PTP_SETTINGS_PATH, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 66 if(file.InitCheck() != B_OK) 67 return false; 68 69 if(WriteMessageDriverSettings(file, settings)) 70 return true; 71 else 72 return false; 73 } 74 75 76 //! Returns the name of the default interface. 77 BString 78 PPPManager::DefaultInterface() 79 { 80 void *handle = load_driver_settings("ptpnet.settings"); 81 BString name = get_driver_parameter(handle, "default", NULL, NULL); 82 unload_driver_settings(handle); 83 return name; 84 } 85 86 87 //! Sets the given BDirectory to the settings folder. 88 bool 89 PPPManager::GetSettingsDirectory(BDirectory *settingsDirectory) 90 { 91 if(settingsDirectory) { 92 BDirectory settings(PTP_INTERFACE_SETTINGS_PATH); 93 if(settings.InitCheck() != B_OK) { 94 create_directory(PTP_INTERFACE_SETTINGS_PATH, 0750); 95 settings.SetTo(PTP_INTERFACE_SETTINGS_PATH); 96 if(settings.InitCheck() != B_OK) 97 return false; 98 } 99 100 *settingsDirectory = settings; 101 } 102 103 return true; 104 } 105 106 107 //! Returns \c B_OK if created successfully and \c B_ERROR otherwise. 108 status_t 109 PPPManager::InitCheck() const 110 { 111 if(fFD < 0) 112 return B_ERROR; 113 else 114 return B_OK; 115 } 116 117 118 /*! \brief Offers an ioctl()-like interface to all functions of the PPP stack. 119 120 \param op Any value of ppp_control_ops. 121 \param data Some ops require you to pass a structure or other data using this 122 argument. 123 \param length Make sure this value is correct (e.g.: size of structure). 124 125 If you cannot find the method that fits your needs or if you want to have direct 126 access to the complete set of PPP functions you should use this method. All 127 other methods call \c Control(), i.e., they are wrappers around this method. 128 */ 129 status_t 130 PPPManager::Control(uint32 op, void *data, size_t length) const 131 { 132 if(InitCheck() != B_OK) 133 return B_ERROR; 134 135 control_net_module_args args; 136 args.name = PPP_INTERFACE_MODULE_NAME; 137 args.op = op; 138 args.data = data; 139 args.length = length; 140 141 return ioctl(fFD, NET_STACK_CONTROL_NET_MODULE, &args); 142 } 143 144 145 /*! \brief Controls a specific PPP module. 146 147 Use this method if you want to access a PPP module. The PPP stack will load it, 148 then call its \c control() function (if it is exported), and finally unload 149 the module. 150 151 \param name The module name. 152 \param op The private control op. 153 \param data Some ops require you to pass a structure or other data using this 154 argument. 155 \param length Make sure this value is correct (e.g.: size of structure). 156 157 \return 158 - \c B_NAME_NOT_FOUND: The module could not be found. 159 - \c B_ERROR: Some error occured. 160 - The module's return value. 161 162 \sa ppp_module_info::control() 163 */ 164 status_t 165 PPPManager::ControlModule(const char *name, uint32 op, void *data, 166 size_t length) const 167 { 168 if(!name) 169 return B_ERROR; 170 171 control_net_module_args args; 172 args.name = name; 173 args.op = op; 174 args.data = data; 175 args.length = length; 176 return Control(PPPC_CONTROL_MODULE, &args, sizeof(args)); 177 } 178 179 180 /*! \brief Creates a nameless interface with the given settings. 181 182 Please use \c CreateInterfaceWithName() instead of this method. 183 184 \return the new interface's ID or \c PPP_UNDEFINED_INTERFACE_ID on failure. 185 */ 186 ppp_interface_id 187 PPPManager::CreateInterface(const driver_settings *settings) const 188 { 189 ppp_interface_description_info info; 190 info.u.settings = settings; 191 192 if(Control(PPPC_CREATE_INTERFACE, &info, sizeof(info)) != B_OK) 193 return PPP_UNDEFINED_INTERFACE_ID; 194 else 195 return info.interface; 196 } 197 198 199 /*! \brief Creates an interface with the given name. 200 201 If the interface already exists its ID will be returned. 202 203 \param name The PPP interface description file's name. 204 205 \return the new interface's ID or \c PPP_UNDEFINED_INTERFACE_ID on failure. 206 */ 207 ppp_interface_id 208 PPPManager::CreateInterfaceWithName(const char *name) const 209 { 210 ppp_interface_description_info info; 211 info.u.name = name; 212 213 if(Control(PPPC_CREATE_INTERFACE_WITH_NAME, &info, sizeof(info)) != B_OK) 214 return PPP_UNDEFINED_INTERFACE_ID; 215 else 216 return info.interface; 217 } 218 219 220 //! Deletes the interface with the given \a ID. 221 bool 222 PPPManager::DeleteInterface(ppp_interface_id ID) const 223 { 224 if(Control(PPPC_DELETE_INTERFACE, &ID, sizeof(ID)) != B_OK) 225 return false; 226 else 227 return true; 228 } 229 230 231 /*! \brief Returns all interface IDs matching a certain filter rule. 232 233 ATTENTION: You are responsible for deleting (via \c delete) the returned data!\n 234 Use this if you want to iterate over all interfaces. It returns an array of all 235 interface IDs.\c 236 You can specify a filter rule that can be either of: 237 - \c PPP_REGISTERED_INTERFACES (default): Only visible interfaces. 238 - \c PPP_UNREGISTERED_INTERFACES: Only invisible interfaces. 239 - \c PPP_ALL_INTERFACES: All (visible and invisible) interfaces. 240 241 \param count The number of IDs in the returned array is stored here. 242 \param filter The filter rule. 243 244 \return an array of interface IDs or \c NULL on failure. 245 */ 246 ppp_interface_id* 247 PPPManager::Interfaces(int32 *count, 248 ppp_interface_filter filter) const 249 { 250 int32 requestCount; 251 ppp_interface_id *interfaces; 252 253 // loop until we get all interfaces 254 while(true) { 255 requestCount = *count = CountInterfaces(filter); 256 if(*count == -1) 257 return NULL; 258 259 requestCount += 10; 260 // request some more interfaces in case some are added in the mean time 261 interfaces = new ppp_interface_id[requestCount]; 262 *count = GetInterfaces(interfaces, requestCount, filter); 263 if(*count == -1) { 264 delete interfaces; 265 return NULL; 266 } 267 268 if(*count < requestCount) 269 break; 270 271 delete interfaces; 272 } 273 274 return interfaces; 275 } 276 277 278 //! Use \c Interfaces() instead of this method. 279 int32 280 PPPManager::GetInterfaces(ppp_interface_id *interfaces, int32 count, 281 ppp_interface_filter filter) const 282 { 283 ppp_get_interfaces_info info; 284 info.interfaces = interfaces; 285 info.count = count; 286 info.filter = filter; 287 288 if(Control(PPPC_GET_INTERFACES, &info, sizeof(info)) != B_OK) 289 return -1; 290 else 291 return info.resultCount; 292 } 293 294 295 //! Returns the ID of the interface with the given settings on success. 296 ppp_interface_id 297 PPPManager::InterfaceWithSettings(const driver_settings *settings) const 298 { 299 ppp_interface_description_info info; 300 info.u.settings = settings; 301 info.interface = PPP_UNDEFINED_INTERFACE_ID; 302 303 Control(PPPC_FIND_INTERFACE_WITH_SETTINGS, &info, sizeof(info)); 304 305 return info.interface; 306 } 307 308 309 //! Returns the ID of the interface with the given if_unit (interface unit). 310 ppp_interface_id 311 PPPManager::InterfaceWithUnit(int32 if_unit) const 312 { 313 int32 count; 314 ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES); 315 316 if(!interfaces) 317 return PPP_UNDEFINED_INTERFACE_ID; 318 319 ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID; 320 PPPInterface interface; 321 ppp_interface_info_t info; 322 323 for(int32 index = 0; index < count; index++) { 324 interface.SetTo(interfaces[index]); 325 if(interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info) 326 && info.info.if_unit == if_unit) { 327 id = interface.ID(); 328 break; 329 } 330 } 331 332 delete interfaces; 333 334 return id; 335 } 336 337 338 //! Returns the ID of the interface with the given name. 339 ppp_interface_id 340 PPPManager::InterfaceWithName(const char *name) const 341 { 342 if(!name) 343 return PPP_UNDEFINED_INTERFACE_ID; 344 345 int32 count; 346 ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES); 347 348 if(!interfaces) 349 return PPP_UNDEFINED_INTERFACE_ID; 350 351 ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID; 352 PPPInterface interface; 353 ppp_interface_info_t info; 354 355 for(int32 index = 0; index < count; index++) { 356 interface.SetTo(interfaces[index]); 357 if(interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info) 358 && strlen(info.info.name) > 0 && !strcasecmp(info.info.name, name)) { 359 id = interface.ID(); 360 break; 361 } 362 } 363 364 delete interfaces; 365 366 if(id != PPP_UNDEFINED_INTERFACE_ID) 367 return id; 368 else if(!strncmp(name, "ppp", 3) && strlen(name) > 3 && isdigit(name[3])) 369 return InterfaceWithUnit(atoi(name + 3)); 370 else if(isdigit(name[0])) 371 return atoi(name); 372 else 373 return PPP_UNDEFINED_INTERFACE_ID; 374 } 375 376 377 //! Returns the number of existing interfaces or a negative value on error. 378 int32 379 PPPManager::CountInterfaces(ppp_interface_filter filter) const 380 { 381 return Control(PPPC_COUNT_INTERFACES, &filter, sizeof(filter)); 382 } 383 384 385 /*! \brief Requests report messages from the PPP stack. 386 387 \param type The type of report. 388 \param thread Receiver thread. 389 \param flags Optional flags. 390 391 \return \c true on success \c false otherwise. 392 */ 393 bool 394 PPPManager::EnableReports(ppp_report_type type, thread_id thread, 395 int32 flags) const 396 { 397 ppp_report_request request; 398 request.type = type; 399 request.thread = thread; 400 request.flags = flags; 401 402 return Control(PPPC_ENABLE_REPORTS, &request, sizeof(request)) == B_OK; 403 } 404 405 406 /*! \brief Removes thread from list of report requestors of this interface. 407 408 \param type The type of report. 409 \param thread Receiver thread. 410 411 \return \c true on success \c false otherwise. 412 */ 413 bool 414 PPPManager::DisableReports(ppp_report_type type, thread_id thread) const 415 { 416 ppp_report_request request; 417 request.type = type; 418 request.thread = thread; 419 420 return Control(PPPC_DISABLE_REPORTS, &request, sizeof(request)) == B_OK; 421 } 422