xref: /haiku/src/add-ons/kernel/network/ppp/shared/libppp/PPPManager.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
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, &parameter, &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, &parameter);
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