4
* Copyright 2013 Alex <alex@linuxonly.ru>
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include <glib/gi18n.h>
30
#include <sys/types.h>
35
#include "../mmguicore.h"
37
#define MMGUI_MODULE_SERVICE_NAME "/usr/sbin/pppd"
38
#define MMGUI_MODULE_IDENTIFIER 245
39
#define MMGUI_MODULE_DESCRIPTION "pppd >= 2.4.5"
41
//Internal definitions
42
#define MODULE_INT_PPPD_DB_FILE_PATH_1 "/var/run/pppd2.tdb"
43
#define MODULE_INT_PPPD_DB_FILE_PATH_2 "/var/run/ppp/pppd2.tdb"
44
#define MODULE_INT_PPPD_LOCK_FILE_PATH "/var/run/%s.pid"
45
#define MODULE_INT_PPPD_DB_FILE_START_PARAMETER "ORIG_UID="
46
#define MODULE_INT_PPPD_DB_FILE_END_PARAMETER "USEPEERDNS="
47
#define MODULE_INT_PPPD_DB_FILE_DEVICE_PARAMETER "DEVICE="
48
#define MODULE_INT_PPPD_DB_FILE_INTERFACE_PARAMETER "IFNAME="
49
#define MODULE_INT_PPPD_DB_FILE_PID_PARAMETER "PPPD_PID="
50
#define MODULE_INT_PPPD_SYSFS_DEVICE_PATH "/sys/dev/char/%u:%u"
51
#define MODULE_INT_PPPD_SYSFS_START_PARAMETER "devices/pci"
52
#define MODULE_INT_PPPD_SYSFS_END_PARAMETER '/'
54
//Private module variables
55
struct _mmguimoduledata {
58
//Connected device information
59
gchar conndevice[256];
61
gchar connifname[IFNAMSIZ];
68
typedef struct _mmguimoduledata *moduledata_t;
71
static void mmgui_module_handle_error_message(mmguicore_t mmguicore, gchar *message)
73
moduledata_t moduledata;
75
if (mmguicore == NULL) return;
77
moduledata = (moduledata_t)mmguicore->cmoduledata;
79
if (moduledata == NULL) return;
81
if (moduledata->errormessage != NULL) {
82
g_free(moduledata->errormessage);
85
if (message != NULL) {
86
moduledata->errormessage = g_strdup(message);
88
moduledata->errormessage = g_strdup("Unknown error");
91
g_warning("%s: %s", MMGUI_MODULE_DESCRIPTION, moduledata->errormessage);
94
static gchar *mmgui_module_pppd_strrstr(gchar *source, gsize sourcelen, gchar *entry, gsize entrylen)
97
gchar *sourceptr, *curptr;
100
if ((source == NULL) || (entry == NULL)) return NULL;
101
if ((sourcelen == 0) || (entrylen == 0)) return source;
103
sourceptr = source + sourcelen - entrylen;
105
for (curptr=sourceptr; curptr>=source; curptr--) {
107
for (ind=0; ind<entrylen; ind++) {
108
if (curptr[ind] != entry[ind]) {
122
static gchar *mmgui_module_pppd_get_config_fragment(gchar *string, gchar *parameter, gchar *buffer, gsize bufsize)
124
gchar *segend, *segstart;
125
gsize datalen, paramlen;
127
if ((string == NULL) || (parameter == NULL) || (buffer == NULL) || (bufsize == 0)) return NULL;
129
segstart = strstr(string, parameter);
131
if (segstart == NULL) return NULL;
133
segend = strchr(segstart, ';');
135
if (segend == NULL) return NULL;
137
paramlen = strlen(parameter);
139
datalen = segend - segstart - paramlen;
141
if (datalen > (bufsize - 1)) datalen = bufsize - 1;
143
memcpy(buffer, segstart+paramlen, datalen);
145
buffer[datalen] = '\0';
150
static gchar *mmgui_module_pppd_get_config_string(gpointer dbmapping, gsize dbsize)
152
gchar *segend, *segstart;
155
if ((dbmapping == NULL) || (dbsize == 0)) return NULL;
157
segend = mmgui_module_pppd_strrstr(dbmapping, dbsize, MODULE_INT_PPPD_DB_FILE_END_PARAMETER, strlen(MODULE_INT_PPPD_DB_FILE_END_PARAMETER));
159
if ((segend == NULL) || ((segend != NULL) && ((*segend) >= dbsize))) return NULL;
161
segstart = mmgui_module_pppd_strrstr(dbmapping, dbsize-(*segend), MODULE_INT_PPPD_DB_FILE_START_PARAMETER, strlen(MODULE_INT_PPPD_DB_FILE_START_PARAMETER));
163
if ((segstart == NULL) || ((segstart != NULL) && (segend <= segstart))) return NULL;
165
result = g_malloc0(segend-segstart+1);
167
if (result == NULL) return NULL;
169
memcpy(result, segstart, segend-segstart);
174
static gchar *mmgui_module_pppd_get_device_serial(gchar *string, gchar *buffer, gsize bufsize)
176
gchar *segend, *segstart;
177
gsize datalen, paramlen;
179
if ((string == NULL) || (buffer == NULL) || (bufsize == 0)) return NULL;
181
paramlen = strlen(MODULE_INT_PPPD_SYSFS_START_PARAMETER);
183
segstart = strstr(string, MODULE_INT_PPPD_SYSFS_START_PARAMETER);
185
if (segstart == NULL) return NULL;
187
segstart = strchr(segstart + paramlen, MODULE_INT_PPPD_SYSFS_END_PARAMETER);
189
if (segstart == NULL) return NULL;
191
segend = strchr(segstart+paramlen, MODULE_INT_PPPD_SYSFS_END_PARAMETER);
193
if (segend == NULL) return NULL;
195
datalen = segend - segstart - 1;
197
if (datalen > (bufsize - 1)) datalen = bufsize - 1;
199
memcpy(buffer, segstart + 1, datalen);
201
buffer[datalen] = '\0';
206
static gboolean mmgui_module_pppd_get_daemon_running(moduledata_t moduledata)
208
gchar pidfilepath[32], pidfiledata[32];
209
gint pidfilefd, status;
210
struct flock pidfilelock;
212
if (moduledata == NULL) return FALSE;
213
if (moduledata->connifname[0] == '\0') return FALSE;
215
memset(pidfilepath, 0, sizeof(pidfilepath));
216
memset(pidfiledata, 0, sizeof(pidfiledata));
218
snprintf(pidfilepath, sizeof(pidfilepath), MODULE_INT_PPPD_LOCK_FILE_PATH, moduledata->connifname);
220
pidfilefd = open(pidfilepath, O_RDONLY);
222
if (pidfilefd == -1) return FALSE;
224
status = read(pidfilefd, pidfiledata, sizeof(pidfiledata));
228
if ((status != -1) && ((pid_t)atoi(pidfiledata) == moduledata->pid)) {
235
static void mmgui_module_pppd_set_connection_status(gpointer mmguicore, gboolean connected)
237
mmguicore_t mmguicorelc;
238
moduledata_t moduledata;
240
if (mmguicore == NULL) return;
241
mmguicorelc = (mmguicore_t)mmguicore;
243
if (mmguicorelc->moduledata == NULL) return;
244
moduledata = (moduledata_t)mmguicorelc->cmoduledata;
246
if (mmguicorelc->device == NULL) return;
249
memset(mmguicorelc->device->interface, 0, IFNAMSIZ);
250
strncpy(mmguicorelc->device->interface, moduledata->connifname, IFNAMSIZ);
251
mmguicorelc->device->connected = TRUE;
253
memset(mmguicorelc->device->interface, 0, IFNAMSIZ);
254
mmguicorelc->device->connected = FALSE;
258
G_MODULE_EXPORT gboolean mmgui_module_init(mmguimodule_t module)
260
if (module == NULL) return FALSE;
262
module->type = MMGUI_MODULE_TYPE_CONNECTION_MANGER;
263
module->requirement = MMGUI_MODULE_REQUIREMENT_FILE;
264
module->priority = MMGUI_MODULE_PRIORITY_LOW;
265
module->identifier = MMGUI_MODULE_IDENTIFIER;
266
module->functions = MMGUI_MODULE_FUNCTION_BASIC;
267
g_snprintf(module->servicename, sizeof(module->servicename), MMGUI_MODULE_SERVICE_NAME);
268
g_snprintf(module->description, sizeof(module->description), MMGUI_MODULE_DESCRIPTION);
273
G_MODULE_EXPORT gboolean mmgui_module_connection_open(gpointer mmguicore)
275
mmguicore_t mmguicorelc;
276
moduledata_t *moduledata;
278
if (mmguicore == NULL) return FALSE;
280
mmguicorelc = (mmguicore_t)mmguicore;
282
moduledata = (moduledata_t *)&mmguicorelc->cmoduledata;
284
(*moduledata) = g_new0(struct _mmguimoduledata, 1);
286
(*moduledata)->errormessage = NULL;
291
G_MODULE_EXPORT gboolean mmgui_module_connection_close(gpointer mmguicore)
293
mmguicore_t mmguicorelc;
294
moduledata_t moduledata;
296
if (mmguicore == NULL) return FALSE;
297
mmguicorelc = (mmguicore_t)mmguicore;
298
moduledata = (moduledata_t)(mmguicorelc->cmoduledata);
300
if (moduledata != NULL) {
301
if (moduledata->errormessage != NULL) {
302
g_free(moduledata->errormessage);
311
G_MODULE_EXPORT gchar *mmgui_module_connection_last_error(gpointer mmguicore)
313
mmguicore_t mmguicorelc;
314
moduledata_t moduledata;
316
if (mmguicore == NULL) return NULL;
318
mmguicorelc = (mmguicore_t)mmguicore;
319
moduledata = (moduledata_t)(mmguicorelc->cmoduledata);
321
return moduledata->errormessage;
324
G_MODULE_EXPORT gboolean mmgui_module_device_connection_open(gpointer mmguicore, mmguidevice_t device)
326
mmguicore_t mmguicorelc;
327
moduledata_t moduledata;
329
if ((mmguicore == NULL) || (device == NULL)) return FALSE;
330
mmguicorelc = (mmguicore_t)mmguicore;
332
if (mmguicorelc->cmoduledata == NULL) return FALSE;
333
moduledata = (moduledata_t)mmguicorelc->cmoduledata;
335
if (device->sysfspath == NULL) {
336
mmgui_module_handle_error_message(mmguicorelc, "Device data not available");
340
if (mmgui_module_pppd_get_device_serial(device->sysfspath, moduledata->devserial, sizeof(moduledata->devserial)) == NULL) {
341
mmgui_module_handle_error_message(mmguicorelc, "Device serial not available");
348
G_MODULE_EXPORT gboolean mmgui_module_device_connection_close(gpointer mmguicore)
350
mmguicore_t mmguicorelc;
351
moduledata_t moduledata;
353
if (mmguicore == NULL) return FALSE;
354
mmguicorelc = (mmguicore_t)mmguicore;
356
if (mmguicorelc->moduledata == NULL) return FALSE;
357
moduledata = (moduledata_t)mmguicorelc->cmoduledata;
359
memset(moduledata->devserial, 0, sizeof(moduledata->devserial));
364
G_MODULE_EXPORT gboolean mmgui_module_device_connection_status(gpointer mmguicore)
366
mmguicore_t mmguicorelc;
367
moduledata_t moduledata;
372
gchar intbuf[16], sysfspath[128], sysfslink[128];
374
gint status, devmajor, devminor;
376
if (mmguicore == NULL) return FALSE;
377
mmguicorelc = (mmguicore_t)mmguicore;
379
if (mmguicorelc->moduledata == NULL) return FALSE;
380
moduledata = (moduledata_t)mmguicorelc->cmoduledata;
382
if (mmguicorelc->device == NULL) return FALSE;
383
if (moduledata->devserial[0] == '\0') return FALSE;
385
/*Usual PPPD database path*/
386
dbfd = open(MODULE_INT_PPPD_DB_FILE_PATH_1, O_RDONLY);
387
/*Try special path first*/
389
/*Special PPPD database path (Fedora uses it)*/
390
dbfd = open(MODULE_INT_PPPD_DB_FILE_PATH_2, O_RDONLY);
391
/*No database found*/
393
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
394
g_debug("Failed to open PPPD database file\n");
399
state = fstat(dbfd, &statbuf);
402
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
403
g_debug("Failed to get PPPD database file size\n");
408
dbmapping = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, dbfd, 0);
410
if(dbmapping == (void *)-1) {
411
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
412
mmgui_module_handle_error_message(mmguicorelc, "Failed to map PPPD database file into memory");
417
pppdconfig = mmgui_module_pppd_get_config_string(dbmapping, statbuf.st_size);
419
if (pppdconfig == NULL) {
420
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
421
mmgui_module_handle_error_message(mmguicorelc, "Failed to get config");
422
munmap(dbmapping, statbuf.st_size);
427
munmap(dbmapping, statbuf.st_size);
430
parameter = mmgui_module_pppd_get_config_fragment(pppdconfig, MODULE_INT_PPPD_DB_FILE_DEVICE_PARAMETER, moduledata->conndevice, sizeof(moduledata->conndevice));
431
if (parameter == NULL) {
432
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
433
g_debug("Device entry not found in PPPD database\n");
438
parameter = mmgui_module_pppd_get_config_fragment(pppdconfig, MODULE_INT_PPPD_DB_FILE_INTERFACE_PARAMETER, moduledata->connifname, sizeof(moduledata->connifname));
439
if (parameter == NULL) {
440
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
441
g_debug("Interface entry not found in PPPD database\n");
446
parameter = mmgui_module_pppd_get_config_fragment(pppdconfig, MODULE_INT_PPPD_DB_FILE_PID_PARAMETER, intbuf, sizeof(intbuf));
447
if (parameter == NULL) {
448
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
449
g_debug("PPPD pid not found in PPPD database\n");
453
moduledata->pid = (pid_t)atoi(parameter);
458
if (!mmgui_module_pppd_get_daemon_running(moduledata)) {
459
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
460
g_debug("PPPD daemon is not running\n");
464
status = stat(moduledata->conndevice, &statbuf);
466
if ((status == -1) || ((status == 0) && (!S_ISCHR(statbuf.st_mode)))) {
467
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
468
g_debug("Device not suitable\n");
472
devmajor = major(statbuf.st_rdev);
473
devminor = minor(statbuf.st_rdev);
475
memset(sysfspath, 0, sizeof(sysfspath));
476
memset(sysfslink, 0, sizeof(sysfslink));
478
snprintf(sysfspath, sizeof(sysfspath), MODULE_INT_PPPD_SYSFS_DEVICE_PATH, devmajor, devminor);
480
status = readlink((const char *)sysfspath, sysfslink, sizeof(sysfslink));
483
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
484
mmgui_module_handle_error_message(mmguicorelc, "Device sysfs path not available");
488
sysfslink[status] = '\0';
490
if (mmgui_module_pppd_get_device_serial(sysfslink, moduledata->connserial, sizeof(moduledata->connserial)) == NULL) {
491
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
492
mmgui_module_handle_error_message(mmguicorelc, "Device serial not available");
496
if (g_str_equal(moduledata->connserial, moduledata->devserial)) {
497
mmgui_module_pppd_set_connection_status(mmguicore, TRUE);
499
mmgui_module_pppd_set_connection_status(mmguicore, FALSE);
505
G_MODULE_EXPORT guint64 mmgui_module_device_connection_timestamp(gpointer mmguicore)
507
mmguicore_t mmguicorelc;
508
moduledata_t moduledata;
509
gchar lockfilepath[128];
513
if (mmguicore == NULL) return FALSE;
514
mmguicorelc = (mmguicore_t)mmguicore;
516
if (mmguicorelc->moduledata == NULL) return FALSE;
517
moduledata = (moduledata_t)mmguicorelc->cmoduledata;
519
if (mmguicorelc->device == NULL) return FALSE;
521
/*Get current timestamp*/
522
timestamp = (guint64)time(NULL);
524
/*Form lock file path*/
525
memset(lockfilepath, 0, sizeof(lockfilepath));
526
g_snprintf(lockfilepath, sizeof(lockfilepath), MODULE_INT_PPPD_LOCK_FILE_PATH, mmguicorelc->device->interface);
527
/*Get lock file modification timestamp*/
528
if (stat(lockfilepath, &statbuf) == 0) {
529
timestamp = (guint64)statbuf.st_mtime;
535
G_MODULE_EXPORT gboolean mmgui_module_device_connection_disconnect(gpointer mmguicore)
537
mmguicore_t mmguicorelc;
538
moduledata_t moduledata;
540
gchar *stderrdata = NULL;
542
gchar *argv[3] = {"/sbin/ifdown", NULL, NULL};
544
if (mmguicore == NULL) return FALSE;
545
mmguicorelc = (mmguicore_t)mmguicore;
547
if (mmguicorelc->moduledata == NULL) return FALSE;
548
moduledata = (moduledata_t)mmguicorelc->cmoduledata;
550
if (mmguicorelc->device == NULL) return FALSE;
551
if (moduledata->devserial[0] == '\0') return FALSE;
553
//If device already disconnected, return TRUE
554
if (!mmguicorelc->device->connected) return TRUE;
557
argv[1] = mmguicorelc->device->interface;
559
if(g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDOUT_TO_DEV_NULL, NULL, NULL, NULL, &stderrdata, &exitstatus, &error)) {
560
//Disconnected - update device state
561
memset(mmguicorelc->device->interface, 0, sizeof(mmguicorelc->device->interface));
562
mmguicorelc->device->connected = FALSE;
565
//Failed to disconnect
567
mmgui_module_handle_error_message(mmguicorelc, error->message);
569
} else if (stderrdata != NULL) {
570
mmgui_module_handle_error_message(mmguicorelc, stderrdata);