usb_moded 0.86.0+mer64
usb_moded-network.c
Go to the documentation of this file.
1
31
32/*============================================================================= */
33
34#include "usb_moded-network.h"
35
37#include "usb_moded-control.h"
38#include "usb_moded-log.h"
40#include "usb_moded-worker.h"
42
43#include <sys/stat.h>
44
45#include <errno.h>
46#include <unistd.h>
47
48/* ========================================================================= *
49 * Constants
50 * ========================================================================= */
51
52#define UDHCP_CONFIG_PATH "/run/usb-moded/udhcpd.conf"
53#define UDHCP_CONFIG_DIR "/run/usb-moded"
54#define UDHCP_CONFIG_LINK "/etc/udhcpd.conf"
55
56/* ========================================================================= *
57 * Types
58 * ========================================================================= */
59
61typedef struct ipforward_data_t
62{
64 char *dns1;
66 char *dns2;
70
71/* ========================================================================= *
72 * Prototypes
73 * ========================================================================= */
74
75/* ------------------------------------------------------------------------- *
76 * IPFORWARD_DATA
77 * ------------------------------------------------------------------------- */
78
79static ipforward_data_t *ipforward_data_create (void);
80static void ipforward_data_delete (ipforward_data_t *self);
81static void ipforward_data_clear (ipforward_data_t *self);
82static void ipforward_data_set_dns1 (ipforward_data_t *self, const char *dns);
83static void ipforward_data_set_dns2 (ipforward_data_t *self, const char *dns);
84static void ipforward_data_set_nat_interface(ipforward_data_t *self, const char *interface);
85
86/* ------------------------------------------------------------------------- *
87 * OFONO
88 * ------------------------------------------------------------------------- */
89
90#ifdef OFONO
91static gchar *ofono_get_default_modem (void);
92static gchar *ofono_get_modem_status (const char *modem);
93static bool ofono_get_roaming_status(void);
94#endif
95
96/* ------------------------------------------------------------------------- *
97 * CONNMAN
98 * ------------------------------------------------------------------------- */
99
100#ifdef CONNMAN
101static bool connman_technology_set_tethering (DBusConnection *con, const char *technology, bool on, DBusError *err);
102static gchar *connman_manager_get_service_path (DBusConnection *con, const char *type);
103static bool connman_service_get_connection_data(DBusConnection *con, const char *service, ipforward_data_t *ipforward);
104static bool connman_get_connection_data (ipforward_data_t *ipforward);
105bool connman_set_tethering (const char *technology, bool on);
106#endif
107
108/* ------------------------------------------------------------------------- *
109 * LEGACY
110 * ------------------------------------------------------------------------- */
111
112#ifndef CONNMAN
113static bool legacy_get_connection_data(ipforward_data_t *ipforward);
114#endif
115
116/* ------------------------------------------------------------------------- *
117 * NETWORK
118 * ------------------------------------------------------------------------- */
119
120static bool network_interface_exists (char *interface);
121static char *network_get_interface (const modedata_t *data);
122static char *network_get_nat_interface (const modedata_t *data);
123static char *network_get_ip (const modedata_t *data);
124static char *network_get_netmask (const modedata_t *data);
125static int network_setup_ip_forwarding (const modedata_t *data, ipforward_data_t *ipforward);
126static void network_cleanup_ip_forwarding(void);
127static int network_check_udhcpd_symlink (void);
128static int network_write_udhcpd_config (const modedata_t *data, ipforward_data_t *ipforward);
130int network_up (const modedata_t *data);
131void network_down (const modedata_t *data);
132void network_update (void);
133
134/* ========================================================================= *
135 * IPFORWARD_DATA
136 * ========================================================================= */
137
138static ipforward_data_t *
139ipforward_data_create(void)
140{
141 LOG_REGISTER_CONTEXT;
142
143 ipforward_data_t *self = g_malloc0(sizeof *self);
144
145 self->dns1 = 0;
146 self->dns2 = 0;
147 self->nat_interface = 0;
148
149 return self;
150}
151
152static void
153ipforward_data_delete(ipforward_data_t *self)
154{
155 LOG_REGISTER_CONTEXT;
156
157 if( self )
158 {
159 ipforward_data_clear(self);
160 g_free(self);
161 }
162}
163
164static void
165ipforward_data_clear(ipforward_data_t *self)
166{
167 LOG_REGISTER_CONTEXT;
168
169 ipforward_data_set_dns1(self, 0);
170 ipforward_data_set_dns2(self, 0);
171 ipforward_data_set_nat_interface(self, 0);
172}
173
174static void
175ipforward_data_set_dns1(ipforward_data_t *self, const char *dns)
176{
177 LOG_REGISTER_CONTEXT;
178
179 g_free(self->dns1),
180 self->dns1 = dns ? g_strdup(dns) : 0;
181}
182
183static void
184ipforward_data_set_dns2(ipforward_data_t *self, const char *dns)
185{
186 LOG_REGISTER_CONTEXT;
187
188 g_free(self->dns2),
189 self->dns2 = dns ? g_strdup(dns) : 0;
190}
191
192static void
193ipforward_data_set_nat_interface(ipforward_data_t *self, const char *interface)
194{
195 LOG_REGISTER_CONTEXT;
196
197 g_free(self->nat_interface),
198 self->nat_interface = interface ? g_strdup(interface) : 0;
199}
200
201/* ========================================================================= *
202 * OFONO
203 * ========================================================================= */
204
205#ifdef OFONO
206
213
214static gchar *
215ofono_get_default_modem(void)
216{
217 gchar *modem = 0;
218 DBusConnection *con = 0;
219 DBusError err = DBUS_ERROR_INIT;
220 DBusMessage *rsp = 0;
221
222 if( !(con = umdbus_get_connection()) )
223 goto EXIT;
224
225 rsp = umdbus_blocking_call(con,
226 "org.ofono",
227 "/",
228 "org.ofono.Manager",
229 "GetModems",
230 &err,
231 DBUS_TYPE_INVALID);
232 if( !rsp )
233 goto EXIT;
234
235 // a(oa{sv}) -> get object path in the first struct in the array
236 DBusMessageIter body;
237 if( umdbus_parser_init(&body, rsp) ) {
238 DBusMessageIter iter_array;
239 if( umdbus_parser_get_array(&body, &iter_array) ) {
240 DBusMessageIter astruct;
241 if( umdbus_parser_get_struct(&iter_array, &astruct) ) {
242 const char *object = 0;
243 if( umdbus_parser_get_object(&astruct, &object) ) {
244 modem = g_strdup(object);
245 }
246 }
247 }
248 }
249
250EXIT:
251 if( rsp )
252 dbus_message_unref(rsp);
253
254 if( con )
255 dbus_connection_unref(con);
256
257 dbus_error_free(&err);
258
259 log_warning("default modem = %s", modem ?: "n/a");
260
261 return modem;
262}
263
272static gchar *
273ofono_get_modem_status(const char *modem)
274{
275 gchar *status = 0;
276 DBusConnection *con = 0;
277 DBusError err = DBUS_ERROR_INIT;
278 DBusMessage *rsp = 0;
279
280 if( !(con = umdbus_get_connection()) )
281 goto EXIT;
282
283 rsp = umdbus_blocking_call(con,
284 "org.ofono",
285 modem,
286 "org.ofono.NetworkRegistration",
287 "GetProperties",
288 &err,
289 DBUS_TYPE_INVALID);
290 if( !rsp )
291 goto EXIT;
292
293 DBusMessageIter body;
294 if( umdbus_parser_init(&body, rsp) ) {
295 DBusMessageIter iter_array;
296 if( umdbus_parser_get_array(&body, &iter_array) ) {
297 DBusMessageIter entry;
298 while( umdbus_parser_get_entry(&iter_array, &entry) ) {
299 const char *key = 0;
300 if( !umdbus_parser_get_string(&entry, &key) )
301 break;
302 if( strcmp(key, "Status") )
303 continue;
304 DBusMessageIter var;
305 if( !umdbus_parser_get_variant(&entry, &var) )
306 break;
307 const char *val = 0;
308 if( !umdbus_parser_get_string(&var, &val) )
309 break;
310 status = g_strdup(val);
311 break;
312 }
313 }
314 }
315
316EXIT:
317 if( rsp )
318 dbus_message_unref(rsp);
319
320 if( con )
321 dbus_connection_unref(con);
322
323 dbus_error_free(&err);
324
325 log_warning("modem status = %s", status ?: "n/a");
326
327 return status;
328}
329
334static bool
335ofono_get_roaming_status(void)
336{
337 LOG_REGISTER_CONTEXT;
338
339 bool roaming = false;
340 gchar *modem = 0;
341 gchar *status = 0;
342
343 if( !(modem = ofono_get_default_modem()) )
344 goto EXIT;
345
346 if( !(status = ofono_get_modem_status(modem)) )
347 goto EXIT;
348
349 if( !strcmp(status, "roaming") )
350 roaming = true;
351
352EXIT:
353 g_free(status);
354 g_free(modem);
355
356 log_warning("modem roaming = %d", roaming);
357
358 return roaming;
359}
360#endif /* OFONO */
361
362/* ========================================================================= *
363 * CONNMAN
364 * ========================================================================= */
365
366#ifdef CONNMAN
367# define CONNMAN_SERVICE "net.connman"
368# define CONNMAN_TECH_INTERFACE "net.connman.Technology"
369# define CONNMAN_ERROR_ALREADY_ENABLED "net.connman.Error.AlreadyEnabled"
370# define CONNMAN_ERROR_ALREADY_DISABLED "net.connman.Error.AlreadyDisabled"
371
372/* ------------------------------------------------------------------------- *
373 * TECHNOLOGY interface
374 * ------------------------------------------------------------------------- */
375
385static bool
386connman_technology_set_tethering(DBusConnection *con, const char *technology, bool on,
387 DBusError *err)
388{
389 LOG_REGISTER_CONTEXT;
390
391 bool res = FALSE;
392 DBusMessage *rsp = 0;
393 const char *key = "Tethering";
394 dbus_bool_t val = on;
395
396 rsp = umdbus_blocking_call(con,
397 CONNMAN_SERVICE,
398 technology,
399 CONNMAN_TECH_INTERFACE,
400 "SetProperty",
401 err,
402 DBUS_TYPE_STRING, &key,
403 DBUS_TYPE_VARIANT,
404 DBUS_TYPE_BOOLEAN, &val,
405 DBUS_TYPE_INVALID);
406
407 if( !rsp ) {
408 if( on ) {
409 if( !g_strcmp0(err->name, CONNMAN_ERROR_ALREADY_ENABLED) )
410 goto SUCCESS;
411 }
412 else {
413 if( !g_strcmp0(err->name, CONNMAN_ERROR_ALREADY_DISABLED) )
414 goto SUCCESS;
415 }
416 log_err("%s.%s method call failed: %s: %s",
417 CONNMAN_TECH_INTERFACE, "SetProperty",
418 err->name, err->message);
419 goto FAILURE;
420 }
421
422SUCCESS:
423 log_debug("%s tethering %s", technology, on ? "on" : "off");
424 dbus_error_free(err);
425 res = TRUE;
426
427FAILURE:
428 if( rsp )
429 dbus_message_unref(rsp);
430
431 return res;
432}
433
434/* ------------------------------------------------------------------------- *
435 * MANAGER interface
436 * ------------------------------------------------------------------------- */
437
446static gchar *
447connman_manager_get_service_path(DBusConnection *con, const char *type)
448{
449 LOG_REGISTER_CONTEXT;
450
451 gchar *service = 0;
452 DBusError err = DBUS_ERROR_INIT;
453 DBusMessage *rsp = 0;
454
455 rsp = umdbus_blocking_call(con,
456 "net.connman",
457 "/",
458 "net.connman.Manager",
459 "GetServices",
460 &err,
461 DBUS_TYPE_INVALID);
462 if( !rsp )
463 goto EXIT;
464
465 // a(oa{sv}) -> get object path in the first struct matching given type
466 DBusMessageIter body;
467 if( umdbus_parser_init(&body, rsp) ) {
468 // @ body
469 DBusMessageIter array_of_structs;
470 if( umdbus_parser_get_array(&body, &array_of_structs) ) {
471 // @ array of structs
472 DBusMessageIter astruct;
473 while( umdbus_parser_get_struct(&array_of_structs, &astruct) ) {
474 // @ struct
475 const char *object = 0;
476 if( !umdbus_parser_get_object(&astruct, &object) )
477 break;
478 DBusMessageIter array_of_entries;
479 if( !umdbus_parser_get_array(&astruct, &array_of_entries) )
480 break;
481 // @ array of dict entries
482 DBusMessageIter entry;
483 while( umdbus_parser_get_entry(&array_of_entries, &entry) ) {
484 // @ dict entry
485 const char *key = 0;
486 if( !umdbus_parser_get_string(&entry, &key) )
487 break;
488 if( strcmp(key, "Type") )
489 continue;
490 DBusMessageIter var;
491 if( !umdbus_parser_get_variant(&entry, &var) )
492 break;
493 const char *value = 0;
494 if( !umdbus_parser_get_string(&var, &value) )
495 break;
496 if( strcmp(value, type) )
497 continue;
498 service = g_strdup(object);
499 goto EXIT;
500 }
501 }
502 }
503 }
504
505EXIT:
506 if( rsp )
507 dbus_message_unref(rsp);
508
509 dbus_error_free(&err);
510
511 log_warning("%s service = %s", type, service ?: "n/a");
512
513 return service;
514}
515
524static bool
525connman_service_get_connection_data(DBusConnection *con,
526 const char *service,
527 ipforward_data_t *ipforward)
528{
529 LOG_REGISTER_CONTEXT;
530
531 bool ack = false;
532 DBusMessage *rsp = NULL;
533 DBusError err = DBUS_ERROR_INIT;
534
535 log_debug("Filling in dns data");
536
537 rsp = umdbus_blocking_call(con,
538 "net.connman",
539 service,
540 "net.connman.Service",
541 "GetProperties",
542 &err,
543 DBUS_TYPE_INVALID);
544 if( !rsp )
545 goto EXIT;
546
547 const char *dns1 = 0;
548 const char *dns2 = 0;
549 const char *state = 0;
550 const char *interface = 0;
551
552 DBusMessageIter body;
553 if( umdbus_parser_init(&body, rsp) ) {
554 // @ body
555 DBusMessageIter array_of_entries;
556 if( umdbus_parser_get_array(&body, &array_of_entries) ) {
557 // @ array of entries
558 DBusMessageIter entry;
559 while( umdbus_parser_get_entry(&array_of_entries, &entry) ) {
560 // @ dict entry
561 const char *key = 0;
562 if( !umdbus_parser_get_string(&entry, &key) )
563 break;
564 DBusMessageIter var;
565 if( !umdbus_parser_get_variant(&entry, &var) )
566 break;
567
568 if( !strcmp(key, "Nameservers"))
569 {
570 DBusMessageIter array_of_strings;
571 if( umdbus_parser_get_array(&var, &array_of_strings) ) {
572 // expect 0, 1, or 2 entries
573 if( !umdbus_parser_at_end(&array_of_strings) )
574 umdbus_parser_get_string(&array_of_strings, &dns1);
575 if( !umdbus_parser_at_end(&array_of_strings) )
576 umdbus_parser_get_string(&array_of_strings, &dns2);
577 }
578 }
579 else if( !strcmp(key, "State"))
580 {
581 umdbus_parser_get_string(&var, &state);
582 }
583 else if( !strcmp(key, "Ethernet"))
584 {
585 DBusMessageIter array_of_en_entries;
586 if( umdbus_parser_get_array(&var, &array_of_en_entries) ) {
587 DBusMessageIter en_entry;
588 while( umdbus_parser_get_entry(&array_of_en_entries, &en_entry) ) {
589 const char *en_key = 0;
590 if( !umdbus_parser_get_string(&en_entry, &en_key) )
591 break;
592 if( strcmp(en_key, "Interface") )
593 continue;
594 DBusMessageIter en_var;
595 if( umdbus_parser_get_variant(&en_entry, &en_var) )
596 umdbus_parser_get_string(&en_var, &interface);
597 }
598 }
599 }
600 }
601 }
602 }
603
604 bool connected = (!g_strcmp0(state, "ready") ||
605 !g_strcmp0(state, "online"));
606
607 log_debug("state = %s", state ?: "n/a");
608 log_debug("connected = %s", connected ? "true" : "false");
609 log_debug("interface = %s", interface ?: "n/a");
610 log_debug("dns1 = %s", dns1 ?: "n/a");
611 log_debug("dns2 = %s", dns2 ?: "n/a");
612
613 if( !dns1 || !interface || !connected )
614 goto EXIT;
615
616 ipforward_data_set_dns1(ipforward, dns1);
617 ipforward_data_set_dns2(ipforward, dns2 ?: dns1);
618 ipforward_data_set_nat_interface(ipforward, interface);
619
620 ack = true;
621
622EXIT:
623 if( rsp )
624 dbus_message_unref(rsp);
625
626 dbus_error_free(&err);
627
628 return ack;
629}
630
631/* ------------------------------------------------------------------------- *
632 * USB-MODED interface
633 * ------------------------------------------------------------------------- */
634
641static bool
642connman_get_connection_data(ipforward_data_t *ipforward)
643{
644 LOG_REGISTER_CONTEXT;
645
646 bool ack = false;
647 DBusConnection *con = 0;
648 gchar *cellular = 0;
649 gchar *wifi = 0;
650
651 if( !(con = umdbus_get_connection()) )
652 goto FAILURE;
653
654 /* Try to get connection data from cellular service */
655 if( !(cellular = connman_manager_get_service_path(con, "cellular")) )
656 log_warning("no sellular service");
657 else if( connman_service_get_connection_data(con, cellular, ipforward) )
658 goto SUCCESS;
659
660 /* Try to get connection data from wifi service */
661 if( !(wifi = connman_manager_get_service_path(con, "wifi")) )
662 log_warning("no wifi service");
663 else if( connman_service_get_connection_data(con, wifi, ipforward) )
664 goto SUCCESS;
665
666 /* Abandon hope */
667 goto FAILURE;
668
669SUCCESS:
670 ack = true;
671
672FAILURE:
673 if( !ack )
674 log_warning("no connection data");
675 else
676 log_debug("got connection data");
677
678 g_free(wifi);
679 g_free(cellular);
680
681 if( con )
682 dbus_connection_unref(con);
683
684 return ack;
685}
686
694bool
695connman_set_tethering(const char *technology, bool on)
696{
697 LOG_REGISTER_CONTEXT;
698
699 bool res = false;
700 DBusError err = DBUS_ERROR_INIT;
701 DBusConnection *con = 0;
702
703 if( !(con = umdbus_get_connection()) )
704 goto EXIT;
705
706 res = connman_technology_set_tethering(con, technology, on, &err);
707
708EXIT:
709 dbus_error_free(&err);
710
711 if( con )
712 dbus_connection_unref(con);
713
714 log_debug("set tethering(%s) = %s -> %s", technology,
715 on ? "on" : "off", res ? "ack" : "nak");
716
717 return res;
718}
719#endif /* CONNMAN */
720
721/* ========================================================================= *
722 * LEGACY
723 * ========================================================================= */
724
725#ifndef CONNMAN
730static bool
731legacy_get_connection_data(ipforward_data_t *ipforward)
732{
733 LOG_REGISTER_CONTEXT;
734
735 static const char path[] = "/etc/resolv.conf";
736
737 bool ack = false;
738 FILE *file = 0;
739 char *buff = 0;
740 size_t size = 0;
741
742 if( !(file = fopen(path, "r")) ) {
743 log_warning("%s: can't open for reading: %m", path);
744 goto EXIT;
745 }
746
747 int count = 0;
748 while( count < 2 && getline(&buff, &size, file) >= 0 ) {
749 /* skip comment and empty lines */
750 if( strchr("#\n", *buff) )
751 continue;
752
753 gchar **tokens = g_strsplit(buff, " ", 3);
754 if( !tokens || !tokens[0] || !tokens[1] ) {
755 // ignore
756 }
757 else if( !g_strcmp0(tokens[0], "nameserver") ) {
758 // TODO: can have '\n' at eol?
759 g_strstrip(tokens[1]);
760 if( ++count == 1 )
761 ipforward_data_set_dns1(ipforward, tokens[1]);
762 else
763 ipforward_data_set_dns2(ipforward, tokens[1]);
764 }
765 g_strfreev(tokens);
766 }
767
768 if( count < 1 ) {
769 log_warning("%s: no nameserver lines found", path);
770 goto EXIT;
771 }
772
773 /* FIXME: connman_service_get_connection_data() duplicates
774 * dns1 if dns2 is not set - is this necessary?
775 */
776 if( count == 1 )
777 ipforward_data_set_dns2(ipforward, ipforward->dns1);
778
779 ack = true;
780
781EXIT:
782 free(buff);
783
784 if( file )
785 fclose(file);
786
787 return ack;
788}
789#endif
790
791/* ========================================================================= *
792 * NETWORK
793 * ========================================================================= */
794
799static bool
800network_interface_exists(char *interface)
801{
802 LOG_REGISTER_CONTEXT;
803
804 bool ack = false;
805
806 if(interface)
807 {
808 char path[PATH_MAX];
809 snprintf(path, sizeof path, "/sys/class/net/%s", interface);
810 ack = (access(path, F_OK) == 0);
811 }
812
813 return ack;
814}
815
822static char *
823network_get_interface(const modedata_t *data)
824{
825 LOG_REGISTER_CONTEXT;
826
827 gchar *interface = g_strdup(data->cached_interface);
828
829 if( !interface ) {
830 log_warning("mode %s: network interface not specified",
831 data->mode_name);
832 }
833 else if( !network_interface_exists(interface) ) {
834 log_warning("mode %s: network interface %s does not exist",
835 data->mode_name, interface);
836 g_free(interface), interface = NULL;
837 }
838
839 return interface;
840}
841
848static char *
849network_get_nat_interface(const modedata_t *data)
850{
851 LOG_REGISTER_CONTEXT;
852
853 gchar *interface = g_strdup(data->cached_nat_interface);
854
855 if( !interface ) {
856 log_warning("mode %s: network nat interface not specified",
857 data->mode_name);
858 }
859 else if( !network_interface_exists(interface) ) {
860 log_warning("mode %s: network nat interface %s does not exist",
861 data->mode_name, interface);
862 g_free(interface), interface = NULL;
863 }
864
865 return interface;
866}
867
874static char *
875network_get_ip(const modedata_t *data)
876{
877 LOG_REGISTER_CONTEXT;
878
879 gchar *ip = g_strdup(data->cached_ip);
880 if( !ip ) {
881 log_warning("mode %s: network ip address not specified",
882 data->mode_name);
883 }
884
885 return ip;
886}
887
894static char *
895network_get_netmask(const modedata_t *data)
896{
897 LOG_REGISTER_CONTEXT;
898
899 gchar *netmask = g_strdup(data->cached_netmask);
900
901 if( !netmask ) {
902 log_warning("mode %s: network netmask not specified",
903 data->mode_name);
904 }
905
906 return netmask;
907}
908
917static int
918network_setup_ip_forwarding(const modedata_t *data, ipforward_data_t *ipforward)
919{
920 LOG_REGISTER_CONTEXT;
921
922 int failed = 1;
923 char *interface = 0;
924 char *nat_interface = 0;
925
926 char command[256];
927
928 if( !(interface = network_get_interface(data)) )
929 goto EXIT;
930
931 nat_interface = network_get_nat_interface(data);
932 if( !nat_interface ) {
933 if( !ipforward->nat_interface ) {
934 log_debug("No nat interface available!");
935 goto EXIT;
936 }
937 nat_interface = strdup(ipforward->nat_interface);
938 }
939
940 write_to_file("/proc/sys/net/ipv4/ip_forward", "1");
941
942 snprintf(command, sizeof command, "/sbin/iptables -t nat -A POSTROUTING -o %s -j MASQUERADE", nat_interface);
943 common_system(command);
944
945 snprintf(command, sizeof command, "/sbin/iptables -A FORWARD -i %s -o %s -m state --state RELATED,ESTABLISHED -j ACCEPT", nat_interface, interface);
946 common_system(command);
947
948 snprintf(command, sizeof command, "/sbin/iptables -A FORWARD -i %s -o %s -j ACCEPT", interface, nat_interface);
949 common_system(command);
950
951 log_debug("ipforwarding success!");
952 failed = 0;
953
954EXIT:
955 free(interface);
956 free(nat_interface);
957
958 return failed;
959}
960
963static void
964network_cleanup_ip_forwarding(void)
965{
966 LOG_REGISTER_CONTEXT;
967
968 write_to_file("/proc/sys/net/ipv4/ip_forward", "0");
969
970 common_system("/sbin/iptables -F FORWARD");
971}
972
977static int
978network_check_udhcpd_symlink(void)
979{
980 LOG_REGISTER_CONTEXT;
981
982 int ret = -1;
983 char dest[sizeof UDHCP_CONFIG_PATH + 1];
984 ssize_t rc = readlink(UDHCP_CONFIG_LINK, dest, sizeof dest - 1);
985
986 if( rc < 0 ) {
987 if( errno != ENOENT )
988 log_err("%s: can't read symlink: %m", UDHCP_CONFIG_LINK);
989 }
990 else if( (size_t)rc < sizeof dest ) {
991 dest[rc] = 0;
992 if( strcmp(dest, UDHCP_CONFIG_PATH) )
993 log_warning("%s: symlink is invalid", UDHCP_CONFIG_LINK);
994 else
995 ret = 0;
996 }
997 return ret;
998}
999
1007static int
1008network_write_udhcpd_config(const modedata_t *data, ipforward_data_t *ipforward)
1009{
1010 LOG_REGISTER_CONTEXT;
1011
1012 // assume failure
1013 int err = -1;
1014
1015 FILE *conffile = 0;
1016 char *interface = 0;
1017 char *ip = 0;
1018 char *netmask = 0;
1019
1020 if( !(interface = network_get_interface(data)) ) {
1021 log_err("no network interface");
1022 goto EXIT;
1023 }
1024
1025 /* generate start and end ip based on the setting */
1026 if( !(ip = network_get_ip(data)) ) {
1027 log_err("no network address");
1028 goto EXIT;
1029 }
1030
1031 int len = 0;
1032 if( sscanf(ip, "%*d.%*d.%*d%n.%*d", &len) == EOF || ip[len] != '.') {
1033 log_err("malformed network address: %s", ip);
1034 goto EXIT;
1035 }
1036
1037 if( !(netmask = network_get_netmask(data)) ) {
1038 log_err("no network address mask");
1039 goto EXIT;
1040 }
1041
1042 /* /tmp and /run is often tmpfs, so we avoid writing to flash */
1043 if( mkdir(UDHCP_CONFIG_DIR, 0775) == -1 && errno != EEXIST ) {
1044 log_warning("%s: can't create directory: %m", UDHCP_CONFIG_DIR);
1045 }
1046
1047 /* print all data in the file */
1048 if( !(conffile = fopen(UDHCP_CONFIG_PATH, "w")) ) {
1049 log_err("%s: can't open for writing: %m", UDHCP_CONFIG_PATH);
1050 goto EXIT;
1051 }
1052
1053 fprintf(conffile, "start\t%.*s.1\n", len, ip);
1054 fprintf(conffile, "end\t%.*s.15\n", len, ip);
1055 fprintf(conffile, "interface\t%s\n", interface);
1056 fprintf(conffile, "option\tsubnet\t%s\n", netmask);
1057 fprintf(conffile, "option\tlease\t3600\n");
1058 fprintf(conffile, "max_leases\t15\n");
1059
1060 if(ipforward != NULL)
1061 {
1062 if( !ipforward->dns1 || !ipforward->dns2 )
1063 log_debug("No dns info!");
1064 else
1065 fprintf(conffile, "opt\tdns\t%s %s\n", ipforward->dns1, ipforward->dns2);
1066 fprintf(conffile, "opt\trouter\t%s\n", ip);
1067 }
1068
1069 fclose(conffile), conffile = 0;
1070
1071 /* check that we have a valid symlink */
1072 if( network_check_udhcpd_symlink() != 0 ) {
1073 if( unlink(UDHCP_CONFIG_LINK) == -1 && errno != ENOENT )
1074 log_warning("%s: can't remove invalid config: %m", UDHCP_CONFIG_LINK);
1075
1076 if( symlink(UDHCP_CONFIG_PATH, UDHCP_CONFIG_LINK) == -1 ) {
1077 log_err("%s: can't create symlink to %s: %m",
1078 UDHCP_CONFIG_LINK, UDHCP_CONFIG_PATH);
1079 goto EXIT;
1080 }
1081 log_debug("%s: symlink to %s created",
1082 UDHCP_CONFIG_LINK, UDHCP_CONFIG_PATH);
1083 }
1084
1085 // success
1086 err = 0;
1087
1088EXIT:
1089 free(netmask);
1090 free(ip);
1091 free(interface);
1092 if( conffile )
1093 fclose(conffile);
1094
1095 return err;
1096}
1097
1109int
1111{
1112 LOG_REGISTER_CONTEXT;
1113
1114 ipforward_data_t *ipforward = NULL;
1115 int ret = 1;
1116
1117 /* Set up nat info only if it is required */
1118 if( data->nat )
1119 {
1120#ifdef OFONO
1121 /* check if we are roaming or not */
1122 if( ofono_get_roaming_status() ) {
1123 /* get permission to use roaming */
1124 if(config_is_roaming_not_allowed())
1125 goto EXIT;
1126 }
1127#endif
1128
1129 ipforward = ipforward_data_create();
1130
1131#ifdef CONNMAN
1132 if( !connman_get_connection_data(ipforward) )
1133 {
1134 log_debug("data connection not available from connman!");
1135 /* TODO: send a message to the UI */
1136 goto EXIT;
1137 }
1138#else
1139 if( !legacy_get_connection_data(ipforward) ) {
1140 log_debug("data connection not available in resolv.conf!");
1141 goto EXIT;
1142 }
1143#endif
1144 }
1145
1146 /* ipforward can be NULL here, which is expected and handled in this function */
1147 ret = network_write_udhcpd_config(data, ipforward);
1148
1149 if( ret == 0 && data->nat )
1150 ret = network_setup_ip_forwarding(data, ipforward);
1151
1152EXIT:
1153 ipforward_data_delete(ipforward);
1154
1155 return ret;
1156}
1157
1164int
1166{
1167 LOG_REGISTER_CONTEXT;
1168
1169 // assume failure
1170 int ret = 1;
1171
1172 gchar *interface = 0;
1173 gchar *address = 0;
1174 gchar *netmask = 0;
1175 gchar *gateway = 0;
1176
1177 char command[256];
1178
1179 if( !(interface = network_get_interface(data)) ) {
1180 log_err("no network interface");
1181 goto EXIT;
1182 }
1183
1184 if( !(address = network_get_ip(data)) ) {
1185 log_err("no network address");
1186 goto EXIT;
1187 }
1188
1189 if( !(netmask = network_get_netmask(data)) ) {
1190 log_err("no network address mask");
1191 goto EXIT;
1192 }
1193
1194 if( !(gateway = config_get_network_setting(NETWORK_GATEWAY_KEY)) ) {
1195 /* gateway is optional */
1196 log_warning("no network gateway");
1197 }
1198
1199 if( !strcmp(address, "dhcp") )
1200 {
1201 snprintf(command, sizeof command,"dhclient -d %s", interface);
1202 if( common_system(command) != 0 ) {
1203 snprintf(command, sizeof command,"udhcpc -i %s", interface);
1204 if( common_system(command) != 0 )
1205 goto EXIT;
1206 }
1207 }
1208 else
1209 {
1210 snprintf(command, sizeof command,"ifconfig %s %s netmask %s", interface, address, netmask);
1211 if( common_system(command) != 0 )
1212 goto EXIT;
1213 }
1214
1215 /* TODO: Check first if there is a gateway set */
1216 if( gateway )
1217 {
1218 snprintf(command, sizeof command,"route add default gw %s", gateway);
1219 if( common_system(command) != 0 )
1220 goto EXIT;
1221 }
1222
1223 ret = 0;
1224
1225EXIT:
1226 log_debug("iface=%s addr=%s mask=%s gw=%s -> %s",
1227 interface ?: "n/a",
1228 address ?: "n/a",
1229 netmask ?: "n/a",
1230 gateway ?: "n/a",
1231 ret ? "failure" : "success");
1232
1233 g_free(gateway);
1234 g_free(netmask);
1235 g_free(address);
1236 g_free(interface);
1237 return ret;
1238}
1239
1244void
1246{
1247 LOG_REGISTER_CONTEXT;
1248
1249 gchar *interface = network_get_interface(data);
1250
1251 char command[256];
1252
1253 log_debug("iface=%s nat=%d", interface ?: "n/a", data->nat);
1254
1255 if( interface ) {
1256 snprintf(command, sizeof command,"ifconfig %s down", interface);
1257 common_system(command);
1258 }
1259
1260 /* dhcp client shutdown happens on disconnect automatically */
1261 if(data->nat)
1262 network_cleanup_ip_forwarding();
1263
1264 g_free(interface);
1265}
1266
1271void
1273{
1274 LOG_REGISTER_CONTEXT;
1275
1276 if( control_get_cable_state() == CABLE_STATE_PC_CONNECTED ) {
1278 if( data && data->network ) {
1279 /* Bring down using old config */
1280 network_down(data);
1281
1282 /* Update config */
1283 modedata_cache_settings(data);
1285
1286 /* Bring up using old config */
1287 network_up(data);
1288 }
1289 modedata_free(data);
1290 }
1291}
char * config_get_network_setting(const char *config)
cable_state_t control_get_cable_state(void)
void modedata_free(modedata_t *self)
struct modedata_t modedata_t
void network_update(void)
int network_up(const modedata_t *data)
struct ipforward_data_t ipforward_data_t
int network_update_udhcpd_config(const modedata_t *data)
void network_down(const modedata_t *data)
modedata_t * worker_dup_usb_mode_data(void)
void worker_set_usb_mode_data(const modedata_t *data)