xref: /haiku/src/add-ons/kernel/network/ppp/shared/libppp/PPPManager.cpp (revision ceff2b88ae26f78af0f954d8836ab50765ff7733)
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.
PPPManager()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.
~PPPManager()70 PPPManager::~PPPManager()
71 {
72 	if (fFD >= 0)
73 		close(fFD);
74 }
75 
76 
77 //!	Sets the default interface.
78 bool
SetDefaultInterface(const BString name)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, &parameter, &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, &parameter);
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
DefaultInterface()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
GetSettingsDirectory(BDirectory * settingsDirectory)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
InitCheck() const142 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
Control(uint32 op,void * data,size_t length) const163 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
ControlModule(const char * name,uint32 op,void * data,size_t length) const199 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
CreateInterface(const driver_settings * settings) const222 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
CreateInterfaceWithName(const char * name) const243 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
delete_interface(const char * name)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
DeleteInterface(const char * name) const302 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
DeleteInterface(ppp_interface_id ID) const316 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*
Interfaces(int32 * count,ppp_interface_filter filter) const341 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: %" B_PRId32 "\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 
359 		//printf("interfaces addr: %p\n, requestCount: %ld", interfaces,
360 		//	requestCount);
361 		*count = GetInterfaces(interfaces, requestCount, filter);
362 		if (*count <= 0) {
363 			printf("No interface, count second round: %" B_PRId32 "\n", *count);
364 			delete interfaces;
365 			return NULL;
366 		}
367 
368 		if (*count < requestCount)
369 			break;
370 
371 		delete interfaces;
372 	}
373 
374 	return interfaces;
375 }
376 
377 
378 //!	Use \c Interfaces() instead of this method.
379 int32
GetInterfaces(ppp_interface_id * interfaces,int32 count,ppp_interface_filter filter) const380 PPPManager::GetInterfaces(ppp_interface_id *interfaces, int32 count,
381 	ppp_interface_filter filter) const
382 {
383 	ppp_get_interfaces_info info;
384 	info.interfaces = interfaces;
385 	info.count = count;
386 	info.filter = filter;
387 
388 	if (Control(PPPC_GET_INTERFACES, &info, sizeof(info)) != B_OK)
389 		return -1;
390 	else
391 		return info.resultCount;
392 }
393 
394 
395 //!	Returns the ID of the interface with the given settings on success.
396 ppp_interface_id
InterfaceWithSettings(const driver_settings * settings) const397 PPPManager::InterfaceWithSettings(const driver_settings *settings) const
398 {
399 	ppp_interface_description_info info;
400 	info.u.settings = settings;
401 	info.interface = PPP_UNDEFINED_INTERFACE_ID;
402 
403 	Control(PPPC_FIND_INTERFACE_WITH_SETTINGS, &info, sizeof(info));
404 
405 	return info.interface;
406 }
407 
408 
409 //!	Returns the ID of the interface with the given if_unit (interface unit).
410 ppp_interface_id
InterfaceWithUnit(int32 if_unit) const411 PPPManager::InterfaceWithUnit(int32 if_unit) const
412 {
413 	int32 count;
414 	ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES);
415 
416 	if (!interfaces)
417 		return PPP_UNDEFINED_INTERFACE_ID;
418 
419 	ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID;
420 	PPPInterface interface;
421 	ppp_interface_info_t info;
422 
423 	for (int32 index = 0; index < count; index++) {
424 		interface.SetTo(interfaces[index]);
425 		if (interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info)
426 				&& info.info.if_unit == if_unit) {
427 			id = interface.ID();
428 			break;
429 		}
430 	}
431 
432 	delete interfaces;
433 
434 	return id;
435 }
436 
437 
438 //!	Returns the ID of the interface with the given name.
439 ppp_interface_id
InterfaceWithName(const char * name) const440 PPPManager::InterfaceWithName(const char *name) const
441 {
442 	if (!name)
443 		return PPP_UNDEFINED_INTERFACE_ID;
444 
445 	int32 count;
446 	ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES);
447 
448 	if (!interfaces || count <= 0) {
449 		printf("ERROR: Could not get ppp name:%s\n", name);
450 		return PPP_UNDEFINED_INTERFACE_ID;
451 	}
452 
453 	// printf("first ID:%ld count:%ld\n", interfaces[0], count);
454 
455 	ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID;
456 	PPPInterface interface;
457 	ppp_interface_info_t info;
458 	// printf("internal info is at: %p\n", &info);
459 
460 	for (int32 index = 0; index < count; index++) {
461 		interface.SetTo(interfaces[index]);
462 		if (interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info)
463 				&& strlen(info.info.name) > 0 && !strcasecmp(info.info.name, name)) {
464 			id = interface.ID();
465 			break;
466 		}
467 	}
468 
469 	delete interfaces;
470 
471 	if (id != PPP_UNDEFINED_INTERFACE_ID)
472 		return id;
473 	else if (!strncmp(name, "ppp", 3) && strlen(name) > 3 && isdigit(name[3]))
474 		return InterfaceWithUnit(atoi(name + 3));
475 	else if (isdigit(name[0]))
476 		return atoi(name);
477 	else
478 		return PPP_UNDEFINED_INTERFACE_ID;
479 }
480 
481 
482 //!	Returns the number of existing interfaces or a negative value on error.
483 bool
is_ppp_interface(const char * name)484 is_ppp_interface(const char* name)
485 {
486 	// size_t length = strlen(name);
487 	// if (length < 8)
488 	//	putchar('\t');
489 	// else
490 	//	printf("\n\t");
491 
492 	// get link level interface for this interface
493 
494 	BNetworkInterface interface(name);
495 	BNetworkAddress linkAddress;
496 	status_t status = interface.GetHardwareAddress(linkAddress);
497 	if (status == B_OK) {
498 		// const char *type = "unknown";
499 		switch (linkAddress.LinkLevelType()) {
500 			case IFT_ETHER:
501 				// type = "Ethernet";
502 				// printf("%s\n", type);
503 				break;
504 			case IFT_LOOP:
505 				// type = "Local Loopback";
506 				// printf("%s\n", type);
507 				break;
508 			case IFT_MODEM:
509 				// type = "Modem";
510 				// printf("%s\n", type);
511 				break;
512 			case IFT_PPP:
513 				// type = "PPP";
514 				// printf("%s\n", type);
515 				return true;
516 				break;
517 			default:
518 				// printf("%s\n", type);
519 				;
520 
521 		}
522 
523 	}
524 	return false;
525 }
526 
527 
528 //!	Returns the number of ppp interfaces
529 int32
count_ppp_interface(void)530 count_ppp_interface(void)
531 {
532 	int32 count = 0;
533 
534 	// get a list of all ppp interfaces
535 	BNetworkRoster& roster = BNetworkRoster::Default();
536 
537 	BNetworkInterface interface;
538 	uint32 cookie = 0;
539 
540 	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
541 		if (is_ppp_interface(interface.Name()))
542 			count++;
543 	}
544 
545 	return count;
546 }
547 
548 
549 //!	Returns the number of existing interfaces or a negative value on error.
550 int32
CountInterfaces(ppp_interface_filter filter) const551 PPPManager::CountInterfaces(ppp_interface_filter filter) const
552 {
553 	// return Control(PPPC_COUNT_INTERFACES, &filter, sizeof(filter));
554 	return count_ppp_interface();
555 }
556 
557 
558 /*!	\brief Requests report messages from the PPP stack.
559 
560 	\param type The type of report.
561 	\param thread Receiver thread.
562 	\param flags Optional flags.
563 
564 	\return \c true on success \c false otherwise.
565 */
566 bool
EnableReports(ppp_report_type type,thread_id thread,int32 flags) const567 PPPManager::EnableReports(ppp_report_type type, thread_id thread,
568 	int32 flags) const
569 {
570 	ppp_report_request request;
571 	request.type = type;
572 	request.thread = thread;
573 	request.flags = flags;
574 
575 	return Control(PPPC_ENABLE_REPORTS, &request, sizeof(request)) == B_OK;
576 }
577 
578 
579 /*!	\brief Removes thread from list of report requestors of this interface.
580 
581 	\param type The type of report.
582 	\param thread Receiver thread.
583 
584 	\return \c true on success \c false otherwise.
585 */
586 bool
DisableReports(ppp_report_type type,thread_id thread) const587 PPPManager::DisableReports(ppp_report_type type, thread_id thread) const
588 {
589 	ppp_report_request request;
590 	request.type = type;
591 	request.thread = thread;
592 
593 	return Control(PPPC_DISABLE_REPORTS, &request, sizeof(request)) == B_OK;
594 }
595