summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTambet Ingo <tambet@gmail.com>2009-01-19 11:01:00 +0200
committerTambet Ingo <tambet@gmail.com>2009-02-09 11:01:35 +0200
commite4398a88c8e09a6576625e6084c1a8d263949b76 (patch)
treeaf4096cdeca881ea9193b3e44f8c0b1d3ec69eea
parenta734c836a56f3170202f0555f1a03c9b2835775c (diff)
Use ModemManager.
-rw-r--r--configure.in1
-rw-r--r--src/Makefile.am33
-rw-r--r--src/NetworkManagerPolicy.c6
-rw-r--r--src/modem-manager/Makefile.am45
-rw-r--r--src/modem-manager/nm-modem-cdma.c264
-rw-r--r--src/modem-manager/nm-modem-cdma.h36
-rw-r--r--src/modem-manager/nm-modem-gsm-hso.c348
-rw-r--r--src/modem-manager/nm-modem-gsm-hso.h33
-rw-r--r--src/modem-manager/nm-modem-gsm-mbm.c261
-rw-r--r--src/modem-manager/nm-modem-gsm-mbm.h55
-rw-r--r--src/modem-manager/nm-modem-gsm.c354
-rw-r--r--src/modem-manager/nm-modem-gsm.h36
-rw-r--r--src/modem-manager/nm-modem-manager.c395
-rw-r--r--src/modem-manager/nm-modem-manager.h35
-rw-r--r--src/modem-manager/nm-modem-types.h90
-rw-r--r--src/modem-manager/nm-modem.c457
-rw-r--r--src/modem-manager/nm-modem.h55
-rw-r--r--src/nm-cdma-device.c593
-rw-r--r--src/nm-cdma-device.h59
-rw-r--r--src/nm-hal-manager.c150
-rw-r--r--src/nm-hso-gsm-device.c593
-rw-r--r--src/nm-hso-gsm-device.h56
-rw-r--r--src/nm-manager.c112
-rw-r--r--src/nm-serial-device.c1180
-rw-r--r--src/nm-serial-device.h110
25 files changed, 2562 insertions, 2795 deletions
diff --git a/configure.in b/configure.in
index a235e227c5..7e82d4d0a2 100644
--- a/configure.in
+++ b/configure.in
@@ -504,6 +504,7 @@ src/dhcp-manager/Makefile
504src/supplicant-manager/Makefile 504src/supplicant-manager/Makefile
505src/ppp-manager/Makefile 505src/ppp-manager/Makefile
506src/dnsmasq-manager/Makefile 506src/dnsmasq-manager/Makefile
507src/modem-manager/Makefile
507src/backends/Makefile 508src/backends/Makefile
508libnm-util/libnm-util.pc 509libnm-util/libnm-util.pc
509libnm-util/Makefile 510libnm-util/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 68ed5e8ded..3e134758a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS= \
6 ppp-manager \ 6 ppp-manager \
7 backends \ 7 backends \
8 dnsmasq-manager \ 8 dnsmasq-manager \
9 modem-manager \
9 . \ 10 . \
10 tests 11 tests
11 12
@@ -17,6 +18,7 @@ INCLUDES = -I${top_srcdir} \
17 -I${top_srcdir}/src/dhcp-manager \ 18 -I${top_srcdir}/src/dhcp-manager \
18 -I${top_srcdir}/src/supplicant-manager \ 19 -I${top_srcdir}/src/supplicant-manager \
19 -I${top_srcdir}/src/dnsmasq-manager \ 20 -I${top_srcdir}/src/dnsmasq-manager \
21 -I${top_srcdir}/src/modem-manager \
20 -I${top_srcdir}/libnm-util \ 22 -I${top_srcdir}/libnm-util \
21 -I${top_srcdir}/callouts 23 -I${top_srcdir}/callouts
22 24
@@ -87,14 +89,6 @@ NetworkManager_SOURCES = \
87 nm-activation-request.h \ 89 nm-activation-request.h \
88 nm-properties-changed-signal.c \ 90 nm-properties-changed-signal.c \
89 nm-properties-changed-signal.h \ 91 nm-properties-changed-signal.h \
90 nm-serial-device.c \
91 nm-serial-device.h \
92 nm-gsm-device.c \
93 nm-gsm-device.h \
94 nm-cdma-device.c \
95 nm-cdma-device.h \
96 nm-hso-gsm-device.c \
97 nm-hso-gsm-device.h \
98 wpa.c \ 92 wpa.c \
99 wpa.h \ 93 wpa.h \
100 nm-netlink.c \ 94 nm-netlink.c \
@@ -117,15 +111,6 @@ nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml
117nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml 111nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
118 dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $< 112 dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $<
119 113
120nm-serial-device-glue.h: $(top_srcdir)/introspection/nm-device-serial.xml
121 dbus-binding-tool --prefix=nm_serial_device --mode=glib-server --output=$@ $<
122
123nm-cdma-device-glue.h: $(top_srcdir)/introspection/nm-device-cdma.xml
124 dbus-binding-tool --prefix=nm_cdma_device --mode=glib-server --output=$@ $<
125
126nm-gsm-device-glue.h: $(top_srcdir)/introspection/nm-device-gsm.xml
127 dbus-binding-tool --prefix=nm_gsm_device --mode=glib-server --output=$@ $<
128
129nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml 114nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
130 dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $< 115 dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $<
131 116
@@ -141,9 +126,6 @@ BUILT_SOURCES = \
141 nm-device-interface-glue.h \ 126 nm-device-interface-glue.h \
142 nm-device-ethernet-glue.h \ 127 nm-device-ethernet-glue.h \
143 nm-device-wifi-glue.h \ 128 nm-device-wifi-glue.h \
144 nm-serial-device-glue.h \
145 nm-cdma-device-glue.h \
146 nm-gsm-device-glue.h \
147 nm-ip4-config-glue.h \ 129 nm-ip4-config-glue.h \
148 nm-active-connection-glue.h \ 130 nm-active-connection-glue.h \
149 nm-dhcp4-config-glue.h 131 nm-dhcp4-config-glue.h
@@ -175,11 +157,12 @@ NetworkManager_LDADD = \
175 ./named-manager/libnamed-manager.la \ 157 ./named-manager/libnamed-manager.la \
176 ./vpn-manager/libvpn-manager.la \ 158 ./vpn-manager/libvpn-manager.la \
177 ./dhcp-manager/libdhcp-manager.la \ 159 ./dhcp-manager/libdhcp-manager.la \
178 ./supplicant-manager/libsupplicant-manager.la \ 160 ./supplicant-manager/libsupplicant-manager.la \
179 ./dnsmasq-manager/libdnsmasq-manager.la \ 161 ./dnsmasq-manager/libdnsmasq-manager.la \
180 ./ppp-manager/libppp-manager.la \ 162 ./ppp-manager/libppp-manager.la \
181 ./backends/libnmbackend.la \ 163 ./modem-manager/libmodem-manager.la \
182 $(top_builddir)/libnm-util/libnm-util.la 164 ./backends/libnmbackend.la \
165 $(top_builddir)/libnm-util/libnm-util.la
183 166
184NetworkManager_LDFLAGS = -rdynamic 167NetworkManager_LDFLAGS = -rdynamic
185 168
diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c
index 6bba92f2b1..941109ab78 100644
--- a/src/NetworkManagerPolicy.c
+++ b/src/NetworkManagerPolicy.c
@@ -34,15 +34,13 @@
34#include "nm-device.h" 34#include "nm-device.h"
35#include "nm-device-wifi.h" 35#include "nm-device-wifi.h"
36#include "nm-device-ethernet.h" 36#include "nm-device-ethernet.h"
37#include "nm-hso-gsm-device.h"
38#include "nm-gsm-device.h"
39#include "nm-cdma-device.h"
40#include "nm-dbus-manager.h" 37#include "nm-dbus-manager.h"
41#include "nm-setting-ip4-config.h" 38#include "nm-setting-ip4-config.h"
42#include "nm-setting-connection.h" 39#include "nm-setting-connection.h"
43#include "NetworkManagerSystem.h" 40#include "NetworkManagerSystem.h"
44#include "nm-named-manager.h" 41#include "nm-named-manager.h"
45#include "nm-vpn-manager.h" 42#include "nm-vpn-manager.h"
43#include "nm-modem-gsm-hso.h"
46 44
47typedef struct LookupThread LookupThread; 45typedef struct LookupThread LookupThread;
48 46
@@ -235,7 +233,7 @@ get_best_device (NMManager *manager, NMActRequest **out_req)
235 } 233 }
236 234
237 /* 'hso' devices never get a gateway from the remote end */ 235 /* 'hso' devices never get a gateway from the remote end */
238 if (!can_default && !NM_IS_HSO_GSM_DEVICE (dev)) 236 if (!can_default && !NM_IS_MODEM_GSM_HSO (dev))
239 continue; 237 continue;
240 238
241 /* 'never-default' devices can't ever be the default */ 239 /* 'never-default' devices can't ever be the default */
diff --git a/src/modem-manager/Makefile.am b/src/modem-manager/Makefile.am
new file mode 100644
index 0000000000..75ab97e041
--- /dev/null
+++ b/src/modem-manager/Makefile.am
@@ -0,0 +1,45 @@
1INCLUDES = \
2 -I${top_srcdir}/src \
3 -I${top_srcdir}/include \
4 -I${top_srcdir}/libnm-util \
5 -I${top_builddir}/marshallers
6
7noinst_LTLIBRARIES = libmodem-manager.la
8
9libmodem_manager_la_SOURCES = \
10 nm-modem-cdma.c \
11 nm-modem-cdma.h \
12 nm-modem-gsm.c \
13 nm-modem-gsm.h \
14 nm-modem-gsm-hso.c \
15 nm-modem-gsm-hso.h \
16 nm-modem-gsm-mbm.c \
17 nm-modem-gsm-mbm.h \
18 nm-modem.c \
19 nm-modem.h \
20 nm-modem-manager.h \
21 nm-modem-manager.c \
22 nm-modem-types.h
23
24libmodem_manager_la_CPPFLAGS = \
25 $(DBUS_CFLAGS)
26
27libmodem_manager_la_LIBADD = \
28 $(DBUS_LIBS) \
29 $(top_builddir)/marshallers/libmarshallers.la
30
31nm-device-cdma-glue.h: $(top_srcdir)/introspection/nm-device-cdma.xml
32 dbus-binding-tool --prefix=nm_device_cdma --mode=glib-server --output=$@ $<
33
34nm-device-gsm-glue.h: $(top_srcdir)/introspection/nm-device-gsm.xml
35 dbus-binding-tool --prefix=nm_device_gsm --mode=glib-server --output=$@ $<
36
37nm-serial-device-glue.h: $(top_srcdir)/introspection/nm-device-serial.xml
38 dbus-binding-tool --prefix=nm_serial_device --mode=glib-server --output=$@ $<
39
40BUILT_SOURCES = \
41 nm-device-cdma-glue.h \
42 nm-device-gsm-glue.h \
43 nm-serial-device-glue.h
44
45CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c
new file mode 100644
index 0000000000..1d426962d0
--- /dev/null
+++ b/src/modem-manager/nm-modem-cdma.c
@@ -0,0 +1,264 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#include <string.h>
4
5#include "nm-modem-cdma.h"
6#include "nm-modem-types.h"
7#include "nm-device-interface.h"
8#include "nm-device-private.h"
9#include "nm-dbus-manager.h"
10#include "nm-setting-connection.h"
11#include "nm-setting-cdma.h"
12#include "nm-utils.h"
13
14#include "nm-device-cdma-glue.h"
15
16G_DEFINE_TYPE (NMModemCdma, nm_modem_cdma, NM_TYPE_MODEM)
17
18#define NM_MODEM_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_CDMA, NMModemCdmaPrivate))
19
20enum {
21 MODEM_STATE_BEGIN,
22 MODEM_STATE_ENABLE,
23 MODEM_STATE_CONNECT
24};
25
26typedef struct {
27 int modem_state;
28} NMModemCdmaPrivate;
29
30enum {
31 SIGNAL_QUALITY,
32
33 LAST_SIGNAL
34};
35
36static guint signals[LAST_SIGNAL] = { 0 };
37
38NMDevice *
39nm_modem_cdma_new (const char *path,
40 const char *data_device,
41 const char *driver)
42{
43 g_return_val_if_fail (path != NULL, NULL);
44 g_return_val_if_fail (data_device != NULL, NULL);
45 g_return_val_if_fail (driver != NULL, NULL);
46
47 return (NMDevice *) g_object_new (NM_TYPE_MODEM_CDMA,
48 NM_DEVICE_INTERFACE_UDI, path,
49 NM_DEVICE_INTERFACE_IFACE, data_device,
50 NM_DEVICE_INTERFACE_DRIVER, driver,
51 NM_DEVICE_INTERFACE_MANAGED, TRUE,
52 NM_MODEM_PATH, path,
53 NULL);
54}
55
56static NMSetting *
57get_setting (NMModemCdma *self, GType setting_type)
58{
59 NMActRequest *req;
60 NMSetting *setting = NULL;
61
62 req = nm_device_get_act_request (NM_DEVICE (self));
63 if (req) {
64 NMConnection *connection;
65
66 connection = nm_act_request_get_connection (req);
67 if (connection)
68 setting = nm_connection_get_setting (connection, setting_type);
69 }
70
71 return setting;
72}
73
74static void
75state_machine (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
76{
77 NMModemCdma *modem = NM_MODEM_CDMA (user_data);
78 NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (modem);
79 NMSettingCdma *setting;
80 GError *error = NULL;
81
82 setting = NM_SETTING_CDMA (get_setting (modem, NM_TYPE_SETTING_CDMA));
83
84 if (call_id)
85 dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID);
86
87 if (error) {
88 nm_warning ("CDMA modem connection failed: %s", error->message);
89 nm_device_state_changed (NM_DEVICE (modem), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE);
90 return;
91 }
92
93 switch (priv->modem_state) {
94 case MODEM_STATE_BEGIN:
95 priv->modem_state = MODEM_STATE_ENABLE;
96 dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (modem), NULL),
97 "Enable", state_machine,
98 modem, NULL,
99 G_TYPE_BOOLEAN, TRUE,
100 G_TYPE_INVALID);
101 break;
102 case MODEM_STATE_ENABLE:
103 priv->modem_state = MODEM_STATE_CONNECT;
104 dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (modem), NULL),
105 "Connect", state_machine,
106 modem, NULL,
107 G_TYPE_STRING, nm_setting_cdma_get_number (setting),
108 G_TYPE_INVALID);
109 break;
110 case MODEM_STATE_CONNECT:
111 nm_device_activate_schedule_stage2_device_config (NM_DEVICE (modem));
112 break;
113 default:
114 nm_warning ("Invalid modem state %d", priv->modem_state);
115 nm_device_state_changed (NM_DEVICE (modem), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE);
116 break;
117 }
118}
119
120static NMActStageReturn
121real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
122{
123 NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (device);
124
125 priv->modem_state = MODEM_STATE_BEGIN;
126 state_machine (NULL, NULL, device);
127
128 return NM_ACT_STAGE_RETURN_POSTPONE;
129}
130
131static NMConnection *
132real_get_best_auto_connection (NMDevice *dev,
133 GSList *connections,
134 char **specific_object)
135{
136 GSList *iter;
137
138 for (iter = connections; iter; iter = g_slist_next (iter)) {
139 NMConnection *connection = NM_CONNECTION (iter->data);
140 NMSettingConnection *s_con;
141
142 s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
143 g_assert (s_con);
144
145 if (!nm_setting_connection_get_autoconnect (s_con))
146 continue;
147
148 if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME))
149 continue;
150
151 return connection;
152 }
153 return NULL;
154}
155
156static void
157real_connection_secrets_updated (NMDevice *dev,
158 NMConnection *connection,
159 GSList *updated_settings,
160 RequestSecretsCaller caller)
161{
162 NMActRequest *req;
163 gboolean found = FALSE;
164 GSList *iter;
165
166 if (caller == SECRETS_CALLER_PPP) {
167 NMPPPManager *ppp_manager;
168 NMSettingCdma *s_cdma = NULL;
169
170 ppp_manager = nm_modem_get_ppp_manager (NM_MODEM (dev));
171 g_return_if_fail (ppp_manager != NULL);
172
173 s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
174 if (!s_cdma) {
175 /* Shouldn't ever happen */
176 nm_ppp_manager_update_secrets (ppp_manager,
177 nm_device_get_iface (dev),
178 NULL,
179 NULL,
180 "missing CDMA setting; no secrets could be found.");
181 } else {
182 const char *username = nm_setting_cdma_get_username (s_cdma);
183 const char *password = nm_setting_cdma_get_password (s_cdma);
184
185 nm_ppp_manager_update_secrets (ppp_manager,
186 nm_device_get_iface (dev),
187 username ? username : "",
188 password ? password : "",
189 NULL);
190 }
191 return;
192 }
193
194 g_return_if_fail (caller == SECRETS_CALLER_CDMA);
195 g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH);
196
197 for (iter = updated_settings; iter; iter = g_slist_next (iter)) {
198 const char *setting_name = (const char *) iter->data;
199
200 if (!strcmp (setting_name, NM_SETTING_CDMA_SETTING_NAME))
201 found = TRUE;
202 else
203 nm_warning ("Ignoring updated secrets for setting '%s'.", setting_name);
204 }
205
206 if (!found)
207 return;
208
209 req = nm_device_get_act_request (dev);
210 g_assert (req);
211
212 g_return_if_fail (nm_act_request_get_connection (req) == connection);
213
214 nm_device_activate_schedule_stage1_device_prepare (dev);
215}
216
217static const char *
218real_get_ppp_name (NMModem *device, NMConnection *connection)
219{
220 NMSettingCdma *s_cdma;
221
222 s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
223 g_assert (s_cdma);
224
225 return nm_setting_cdma_get_username (s_cdma);
226}
227
228/*****************************************************************************/
229
230static void
231nm_modem_cdma_init (NMModemCdma *self)
232{
233 nm_device_set_device_type (NM_DEVICE (self), NM_DEVICE_TYPE_CDMA);
234}
235
236static void
237nm_modem_cdma_class_init (NMModemCdmaClass *klass)
238{
239 GObjectClass *object_class = G_OBJECT_CLASS (klass);
240 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
241 NMModemClass *modem_class = NM_MODEM_CLASS (klass);
242
243 g_type_class_add_private (object_class, sizeof (NMModemCdmaPrivate));
244
245 /* Virtual methods */
246 device_class->get_best_auto_connection = real_get_best_auto_connection;
247 device_class->connection_secrets_updated = real_connection_secrets_updated;
248 device_class->act_stage1_prepare = real_act_stage1_prepare;
249 modem_class->get_ppp_name = real_get_ppp_name;
250
251 /* Signals */
252 signals[SIGNAL_QUALITY] =
253 g_signal_new ("signal-quality",
254 G_OBJECT_CLASS_TYPE (object_class),
255 G_SIGNAL_RUN_FIRST,
256 G_STRUCT_OFFSET (NMModemCdmaClass, signal_quality),
257 NULL, NULL,
258 g_cclosure_marshal_VOID__UINT,
259 G_TYPE_NONE, 1,
260 G_TYPE_UINT);
261
262 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
263 &dbus_glib_nm_device_cdma_object_info);
264}
diff --git a/src/modem-manager/nm-modem-cdma.h b/src/modem-manager/nm-modem-cdma.h
new file mode 100644
index 0000000000..a1f3bf5459
--- /dev/null
+++ b/src/modem-manager/nm-modem-cdma.h
@@ -0,0 +1,36 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#ifndef NM_MODEM_CDMA_H
4#define NM_MODEM_CDMA_H
5
6#include <nm-modem.h>
7
8G_BEGIN_DECLS
9
10#define NM_TYPE_MODEM_CDMA (nm_modem_cdma_get_type ())
11#define NM_MODEM_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_CDMA, NMModemCdma))
12#define NM_MODEM_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
13#define NM_IS_MODEM_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_CDMA))
14#define NM_IS_MODEM_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_CDMA))
15#define NM_MODEM_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
16
17typedef struct {
18 NMModem parent;
19} NMModemCdma;
20
21typedef struct {
22 NMModemClass parent;
23
24 /* Signals */
25 void (*signal_quality) (NMModemCdma *self, guint32 quality);
26} NMModemCdmaClass;
27
28GType nm_modem_cdma_get_type (void);
29
30NMDevice *nm_modem_cdma_new (const char *path,
31 const char *data_device,
32 const char *driver);
33
34G_END_DECLS
35
36#endif /* NM_MODEM_CDMA_H */
diff --git a/src/modem-manager/nm-modem-gsm-hso.c b/src/modem-manager/nm-modem-gsm-hso.c
new file mode 100644
index 0000000000..343bfa3f24
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm-hso.c
@@ -0,0 +1,348 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#include "nm-modem-gsm-hso.h"
4#include "nm-device-private.h"
5#include "nm-device-interface.h"
6#include "NetworkManagerSystem.h"
7#include "nm-setting-connection.h"
8#include "nm-setting-gsm.h"
9#include "nm-modem-types.h"
10#include "nm-utils.h"
11
12G_DEFINE_TYPE (NMModemGsmHso, nm_modem_gsm_hso, NM_TYPE_MODEM_GSM)
13
14#define NM_MODEM_GSM_HSO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GSM_HSO, NMModemGsmHsoPrivate))
15
16typedef struct {
17 char *netdev_iface;
18 NMIP4Config *pending_ip4_config;
19} NMModemGsmHsoPrivate;
20
21#define HSO_SECRETS_TRIES "gsm-secrets-tries"
22
23static char *
24get_network_device (NMDevice *device)
25{
26 char *result = NULL;
27 GError *error = NULL;
28 GValue value = { 0, };
29
30 if (!dbus_g_proxy_call (nm_modem_get_proxy (NM_MODEM (device), "org.freedesktop.DBus.Properties"),
31 "Get", &error,
32 G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM_GSM_HSO,
33 G_TYPE_STRING, "NetworkDevice",
34 G_TYPE_INVALID,
35 G_TYPE_VALUE, &value,
36 G_TYPE_INVALID)) {
37 nm_warning ("Could not get HSO device's network interface: %s", error->message);
38 g_error_free (error);
39 } else {
40 if (G_VALUE_HOLDS_STRING (&value))
41 result = g_value_dup_string (&value);
42 else
43 nm_warning ("Could not get HSO device's network interface: wrong type '%s'",
44 G_VALUE_TYPE_NAME (&value));
45
46 g_value_unset (&value);
47 }
48
49 return result;
50}
51
52NMDevice *
53nm_modem_gsm_hso_new (const char *path,
54 const char *data_device,
55 const char *driver)
56{
57 NMDevice *device;
58
59 g_return_val_if_fail (path != NULL, NULL);
60 g_return_val_if_fail (data_device != NULL, NULL);
61 g_return_val_if_fail (driver != NULL, NULL);
62
63 device = (NMDevice *) g_object_new (NM_TYPE_MODEM_GSM_HSO,
64 NM_DEVICE_INTERFACE_UDI, path,
65 NM_DEVICE_INTERFACE_IFACE, data_device,
66 NM_DEVICE_INTERFACE_DRIVER, driver,
67 NM_DEVICE_INTERFACE_MANAGED, TRUE,
68 NM_MODEM_PATH, path,
69 NULL);
70
71 if (device) {
72 NMModemGsmHsoPrivate *priv;
73
74 priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
75 priv->netdev_iface = get_network_device (device);
76 if (!priv->netdev_iface) {
77 g_object_unref (device);
78 device = NULL;
79 }
80 }
81
82 return device;
83}
84
85/*****************************************************************************/
86
87static NMSetting *
88get_setting (NMModemGsmHso *modem, GType setting_type)
89{
90 NMActRequest *req;
91 NMSetting *setting = NULL;
92
93 req = nm_device_get_act_request (NM_DEVICE (modem));
94 if (req) {
95 NMConnection *connection;
96
97 connection = nm_act_request_get_connection (req);
98 if (connection)
99 setting = nm_connection_get_setting (connection, setting_type);
100 }
101
102 return setting;
103}
104
105static void
106hso_auth_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
107{
108 NMDevice *device = NM_DEVICE (user_data);
109 GError *error = NULL;
110
111 if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID))
112 nm_device_activate_schedule_stage3_ip_config_start (device);
113 else {
114 nm_warning ("Authentication failed: %s", error->message);
115 g_error_free (error);
116 nm_device_state_changed (device,
117 NM_DEVICE_STATE_FAILED,
118 NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED);
119 }
120}
121
122static void
123do_hso_auth (NMModemGsmHso *device)
124{
125 NMSettingGsm *s_gsm;
126 const char *username;
127 const char *password;
128
129 s_gsm = NM_SETTING_GSM (get_setting (device, NM_TYPE_SETTING_GSM));
130 username = nm_setting_gsm_get_username (s_gsm);
131 password = nm_setting_gsm_get_password (s_gsm);
132
133 dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM_GSM_HSO),
134 "Authenticate", hso_auth_done,
135 device, NULL,
136 G_TYPE_STRING, username ? username : "",
137 G_TYPE_STRING, password ? password : "",
138 G_TYPE_INVALID);
139}
140
141static NMActStageReturn
142real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
143{
144 NMActRequest *req;
145 NMConnection *connection;
146 const char *setting_name;
147 GPtrArray *hints = NULL;
148 const char *hint1 = NULL, *hint2 = NULL;
149 guint32 tries;
150
151 req = nm_device_get_act_request (device);
152 g_assert (req);
153 connection = nm_act_request_get_connection (req);
154 g_assert (connection);
155
156 setting_name = nm_connection_need_secrets (connection, &hints);
157 if (!setting_name) {
158 do_hso_auth (NM_MODEM_GSM_HSO (device));
159 return NM_ACT_STAGE_RETURN_POSTPONE;
160 }
161
162 if (hints) {
163 if (hints->len > 0)
164 hint1 = g_ptr_array_index (hints, 0);
165 if (hints->len > 1)
166 hint2 = g_ptr_array_index (hints, 1);
167 }
168
169 nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
170
171 tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), HSO_SECRETS_TRIES));
172 nm_act_request_request_connection_secrets (req,
173 setting_name,
174 tries ? TRUE : FALSE,
175 SECRETS_CALLER_HSO_GSM,
176 hint1,
177 hint2);
178 g_object_set_data (G_OBJECT (connection), HSO_SECRETS_TRIES, GUINT_TO_POINTER (++tries));
179
180 if (hints)
181 g_ptr_array_free (hints, TRUE);
182
183 return NM_ACT_STAGE_RETURN_POSTPONE;
184}
185
186static void
187get_ip4_config_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
188{
189 NMDevice *device = NM_DEVICE (user_data);
190 guint32 ip4_address;
191 GArray *dns_array;
192 GError *error = NULL;
193
194 if (dbus_g_proxy_end_call (proxy, call_id, &error,
195 G_TYPE_UINT, &ip4_address,
196 DBUS_TYPE_G_UINT_ARRAY, &dns_array,
197 G_TYPE_INVALID)) {
198
199 NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
200 NMIP4Address *addr;
201 int i;
202
203 addr = nm_ip4_address_new ();
204 nm_ip4_address_set_address (addr, ip4_address);
205 nm_ip4_address_set_prefix (addr, 32);
206
207 priv->pending_ip4_config = nm_ip4_config_new ();
208 nm_ip4_config_take_address (priv->pending_ip4_config, addr);
209
210 for (i = 0; i < dns_array->len; i++)
211 nm_ip4_config_add_nameserver (priv->pending_ip4_config,
212 g_array_index (dns_array, guint32, i));
213
214 nm_device_activate_schedule_stage4_ip_config_get (device);
215 } else {
216 nm_warning ("Retrieving IP4 configuration failed: %s", error->message);
217 g_error_free (error);
218 nm_device_state_changed (device,
219 NM_DEVICE_STATE_FAILED,
220 NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
221 }
222}
223
224static NMActStageReturn
225real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason)
226{
227 dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM_GSM_HSO),
228 "GetIP4Config", get_ip4_config_done,
229 device, NULL,
230 G_TYPE_INVALID);
231
232 return NM_ACT_STAGE_RETURN_POSTPONE;
233}
234
235static NMActStageReturn
236real_act_stage4_get_ip4_config (NMDevice *device,
237 NMIP4Config **config,
238 NMDeviceStateReason *reason)
239{
240 NMModemGsmHso *self = NM_MODEM_GSM_HSO (device);
241 NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (self);
242 gboolean no_firmware = FALSE;
243
244 nm_device_set_ip_iface (device, priv->netdev_iface);
245 if (!nm_device_hw_bring_up (device, TRUE, &no_firmware)) {
246 if (no_firmware)
247 *reason = NM_DEVICE_STATE_REASON_FIRMWARE_MISSING;
248 else
249 *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
250 return NM_ACT_STAGE_RETURN_FAILURE;
251 }
252
253 *config = priv->pending_ip4_config;
254 priv->pending_ip4_config = NULL;
255
256 return NM_ACT_STAGE_RETURN_SUCCESS;
257}
258
259static void
260real_deactivate (NMDevice *device)
261{
262 NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
263
264 if (priv->pending_ip4_config) {
265 g_object_unref (priv->pending_ip4_config);
266 priv->pending_ip4_config = NULL;
267 }
268
269 if (priv->netdev_iface) {
270 nm_system_device_flush_ip4_routes_with_iface (priv->netdev_iface);
271 nm_system_device_flush_ip4_addresses_with_iface (priv->netdev_iface);
272 nm_system_device_set_up_down_with_iface (priv->netdev_iface, FALSE, NULL);
273 }
274 nm_device_set_ip_iface (device, NULL);
275
276 if (NM_DEVICE_CLASS (nm_modem_gsm_hso_parent_class)->deactivate)
277 NM_DEVICE_CLASS (nm_modem_gsm_hso_parent_class)->deactivate (device);
278}
279
280static gboolean
281real_hw_is_up (NMDevice *device)
282{
283 NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
284 NMDeviceState state;
285
286 state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
287 if (priv->pending_ip4_config || state == NM_DEVICE_STATE_IP_CONFIG || state == NM_DEVICE_STATE_ACTIVATED)
288 return nm_system_device_is_up_with_iface (priv->netdev_iface);
289
290 return TRUE;
291}
292
293static gboolean
294real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
295{
296 NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
297 NMDeviceState state;
298
299 state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
300 if (priv->pending_ip4_config || state == NM_DEVICE_STATE_IP_CONFIG || state == NM_DEVICE_STATE_ACTIVATED)
301 return nm_system_device_set_up_down_with_iface (priv->netdev_iface, TRUE, no_firmware);
302
303 return TRUE;
304}
305
306static void
307real_connect (NMModem *modem, const char *number)
308{
309 nm_device_activate_schedule_stage2_device_config (NM_DEVICE (modem));
310}
311
312/*****************************************************************************/
313
314static void
315nm_modem_gsm_hso_init (NMModemGsmHso *self)
316{
317}
318
319static void
320finalize (GObject *object)
321{
322 NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (object);
323
324 g_free (priv->netdev_iface);
325
326 G_OBJECT_CLASS (nm_modem_gsm_hso_parent_class)->finalize (object);
327}
328
329static void
330nm_modem_gsm_hso_class_init (NMModemGsmHsoClass *klass)
331{
332 GObjectClass *object_class = G_OBJECT_CLASS (klass);
333 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
334 NMModemClass *modem_class = NM_MODEM_CLASS (klass);
335
336 g_type_class_add_private (object_class, sizeof (NMModemGsmHsoPrivate));
337
338 object_class->finalize = finalize;
339
340 device_class->act_stage2_config = real_act_stage2_config;
341 device_class->act_stage3_ip_config_start = real_act_stage3_ip_config_start;
342 device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
343 device_class->deactivate = real_deactivate;
344 device_class->hw_is_up = real_hw_is_up;
345 device_class->hw_bring_up = real_hw_bring_up;
346
347 modem_class->connect = real_connect;
348}
diff --git a/src/modem-manager/nm-modem-gsm-hso.h b/src/modem-manager/nm-modem-gsm-hso.h
new file mode 100644
index 0000000000..9b67bee921
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm-hso.h
@@ -0,0 +1,33 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#ifndef NM_MODEM_GSM_HSO_H
4#define NM_MODEM_GSM_HSO_H
5
6#include <nm-modem-gsm.h>
7
8G_BEGIN_DECLS
9
10#define NM_TYPE_MODEM_GSM_HSO (nm_modem_gsm_hso_get_type ())
11#define NM_MODEM_GSM_HSO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_GSM_HSO, NMModemGsmHso))
12#define NM_MODEM_GSM_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_GSM_HSO, NMModemGsmHsoClass))
13#define NM_IS_MODEM_GSM_HSO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_GSM_HSO))
14#define NM_IS_MODEM_GSM_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_GSM_HSO))
15#define NM_MODEM_GSM_HSO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_GSM_HSO, NMModemGsmHsoClass))
16
17typedef struct {
18 NMModemGsm parent;
19} NMModemGsmHso;
20
21typedef struct {
22 NMModemGsmClass parent;
23} NMModemGsmHsoClass;
24
25GType nm_modem_gsm_hso_get_type (void);
26
27NMDevice *nm_modem_gsm_hso_new (const char *path,
28 const char *data_device,
29 const char *driver);
30
31G_END_DECLS
32
33#endif /* NM_MODEM_GSM_HSO_H */
diff --git a/src/modem-manager/nm-modem-gsm-mbm.c b/src/modem-manager/nm-modem-gsm-mbm.c
new file mode 100644
index 0000000000..adac6f7552
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm-mbm.c
@@ -0,0 +1,261 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 Additions to NetworkManager, network-manager-applet and modemmanager
4 for supporting Ericsson modules like F3507g.
5
6 Author: Per Hallsmark <per@hallsmark.se>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23*/
24
25#include "nm-modem-gsm-mbm.h"
26#include "nm-device-private.h"
27#include "nm-device-interface.h"
28#include "NetworkManagerSystem.h"
29#include "nm-setting-connection.h"
30#include "nm-setting-gsm.h"
31#include "nm-modem-types.h"
32#include "nm-utils.h"
33
34G_DEFINE_TYPE (NMModemGsmMbm, nm_modem_gsm_mbm, NM_TYPE_MODEM_GSM)
35
36#define NM_MODEM_GSM_MBM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GSM_MBM, NMModemGsmMbmPrivate))
37
38typedef struct {
39 char *netdev_iface;
40 NMIP4Config *pending_ip4_config;
41} NMModemGsmMbmPrivate;
42
43#define MBM_SECRETS_TRIES "gsm-secrets-tries"
44
45static char *
46get_network_device (NMDevice *device)
47{
48 char *result = NULL;
49 GError *error = NULL;
50 GValue value = { 0, };
51
52 if (!dbus_g_proxy_call (nm_modem_get_proxy (NM_MODEM (device), "org.freedesktop.DBus.Properties"),
53 "Get", &error,
54 G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM_GSM_MBM,
55 G_TYPE_STRING, "NetworkDevice",
56 G_TYPE_INVALID,
57 G_TYPE_VALUE, &value,
58 G_TYPE_INVALID)) {
59 nm_warning ("Could not get MBM device's network interface: %s", error->message);
60 g_error_free (error);
61 } else {
62 if (G_VALUE_HOLDS_STRING (&value))
63 result = g_value_dup_string (&value);
64 else
65 nm_warning ("Could not get MBM device's network interface: wrong type '%s'",
66 G_VALUE_TYPE_NAME (&value));
67
68 g_value_unset (&value);
69 }
70
71 return result;
72}
73
74NMDevice *
75nm_modem_gsm_mbm_new (const char *path,
76 const char *data_device,
77 const char *driver)
78{
79 NMDevice *device;
80
81 g_return_val_if_fail (path != NULL, NULL);
82 g_return_val_if_fail (data_device != NULL, NULL);
83 g_return_val_if_fail (driver != NULL, NULL);
84
85 device = (NMDevice *) g_object_new (NM_TYPE_MODEM_GSM_MBM,
86 NM_DEVICE_INTERFACE_UDI, path,
87 NM_DEVICE_INTERFACE_IFACE, data_device,
88 NM_DEVICE_INTERFACE_DRIVER, driver,
89 NM_DEVICE_INTERFACE_MANAGED, TRUE,
90 NM_MODEM_PATH, path,
91 NULL);
92
93 if (device) {
94 NMModemGsmMbmPrivate *priv;
95
96 priv = NM_MODEM_GSM_MBM_GET_PRIVATE (device);
97 priv->netdev_iface = get_network_device (device);
98 if (!priv->netdev_iface) {
99 g_object_unref (device);
100 device = NULL;
101 }
102 }
103
104 return device;
105}
106
107/*****************************************************************************/
108
109#if 0
110static NMSetting *
111get_setting (NMModemGsmMbm *modem, GType setting_type)
112{
113 NMActRequest *req;
114 NMSetting *setting = NULL;
115
116 req = nm_device_get_act_request (NM_DEVICE (modem));
117 if (req) {
118 NMConnection *connection;
119
120 connection = nm_act_request_get_connection (req);
121 if (connection)
122 setting = nm_connection_get_setting (connection, setting_type);
123 }
124
125 return setting;
126}
127#endif
128
129#if 0
130static NMActStageReturn
131real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
132{
133 NMActRequest *req;
134 NMConnection *connection;
135 const char *setting_name;
136 GPtrArray *hints = NULL;
137 const char *hint1 = NULL, *hint2 = NULL;
138 guint32 tries;
139
140 req = nm_device_get_act_request (device);
141 g_assert (req);
142 connection = nm_act_request_get_connection (req);
143 g_assert (connection);
144
145 setting_name = nm_connection_need_secrets (connection, &hints);
146 if (!setting_name) {
147 // do_mbm_auth (NM_MODEM_GSM_MBM (device));
148 return NM_ACT_STAGE_RETURN_POSTPONE;
149 }
150
151 if (hints) {
152 if (hints->len > 0)
153 hint1 = g_ptr_array_index (hints, 0);
154 if (hints->len > 1)
155 hint2 = g_ptr_array_index (hints, 1);
156 }
157
158 nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
159
160 tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), MBM_SECRETS_TRIES));
161 nm_act_request_request_connection_secrets (req,
162 setting_name,
163 tries ? TRUE : FALSE,
164 SECRETS_CALLER_MBM_GSM,
165 hint1,
166 hint2);
167 g_object_set_data (G_OBJECT (connection), MBM_SECRETS_TRIES, GUINT_TO_POINTER (++tries));
168
169 if (hints)
170 g_ptr_array_free (hints, TRUE);
171
172 return NM_ACT_STAGE_RETURN_POSTPONE;
173}
174#endif
175
176static void
177real_deactivate (NMDevice *device)
178{
179 NMModemGsmMbmPrivate *priv = NM_MODEM_GSM_MBM_GET_PRIVATE (device);
180
181 if (priv->pending_ip4_config) {
182 g_object_unref (priv->pending_ip4_config);
183 priv->pending_ip4_config = NULL;
184 }
185
186 if (priv->netdev_iface) {
187 nm_system_device_flush_ip4_routes_with_iface (priv->netdev_iface);
188 nm_system_device_flush_ip4_addresses_with_iface (priv->netdev_iface);
189 nm_system_device_set_up_down_with_iface (priv->netdev_iface, FALSE, NULL);
190 }
191 nm_device_set_ip_iface (device, NULL);
192
193 if (NM_DEVICE_CLASS (nm_modem_gsm_mbm_parent_class)->deactivate)
194 NM_DEVICE_CLASS (nm_modem_gsm_mbm_parent_class)->deactivate (device);
195}
196
197static gboolean
198real_hw_is_up (NMDevice *device)
199{
200 NMModemGsmMbmPrivate *priv = NM_MODEM_GSM_MBM_GET_PRIVATE (device);
201
202 if (priv->netdev_iface)
203 return nm_system_device_is_up_with_iface (priv->netdev_iface);
204
205 return TRUE;
206}
207
208static gboolean
209real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
210{
211 NMModemGsmMbmPrivate *priv = NM_MODEM_GSM_MBM_GET_PRIVATE (device);
212
213 if (priv->netdev_iface)
214 return nm_system_device_set_up_down_with_iface (priv->netdev_iface, TRUE, no_firmware);
215
216 return TRUE;
217}
218
219static void
220real_connect (NMModem *modem, const char *number)
221{
222 nm_device_activate_schedule_stage2_device_config (NM_DEVICE (modem));
223}
224
225/*****************************************************************************/
226
227static void
228nm_modem_gsm_mbm_init (NMModemGsmMbm *self)
229{
230}
231
232static void
233finalize (GObject *object)
234{
235 NMModemGsmMbmPrivate *priv = NM_MODEM_GSM_MBM_GET_PRIVATE (object);
236
237 g_free (priv->netdev_iface);
238
239 G_OBJECT_CLASS (nm_modem_gsm_mbm_parent_class)->finalize (object);
240}
241
242static void
243nm_modem_gsm_mbm_class_init (NMModemGsmMbmClass *klass)
244{
245 GObjectClass *object_class = G_OBJECT_CLASS (klass);
246 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
247 NMModemClass *modem_class = NM_MODEM_CLASS (klass);
248
249 g_type_class_add_private (object_class, sizeof (NMModemGsmMbmPrivate));
250
251 object_class->finalize = finalize;
252
253#if 0
254 device_class->act_stage2_config = real_act_stage2_config;
255#endif
256 device_class->deactivate = real_deactivate;
257 device_class->hw_is_up = real_hw_is_up;
258 device_class->hw_bring_up = real_hw_bring_up;
259
260 modem_class->connect = real_connect;
261}
diff --git a/src/modem-manager/nm-modem-gsm-mbm.h b/src/modem-manager/nm-modem-gsm-mbm.h
new file mode 100644
index 0000000000..9bd4b3a7da
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm-mbm.h
@@ -0,0 +1,55 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 Additions to NetworkManager, network-manager-applet and modemmanager
4 for supporting Ericsson modules like F3507g.
5
6 Author: Per Hallsmark <per@hallsmark.se>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23*/
24
25#ifndef NM_MODEM_GSM_MBM_H
26#define NM_MODEM_GSM_MBM_H
27
28#include <nm-modem-gsm.h>
29
30G_BEGIN_DECLS
31
32#define NM_TYPE_MODEM_GSM_MBM (nm_modem_gsm_mbm_get_type ())
33#define NM_MODEM_GSM_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_GSM_MBM, NMModemGsmMbm))
34#define NM_MODEM_GSM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_GSM_MBM, NMModemGsmMbmClass))
35#define NM_IS_MODEM_GSM_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_GSM_MBM))
36#define NM_IS_MODEM_GSM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_GSM_MBM))
37#define NM_MODEM_GSM_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_GSM_MBM, NMModemGsmMbmClass))
38
39typedef struct {
40 NMModemGsm parent;
41} NMModemGsmMbm;
42
43typedef struct {
44 NMModemGsmClass parent;
45} NMModemGsmMbmClass;
46
47GType nm_modem_gsm_mbm_get_type (void);
48
49NMDevice *nm_modem_gsm_mbm_new (const char *path,
50 const char *data_device,
51 const char *driver);
52
53G_END_DECLS
54
55#endif /* NM_MODEM_GSM_MBM_H */
diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c
new file mode 100644
index 0000000000..15231797e6
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm.c
@@ -0,0 +1,354 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#include <string.h>
4#include "nm-modem-gsm.h"
5#include "nm-device-private.h"
6#include "nm-device-interface.h"
7#include "nm-setting-connection.h"
8#include "nm-setting-gsm.h"
9#include "nm-modem-types.h"
10#include "nm-utils.h"
11
12#include "nm-device-gsm-glue.h"
13
14G_DEFINE_TYPE (NMModemGsm, nm_modem_gsm, NM_TYPE_MODEM)
15
16#define NM_MODEM_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GSM, NMModemGsmPrivate))
17
18enum {
19 MODEM_STATE_BEGIN,
20 MODEM_STATE_ENABLE,
21 MODEM_STATE_SET_PIN,
22 MODEM_STATE_SET_APN,
23 MODEM_STATE_SET_BAND,
24 MODEM_STATE_SET_NETWORK_MODE,
25 MODEM_STATE_REGISTER,
26 MODEM_STATE_FAILED,
27};
28
29typedef struct {
30 int modem_state;
31} NMModemGsmPrivate;
32
33NMDevice *
34nm_modem_gsm_new (const char *path,
35 const char *data_device,
36 const char *driver)
37{
38 g_return_val_if_fail (path != NULL, NULL);
39 g_return_val_if_fail (data_device != NULL, NULL);
40 g_return_val_if_fail (driver != NULL, NULL);
41
42 return (NMDevice *) g_object_new (NM_TYPE_MODEM_GSM,
43 NM_DEVICE_INTERFACE_UDI, path,
44 NM_DEVICE_INTERFACE_IFACE, data_device,
45 NM_DEVICE_INTERFACE_DRIVER, driver,
46 NM_DEVICE_INTERFACE_MANAGED, TRUE,
47 NM_MODEM_PATH, path,
48 NULL);
49}
50
51static NMSetting *
52get_setting (NMModemGsm *modem, GType setting_type)
53{
54 NMActRequest *req;
55 NMSetting *setting = NULL;
56
57 req = nm_device_get_act_request (NM_DEVICE (modem));
58 if (req) {
59 NMConnection *connection;
60
61 connection = nm_act_request_get_connection (req);
62 if (connection)
63 setting = nm_connection_get_setting (connection, setting_type);
64 }
65
66 return setting;
67}
68
69#define get_proxy(dev,iface) (nm_modem_get_proxy(NM_MODEM (dev), iface))
70
71static void
72state_machine (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
73{
74 NMModemGsm *modem = NM_MODEM_GSM (user_data);
75 NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (modem);
76 NMSettingGsm *setting;
77 const char *secret = NULL;
78 const char *secret_name = NULL;
79 const char *str;
80 GError *error = NULL;
81 int i;
82 gboolean retry_secret = FALSE;
83
84 setting = NM_SETTING_GSM (get_setting (modem, NM_TYPE_SETTING_GSM));
85
86 if (call_id)
87 dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID);
88
89 if (error) {
90 g_debug ("%s", dbus_g_error_get_name (error));
91
92 if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN)) {
93 secret = nm_setting_gsm_get_pin (setting);
94 secret_name = NM_SETTING_GSM_PIN;
95 priv->modem_state = MODEM_STATE_SET_PIN;
96 } else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PUK)) {
97 secret = nm_setting_gsm_get_puk (setting);
98 secret_name = NM_SETTING_GSM_PUK;
99 priv->modem_state = MODEM_STATE_SET_PIN;
100 } else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_WRONG)) {
101 g_object_set (setting, NM_SETTING_GSM_PIN, NULL, NULL);
102 secret_name = NM_SETTING_GSM_PIN;
103 retry_secret = TRUE;
104 priv->modem_state = MODEM_STATE_SET_PIN;
105 }
106
107 /* FIXME: Hacks to ignore failures of setting band and network mode for now
108 since only Huawei module supports it. Remove when ModemManager rules.
109 */
110 else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED) &&
111 (priv->modem_state == MODEM_STATE_SET_BAND ||
112 priv->modem_state == MODEM_STATE_SET_NETWORK_MODE)) {
113
114 nm_warning ("Modem does not support setting %s, ignoring",
115 priv->modem_state == MODEM_STATE_SET_BAND ? "band" : "network mode");
116 } else {
117 priv->modem_state = MODEM_STATE_FAILED;
118 nm_warning ("GSM modem connection failed: %s", error->message);
119 }
120
121 g_error_free (error);
122 }
123
124 again:
125
126 switch (priv->modem_state) {
127 case MODEM_STATE_BEGIN:
128 priv->modem_state = MODEM_STATE_ENABLE;
129 dbus_g_proxy_begin_call (get_proxy (modem, MM_DBUS_INTERFACE_MODEM),
130 "Enable", state_machine,
131 modem, NULL,
132 G_TYPE_BOOLEAN, TRUE,
133 G_TYPE_INVALID);
134 break;
135
136 case MODEM_STATE_SET_PIN:
137 if (secret) {
138 priv->modem_state = MODEM_STATE_ENABLE;
139 dbus_g_proxy_begin_call (get_proxy (modem, MM_DBUS_INTERFACE_MODEM_GSM_CARD),
140 "SendPin", state_machine,
141 modem, NULL,
142 G_TYPE_STRING, secret,
143 G_TYPE_INVALID);
144 } else {
145 nm_device_state_changed (NM_DEVICE (modem), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
146 nm_act_request_request_connection_secrets (nm_device_get_act_request (NM_DEVICE (modem)),
147 NM_SETTING_GSM_SETTING_NAME,
148 retry_secret,
149 SECRETS_CALLER_GSM,
150 secret_name,
151 NULL);
152
153 }
154 break;
155
156 case MODEM_STATE_ENABLE:
157 priv->modem_state = MODEM_STATE_SET_APN;
158 str = nm_setting_gsm_get_apn (setting);
159
160 if (str)
161 dbus_g_proxy_begin_call (get_proxy (modem, MM_DBUS_INTERFACE_MODEM_GSM_NETWORK),
162 "SetApn", state_machine,
163 modem, NULL,
164 G_TYPE_STRING, str,
165 G_TYPE_INVALID);
166 else
167 goto again;
168
169 break;
170 case MODEM_STATE_SET_APN:
171 priv->modem_state = MODEM_STATE_SET_BAND;
172 i = nm_setting_gsm_get_band (setting);
173
174 if (i)
175 dbus_g_proxy_begin_call (get_proxy (modem, MM_DBUS_INTERFACE_MODEM_GSM_NETWORK),
176 "SetBand", state_machine,
177 modem, NULL,
178 G_TYPE_UINT, (guint32) i,
179 G_TYPE_INVALID);
180 else
181 goto again;
182
183 break;
184
185 case MODEM_STATE_SET_BAND:
186 priv->modem_state = MODEM_STATE_SET_NETWORK_MODE;
187 i = nm_setting_gsm_get_network_type (setting);
188
189 if (i)
190 dbus_g_proxy_begin_call (get_proxy (modem, MM_DBUS_INTERFACE_MODEM_GSM_NETWORK),
191 "SetNetworkMode", state_machine,
192 modem, NULL,
193 G_TYPE_UINT, (guint32) i,
194 G_TYPE_INVALID);
195 else
196 goto again;
197
198 break;
199
200 case MODEM_STATE_SET_NETWORK_MODE:
201 priv->modem_state = MODEM_STATE_REGISTER;
202
203 str = nm_setting_gsm_get_network_id (setting);
204 dbus_g_proxy_begin_call_with_timeout (get_proxy (modem, MM_DBUS_INTERFACE_MODEM_GSM_NETWORK),
205 "Register", state_machine,
206 modem, NULL, 120000,
207 G_TYPE_STRING, str ? str : "",
208 G_TYPE_INVALID);
209 break;
210
211 case MODEM_STATE_REGISTER:
212 nm_modem_connect (NM_MODEM (modem), nm_setting_gsm_get_number (setting));
213 break;
214 case MODEM_STATE_FAILED:
215 default:
216 nm_device_state_changed (NM_DEVICE (modem), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE);
217 break;
218 }
219}
220
221static NMActStageReturn
222real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
223{
224 NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (device);
225
226 priv->modem_state = MODEM_STATE_BEGIN;
227 state_machine (NULL, NULL, device);
228
229 return NM_ACT_STAGE_RETURN_POSTPONE;
230}
231
232static NMConnection *
233real_get_best_auto_connection (NMDevice *dev,
234 GSList *connections,
235 char **specific_object)
236{
237 GSList *iter;
238
239 for (iter = connections; iter; iter = g_slist_next (iter)) {
240 NMConnection *connection = NM_CONNECTION (iter->data);
241 NMSettingConnection *s_con;
242
243 s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
244 g_assert (s_con);
245
246 if (!nm_setting_connection_get_autoconnect (s_con))
247 continue;
248
249 if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME))
250 continue;
251
252 return connection;
253 }
254 return NULL;
255}
256
257static void
258real_connection_secrets_updated (NMDevice *dev,
259 NMConnection *connection,
260 GSList *updated_settings,
261 RequestSecretsCaller caller)
262{
263 NMActRequest *req;
264 gboolean found = FALSE;
265 GSList *iter;
266
267 if (caller == SECRETS_CALLER_PPP) {
268 NMPPPManager *ppp_manager;
269 NMSettingGsm *s_gsm = NULL;
270
271 ppp_manager = nm_modem_get_ppp_manager (NM_MODEM (dev));
272 g_return_if_fail (ppp_manager != NULL);
273
274 s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
275 if (!s_gsm) {
276 /* Shouldn't ever happen */
277 nm_ppp_manager_update_secrets (ppp_manager,
278 nm_device_get_iface (dev),
279 NULL,
280 NULL,
281 "missing GSM setting; no secrets could be found.");
282 } else {
283 const char *username = nm_setting_gsm_get_username (s_gsm);
284 const char *password = nm_setting_gsm_get_password (s_gsm);
285
286 nm_ppp_manager_update_secrets (ppp_manager,
287 nm_device_get_iface (dev),
288 username ? username : "",
289 password ? password : "",
290 NULL);
291 }
292 return;
293 }
294
295 g_return_if_fail (caller == SECRETS_CALLER_GSM);
296 g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH);
297
298 for (iter = updated_settings; iter; iter = g_slist_next (iter)) {
299 const char *setting_name = (const char *) iter->data;
300
301 if (!strcmp (setting_name, NM_SETTING_GSM_SETTING_NAME))
302 found = TRUE;
303 else
304 nm_warning ("Ignoring updated secrets for setting '%s'.", setting_name);
305 }
306
307 if (!found)
308 return;
309
310 req = nm_device_get_act_request (dev);
311 g_assert (req);
312
313 g_return_if_fail (nm_act_request_get_connection (req) == connection);
314
315 nm_device_activate_schedule_stage1_device_prepare (dev);
316}
317
318static const char *
319real_get_ppp_name (NMModem *device, NMConnection *connection)
320{
321 NMSettingGsm *s_gsm;
322
323 s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
324 g_assert (s_gsm);
325
326 return nm_setting_gsm_get_username (s_gsm);
327}
328
329/*****************************************************************************/
330
331static void
332nm_modem_gsm_init (NMModemGsm *self)
333{
334 nm_device_set_device_type (NM_DEVICE (self), NM_DEVICE_TYPE_GSM);
335}
336
337static void
338nm_modem_gsm_class_init (NMModemGsmClass *klass)
339{
340 GObjectClass *object_class = G_OBJECT_CLASS (klass);
341 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
342 NMModemClass *modem_class = NM_MODEM_CLASS (klass);
343
344 g_type_class_add_private (object_class, sizeof (NMModemGsmPrivate));
345
346 /* Virtual methods */
347 device_class->get_best_auto_connection = real_get_best_auto_connection;
348 device_class->connection_secrets_updated = real_connection_secrets_updated;
349 device_class->act_stage1_prepare = real_act_stage1_prepare;
350 modem_class->get_ppp_name = real_get_ppp_name;
351
352 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
353 &dbus_glib_nm_device_gsm_object_info);
354}
diff --git a/src/modem-manager/nm-modem-gsm.h b/src/modem-manager/nm-modem-gsm.h
new file mode 100644
index 0000000000..50f08548e7
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm.h
@@ -0,0 +1,36 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#ifndef NM_MODEM_GSM_H
4#define NM_MODEM_GSM_H
5
6#include <nm-modem.h>
7
8G_BEGIN_DECLS
9
10#define NM_TYPE_MODEM_GSM (nm_modem_gsm_get_type ())
11#define NM_MODEM_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_GSM, NMModemGsm))
12#define NM_MODEM_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_GSM, NMModemGsmClass))
13#define NM_IS_MODEM_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_GSM))
14#define NM_IS_MODEM_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_GSM))
15#define NM_MODEM_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_GSM, NMModemGsmClass))
16
17typedef struct {
18 NMModem parent;
19} NMModemGsm;
20
21typedef struct {
22 NMModemClass parent;
23
24 /* Signals */
25 void (*signal_quality) (NMModemGsm *self, guint32 quality);
26} NMModemGsmClass;
27
28GType nm_modem_gsm_get_type (void);
29
30NMDevice *nm_modem_gsm_new (const char *path,
31 const char *data_device,
32 const char *driver);
33
34G_END_DECLS
35
36#endif /* NM_MODEM_GSM_H */
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
new file mode 100644
index 0000000000..85aaf713c4
--- /dev/null
+++ b/src/modem-manager/nm-modem-manager.c
@@ -0,0 +1,395 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#include <string.h>
4#include "nm-modem-manager.h"
5#include "nm-modem.h"
6#include "nm-modem-gsm.h"
7#include "nm-modem-gsm-hso.h"
8#include "nm-modem-gsm-mbm.h"
9#include "nm-modem-cdma.h"
10#include "nm-dbus-manager.h"
11#include "nm-utils.h"
12#include "nm-modem-types.h"
13
14#define MODEM_POKE_INTERVAL 120000
15
16G_DEFINE_TYPE (NMModemManager, nm_modem_manager, G_TYPE_OBJECT)
17
18#define NM_MODEM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_MANAGER, NMModemManagerPrivate))
19
20typedef struct {
21 NMDBusManager *dbus_mgr;
22 DBusGProxy *proxy;
23 GHashTable *modems;
24 gboolean disposed;
25 guint poke_id;
26} NMModemManagerPrivate;
27
28enum {
29 DEVICE_ADDED,
30 DEVICE_REMOVED,
31
32 LAST_SIGNAL
33};
34
35static guint signals[LAST_SIGNAL] = { 0 };
36
37
38NMModemManager *
39nm_modem_manager_get (void)
40{
41 static NMModemManager *singleton = NULL;
42
43 if (!singleton)
44 singleton = NM_MODEM_MANAGER (g_object_new (NM_TYPE_MODEM_MANAGER, NULL));
45 else
46 g_object_ref (singleton);
47
48 g_assert (singleton);
49 return singleton;
50}
51
52static gboolean
53get_modem_properties (DBusGConnection *connection,
54 const char *path,
55 char **data_device,
56 char **driver,
57 guint32 *type)
58{
59 DBusGProxy *proxy;
60 GValue value = { 0 };
61 GError *err = NULL;
62
63 proxy = dbus_g_proxy_new_for_name (connection,
64 MM_DBUS_SERVICE,
65 path,
66 "org.freedesktop.DBus.Properties");
67
68 if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
69 G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
70 G_TYPE_STRING, "Type",
71 G_TYPE_INVALID,
72 G_TYPE_VALUE, &value,
73 G_TYPE_INVALID)) {
74 *type = g_value_get_uint (&value);
75 g_value_unset (&value);
76 } else {
77 g_warning ("Could not get device type: %s", err->message);
78 goto out;
79 }
80
81 if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
82 G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
83 G_TYPE_STRING, "DataDevice",
84 G_TYPE_INVALID,
85 G_TYPE_VALUE, &value,
86 G_TYPE_INVALID)) {
87 *data_device = g_value_dup_string (&value);
88 g_value_unset (&value);
89 } else {
90 g_warning ("Could not get modem data device: %s", err->message);
91 goto out;
92 }
93
94 if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
95 G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
96 G_TYPE_STRING, "Driver",
97 G_TYPE_INVALID,
98 G_TYPE_VALUE, &value,
99 G_TYPE_INVALID)) {
100 *driver = g_value_dup_string (&value);
101 g_value_unset (&value);
102 } else {
103 g_warning ("Could not get modem driver: %s", err->message);
104 goto out;
105 }
106
107 out:
108 if (err)
109 g_error_free (err);
110
111 g_object_unref (proxy);
112
113 return *data_device && *driver;
114}
115
116static void
117create_modem (NMModemManager *manager, const char *path)
118{
119 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (manager);
120 NMDevice *device;
121 char *data_device = NULL;
122 char *driver = NULL;
123 uint modem_type = MM_MODEM_TYPE_UNKNOWN;
124
125 if (g_hash_table_lookup (priv->modems, path)) {
126 nm_warning ("Modem with path %s already exists, ignoring", path);
127 return;
128 }
129
130 if (!get_modem_properties (nm_dbus_manager_get_connection (priv->dbus_mgr), path,
131 &data_device, &driver, &modem_type))
132 return;
133
134 if (modem_type == MM_MODEM_TYPE_UNKNOWN) {
135 nm_warning ("Modem with path %s has unknown type, ignoring", path);
136 return;
137 }
138
139 if (!driver || !strlen (driver)) {
140 nm_warning ("Modem with path %s has unknown driver, ignoring", path);
141 return;
142 }
143
144 if (!data_device || !strlen (data_device)) {
145 nm_warning ("Modem with path %s has unknown data device, ignoring", path);
146 return;
147 }
148
149 if (modem_type == MM_MODEM_TYPE_GSM) {
150 if (!strcmp (driver, "hso"))
151 device = nm_modem_gsm_hso_new (path, data_device, driver);
152 else if (!strcmp (driver, "mbm"))
153 device = nm_modem_gsm_mbm_new (path, data_device, driver);
154 else
155 device = nm_modem_gsm_new (path, data_device, driver);
156 } else if (modem_type == MM_MODEM_TYPE_CDMA)
157 device = nm_modem_cdma_new (path, data_device, driver);
158 else
159 g_error ("Invalid modem type");
160
161 g_free (data_device);
162 g_free (driver);
163
164 if (device) {
165 g_hash_table_insert (priv->modems, g_strdup (path), device);
166 g_signal_emit (manager, signals[DEVICE_ADDED], 0, device);
167 }
168}
169
170static void
171modem_added (DBusGProxy *proxy, const char *path, gpointer user_data)
172{
173 create_modem (NM_MODEM_MANAGER (user_data), path);
174}
175
176static void
177modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
178{
179 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (user_data);
180 NMModem *modem;
181
182 modem = (NMModem *) g_hash_table_lookup (priv->modems, path);
183 if (modem) {
184 g_signal_emit (user_data, signals[DEVICE_REMOVED], 0, modem);
185 g_hash_table_remove (priv->modems, path);
186 }
187}
188
189static gboolean
190poke_modem_cb (gpointer user_data)
191{
192 NMModemManager *self = NM_MODEM_MANAGER (user_data);
193 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
194 DBusGConnection *g_connection;
195 DBusGProxy *proxy;
196
197 g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
198 proxy = dbus_g_proxy_new_for_name (g_connection,
199 MM_DBUS_SERVICE,
200 MM_DBUS_PATH,
201 MM_DBUS_INTERFACE);
202
203 nm_info ("Trying to start the modem-manager...");
204 dbus_g_proxy_call_no_reply (proxy, "EnumerateDevices", G_TYPE_INVALID);
205 g_object_unref (proxy);
206
207 return TRUE;
208}
209
210static void
211enumerate_devices_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer data)
212{
213 NMModemManager *manager = NM_MODEM_MANAGER (data);
214 GPtrArray *modems;
215 GError *error = NULL;
216
217 if (!dbus_g_proxy_end_call (proxy, call_id, &error,
218 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &modems,
219 G_TYPE_INVALID)) {
220 nm_warning ("Could not get modem list: %s", error->message);
221 g_error_free (error);
222 } else {
223 int i;
224
225 for (i = 0; i < modems->len; i++) {
226 char *path = (char *) g_ptr_array_index (modems, i);
227
228 create_modem (manager, path);
229 g_free (path);
230 }
231
232 g_ptr_array_free (modems, TRUE);
233 }
234}
235
236static void
237modem_manager_appeared (NMModemManager *self, gboolean enumerate_devices)
238{
239 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
240
241 if (priv->poke_id) {
242 g_source_remove (priv->poke_id);
243 priv->poke_id = 0;
244 }
245
246 priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
247 MM_DBUS_SERVICE, MM_DBUS_PATH, MM_DBUS_INTERFACE);
248
249 dbus_g_proxy_add_signal (priv->proxy, "DeviceAdded", G_TYPE_STRING, G_TYPE_INVALID);
250 dbus_g_proxy_connect_signal (priv->proxy, "DeviceAdded",
251 G_CALLBACK (modem_added), self,
252 NULL);
253
254 dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", G_TYPE_STRING, G_TYPE_INVALID);
255 dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved",
256 G_CALLBACK (modem_removed), self,
257 NULL);
258
259 if (enumerate_devices)
260 dbus_g_proxy_begin_call (priv->proxy, "EnumerateDevices", enumerate_devices_done, self, NULL, G_TYPE_INVALID);
261}
262
263static gboolean
264remove_one_modem (gpointer key, gpointer value, gpointer user_data)
265{
266 g_signal_emit (user_data, signals[DEVICE_REMOVED], 0, value);
267
268 return TRUE;
269}
270
271static void
272modem_manager_disappeared (NMModemManager *self)
273{
274 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
275
276 g_hash_table_foreach_remove (priv->modems, remove_one_modem, self);
277
278 if (priv->proxy) {
279 g_object_unref (priv->proxy);
280 priv->proxy = NULL;
281 }
282
283 /* Try to activate the modem-manager */
284 poke_modem_cb (self);
285 priv->poke_id = g_timeout_add (MODEM_POKE_INTERVAL, poke_modem_cb, self);
286}
287
288static void
289nm_modem_manager_name_owner_changed (NMDBusManager *dbus_mgr,
290 const char *name,
291 const char *old_owner,
292 const char *new_owner,
293 gpointer user_data)
294{
295 gboolean old_owner_good;
296 gboolean new_owner_good;
297
298 /* Can't handle the signal if its not from the modem service */
299 if (strcmp (MM_DBUS_SERVICE, name) != 0)
300 return;
301
302 old_owner_good = (old_owner && strlen (old_owner));
303 new_owner_good = (new_owner && strlen (new_owner));
304
305 if (!old_owner_good && new_owner_good) {
306 nm_info ("modem manager appeared");
307 modem_manager_appeared (NM_MODEM_MANAGER (user_data), FALSE);
308 } else if (old_owner_good && !new_owner_good) {
309 nm_info ("modem manager disappeared");
310 modem_manager_disappeared (NM_MODEM_MANAGER (user_data));
311 }
312}
313
314/*******************************************************/
315
316static void
317nm_modem_manager_init (NMModemManager *self)
318{
319 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
320
321 priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
322 priv->dbus_mgr = nm_dbus_manager_get ();
323
324 g_signal_connect (priv->dbus_mgr, "name-owner-changed",
325 G_CALLBACK (nm_modem_manager_name_owner_changed),
326 self);
327
328 if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_DBUS_SERVICE))
329 modem_manager_appeared (self, TRUE);
330 else
331 modem_manager_disappeared (self);
332}
333
334static void
335dispose (GObject *object)
336{
337 NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (object);
338
339 if (priv->disposed)
340 return;
341
342 priv->disposed = TRUE;
343
344 if (priv->poke_id) {
345 g_source_remove (priv->poke_id);
346 priv->poke_id = 0;
347 }
348
349 g_hash_table_foreach_remove (priv->modems, remove_one_modem, object);
350 g_hash_table_destroy (priv->modems);
351
352 if (priv->proxy) {
353 g_object_unref (priv->proxy);
354 priv->proxy = NULL;
355 }
356
357 if (priv->dbus_mgr) {
358 g_object_unref (priv->dbus_mgr);
359 priv->dbus_mgr = NULL;
360 }
361
362 /* Chain up to the parent class */
363 G_OBJECT_CLASS (nm_modem_manager_parent_class)->dispose (object);
364}
365
366static void
367nm_modem_manager_class_init (NMModemManagerClass *klass)
368{
369 GObjectClass *object_class = G_OBJECT_CLASS (klass);
370
371 g_type_class_add_private (object_class, sizeof (NMModemManagerPrivate));
372
373 object_class->dispose = dispose;
374
375 /* signals */
376 signals[DEVICE_ADDED] =
377 g_signal_new ("device-added",
378 G_OBJECT_CLASS_TYPE (object_class),
379 G_SIGNAL_RUN_FIRST,
380 G_STRUCT_OFFSET (NMModemManagerClass, device_added),
381 NULL, NULL,
382 g_cclosure_marshal_VOID__OBJECT,
383 G_TYPE_NONE, 1,
384 G_TYPE_OBJECT);
385
386 signals[DEVICE_REMOVED] =
387 g_signal_new ("device-removed",
388 G_OBJECT_CLASS_TYPE (object_class),
389 G_SIGNAL_RUN_FIRST,
390 G_STRUCT_OFFSET (NMModemManagerClass, device_removed),
391 NULL, NULL,
392 g_cclosure_marshal_VOID__OBJECT,
393 G_TYPE_NONE, 1,
394 G_TYPE_OBJECT);
395}
diff --git a/src/modem-manager/nm-modem-manager.h b/src/modem-manager/nm-modem-manager.h
new file mode 100644
index 0000000000..fb51f73988
--- /dev/null
+++ b/src/modem-manager/nm-modem-manager.h
@@ -0,0 +1,35 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#ifndef NM_MODEM_MANAGER_H
4#define NM_MODEM_MANAGER_H
5
6#include <glib-object.h>
7#include "nm-device.h"
8
9#define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type ())
10#define NM_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_MANAGER, NMModemManager))
11#define NM_MODEM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass))
12#define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_MANAGER))
13#define NM_IS_MODEM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_MANAGER))
14#define NM_MODEM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_MANAGER, NMModemManagerClass))
15
16typedef struct {
17 GObject parent;
18} NMModemManager;
19
20typedef struct {
21 GObjectClass parent;
22
23 /* Signals */
24 void (*device_added) (NMModemManager *manager,
25 NMDevice *device);
26
27 void (*device_removed) (NMModemManager *manager,
28 NMDevice *device);
29} NMModemManagerClass;
30
31GType nm_modem_manager_get_type (void);
32
33NMModemManager *nm_modem_manager_get (void);
34
35#endif /* NM_MODEM_MANAGER_H */
diff --git a/src/modem-manager/nm-modem-types.h b/src/modem-manager/nm-modem-types.h
new file mode 100644
index 0000000000..4a5dad42ec
--- /dev/null
+++ b/src/modem-manager/nm-modem-types.h
@@ -0,0 +1,90 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#ifndef NM_MODEM_TYPES_H
4#define NM_MODEM_TYPES_H
5
6#define MM_DBUS_SERVICE "org.freedesktop.ModemManager"
7#define MM_DBUS_PATH "/org/freedesktop/ModemManager"
8#define MM_DBUS_INTERFACE "org.freedesktop.ModemManager"
9#define MM_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem"
10#define MM_DBUS_INTERFACE_MODEM_CDMA "org.freedesktop.ModemManager.Modem.Cdma"
11
12#define MM_DBUS_INTERFACE_MODEM_GSM_CARD "org.freedesktop.ModemManager.Modem.Gsm.Card"
13#define MM_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network"
14#define MM_DBUS_INTERFACE_MODEM_GSM_HSO "org.freedesktop.ModemManager.Modem.Gsm.Hso"
15#define MM_DBUS_INTERFACE_MODEM_GSM_MBM "org.freedesktop.ModemManager.Modem.Gsm.Mbm"
16
17#define MM_MODEM_TYPE_UNKNOWN 0
18#define MM_MODEM_TYPE_GSM 1
19#define MM_MODEM_TYPE_CDMA 2
20
21/* Errors */
22
23#define MM_SERIAL_OPEN_FAILED MM_DBUS_INTERFACE_MODEM ".SerialOpenFailed"
24#define MM_SERIAL_SEND_FAILED MM_DBUS_INTERFACE_MODEM ".SerialSendFailed"
25#define MM_SERIAL_RESPONSE_TIMEOUT MM_DBUS_INTERFACE_MODEM ".SerialResponseTimeout"
26
27#define MM_MODEM_ERROR_GENERAL MM_DBUS_INTERFACE_MODEM ".General"
28#define MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED MM_DBUS_INTERFACE_MODEM ".OperationNotSupported"
29
30#define MM_MODEM_CONNECT_ERROR_NO_CARRIER MM_DBUS_INTERFACE_MODEM ".NoCarrier"
31#define MM_MODEM_CONNECT_ERROR_NO_DIALTONE MM_DBUS_INTERFACE_MODEM ".NoDialtone"
32#define MM_MODEM_CONNECT_ERROR_BUSY MM_DBUS_INTERFACE_MODEM ".Busy"
33#define MM_MODEM_CONNECT_ERROR_NO_ANSWER MM_DBUS_INTERFACE_MODEM ".NoAnswer"
34
35#define MM_MODEM_ERROR "org.freedesktop.ModemManager.Modem.Gsm"
36
37#define MM_MODEM_ERROR_PHONE_FAILURE MM_MODEM_ERROR ".PhoneFailure"
38#define MM_MODEM_ERROR_NO_CONNECTION MM_MODEM_ERROR ".NoConnection"
39#define MM_MODEM_ERROR_LINK_RESERVED MM_MODEM_ERROR ".LinkReserved"
40#define MM_MODEM_ERROR_NOT_ALLOWED MM_MODEM_ERROR ".OperationNotAllowed"
41#define MM_MODEM_ERROR_NOT_SUPPORTED MM_MODEM_ERROR ".OperationNotSupported"
42#define MM_MODEM_ERROR_PH_SIM_PIN MM_MODEM_ERROR ".PhSimPinRequired"
43#define MM_MODEM_ERROR_PH_FSIM_PIN MM_MODEM_ERROR ".PhFSimPinRequired"
44#define MM_MODEM_ERROR_PH_FSIM_PUK MM_MODEM_ERROR ".PhFPukRequired"
45#define MM_MODEM_ERROR_SIM_NOT_INSERTED MM_MODEM_ERROR ".SimNotInserted"
46#define MM_MODEM_ERROR_SIM_PIN MM_MODEM_ERROR ".SimPinRequired"
47#define MM_MODEM_ERROR_SIM_PUK MM_MODEM_ERROR ".SimPukRequired"
48#define MM_MODEM_ERROR_SIM_FAILURE MM_MODEM_ERROR ".SimFailure"
49#define MM_MODEM_ERROR_SIM_BUSY MM_MODEM_ERROR ".SimBusy"
50#define MM_MODEM_ERROR_SIM_WRONG MM_MODEM_ERROR ".SimWrong"
51#define MM_MODEM_ERROR_WRONG_PASSWORD MM_MODEM_ERROR ".IncorrectPassword"
52#define MM_MODEM_ERROR_SIM_PIN2 MM_MODEM_ERROR ".SimPin2Required"
53#define MM_MODEM_ERROR_SIM_PUK2 MM_MODEM_ERROR ".SimPuk2Required"
54#define MM_MODEM_ERROR_MEMORY_FULL MM_MODEM_ERROR ".MemoryFull"
55#define MM_MODEM_ERROR_INVALID_INDEX MM_MODEM_ERROR ".InvalidIndex"
56#define MM_MODEM_ERROR_NOT_FOUND MM_MODEM_ERROR ".NotFound"
57#define MM_MODEM_ERROR_MEMORY_FAILURE MM_MODEM_ERROR ".MemoryFailure"
58#define MM_MODEM_ERROR_TEXT_TOO_LONG MM_MODEM_ERROR ".TextTooLong"
59#define MM_MODEM_ERROR_INVALID_CHARS MM_MODEM_ERROR ".InvalidChars"
60#define MM_MODEM_ERROR_DIAL_STRING_TOO_LONG MM_MODEM_ERROR ".DialStringTooLong"
61#define MM_MODEM_ERROR_DIAL_STRING_INVALID MM_MODEM_ERROR ".InvalidDialString"
62#define MM_MODEM_ERROR_NO_NETWORK MM_MODEM_ERROR ".NoNetwork"
63#define MM_MODEM_ERROR_NETWORK_TIMEOUT MM_MODEM_ERROR ".NetworkTimeout"
64#define MM_MODEM_ERROR_NETWORK_NOT_ALLOWED MM_MODEM_ERROR ".NetworkNotAllowed"
65#define MM_MODEM_ERROR_NETWORK_PIN MM_MODEM_ERROR ".NetworkPinRequired"
66#define MM_MODEM_ERROR_NETWORK_PUK MM_MODEM_ERROR ".NetworkPukRequired"
67#define MM_MODEM_ERROR_NETWORK_SUBSET_PIN MM_MODEM_ERROR ".NetworkSubsetPinRequired"
68#define MM_MODEM_ERROR_NETWORK_SUBSET_PUK MM_MODEM_ERROR ".NetworkSubsetPukRequired"
69#define MM_MODEM_ERROR_SERVICE_PIN MM_MODEM_ERROR ".ServicePinRequired"
70#define MM_MODEM_ERROR_SERVICE_PUK MM_MODEM_ERROR ".ServicePukRequired"
71#define MM_MODEM_ERROR_CORP_PIN MM_MODEM_ERROR ".CorporatePinRequired"
72#define MM_MODEM_ERROR_CORP_PUK MM_MODEM_ERROR ".CorporatePukRequired"
73#define MM_MODEM_ERROR_HIDDEN_KEY MM_MODEM_ERROR ".HiddenKeyRequired"
74#define MM_MODEM_ERROR_EAP_NOT_SUPPORTED MM_MODEM_ERROR ".EapMethodNotSupported"
75#define MM_MODEM_ERROR_INCORRECT_PARAMS MM_MODEM_ERROR ".IncorrectParams"
76#define MM_MODEM_ERROR_UNKNOWN MM_MODEM_ERROR ".Unknown"
77#define MM_MODEM_ERROR_GPRS_ILLEGAL_MS MM_MODEM_ERROR ".GprsIllegalMs"
78#define MM_MODEM_ERROR_GPRS_ILLEGAL_ME MM_MODEM_ERROR ".GprsIllegalMe"
79#define MM_MODEM_ERROR_GPRS_SERVICE_NOT_ALLOWED MM_MODEM_ERROR ".GprsServiceNotAllowed"
80#define MM_MODEM_ERROR_GPRS_PLMN_NOT_ALLOWED MM_MODEM_ERROR ".GprsPlmnNotAllowed"
81#define MM_MODEM_ERROR_GPRS_LOCATION_NOT_ALLOWED MM_MODEM_ERROR ".GprsLocationNotAllowed"
82#define MM_MODEM_ERROR_GPRS_ROAMING_NOT_ALLOWED MM_MODEM_ERROR ".GprsRoamingNotAllowed"
83#define MM_MODEM_ERROR_GPRS_OPTION_NOT_SUPPORTED MM_MODEM_ERROR ".GprsOptionNotSupported"
84#define MM_MODEM_ERROR_GPRS_NOT_SUBSCRIBED MM_MODEM_ERROR ".GprsNotSubscribed"
85#define MM_MODEM_ERROR_GPRS_OUT_OF_ORDER MM_MODEM_ERROR ".GprsOutOfOrder"
86#define MM_MODEM_ERROR_GPRS_PDP_AUTH_FAILURE MM_MODEM_ERROR ".GprsPdpAuthFailure"
87#define MM_MODEM_ERROR_GPRS_UNKNOWN MM_MODEM_ERROR ".GprsUnspecified"
88#define MM_MODEM_ERROR_GPRS_INVALID_CLASS MM_MODEM_ERROR ".GprsInvalidClass"
89
90#endif /* NM_MODEM_TYPES_H */
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
new file mode 100644
index 0000000000..fddfd059fd
--- /dev/null
+++ b/src/modem-manager/nm-modem.c
@@ -0,0 +1,457 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#include <string.h>
4#include "nm-modem.h"
5#include "nm-device-private.h"
6#include "nm-device-interface.h"
7#include "nm-dbus-manager.h"
8#include "nm-setting-connection.h"
9#include "nm-setting-gsm.h"
10#include "nm-setting-cdma.h"
11#include "nm-marshal.h"
12#include "nm-properties-changed-signal.h"
13#include "nm-modem-types.h"
14#include "nm-utils.h"
15#include "nm-serial-device-glue.h"
16
17G_DEFINE_TYPE (NMModem, nm_modem, NM_TYPE_DEVICE)
18
19#define NM_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM, NMModemPrivate))
20
21enum {
22 PROP_0,
23 PROP_PATH,
24
25 LAST_PROP
26};
27
28typedef struct {
29 NMDBusManager *dbus_mgr;
30 char *path;
31 DBusGProxy *proxy;
32 NMPPPManager *ppp_manager;
33 NMIP4Config *pending_ip4_config;
34
35 guint state_to_disconnected_id;
36
37 /* PPP stats */
38 guint32 in_bytes;
39 guint32 out_bytes;
40} NMModemPrivate;
41
42enum {
43 PPP_STATS,
44 PROPERTIES_CHANGED,
45
46 LAST_SIGNAL
47};
48
49static guint signals[LAST_SIGNAL] = { 0 };
50
51NMPPPManager *
52nm_modem_get_ppp_manager (NMModem *self)
53{
54 g_return_val_if_fail (NM_IS_MODEM (self), NULL);
55
56 return NM_MODEM_GET_PRIVATE (self)->ppp_manager;
57}
58
59DBusGProxy *
60nm_modem_get_proxy (NMModem *self,
61 const char *interface)
62{
63
64 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
65 const char *current_iface;
66
67 g_return_val_if_fail (NM_IS_MODEM (self), NULL);
68
69 /* Default to the default interface. */
70 if (interface == NULL)
71 interface = MM_DBUS_INTERFACE_MODEM;
72
73 current_iface = dbus_g_proxy_get_interface (priv->proxy);
74 if (!current_iface || strcmp (current_iface, interface))
75 dbus_g_proxy_set_interface (priv->proxy, interface);
76
77 return priv->proxy;
78}
79
80void
81nm_modem_connect (NMModem *self,
82 const char *number)
83{
84 g_return_if_fail (NM_IS_MODEM (self));
85
86 NM_MODEM_GET_CLASS (self)->connect (self, number);
87}
88
89const char *
90nm_modem_get_ppp_name (NMModem *self,
91 NMConnection *connection)
92{
93 g_return_val_if_fail (NM_IS_MODEM (self), NULL);
94 g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
95
96 if (NM_MODEM_GET_CLASS (self)->get_ppp_name)
97 return NM_MODEM_GET_CLASS (self)->get_ppp_name (self, connection);
98
99 return NULL;
100}
101
102static void
103ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data)
104{
105 NMDevice *device = NM_DEVICE (user_data);
106
107 switch (status) {
108 case NM_PPP_STATUS_NETWORK:
109 nm_device_state_changed (device, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
110 break;
111 case NM_PPP_STATUS_DISCONNECT:
112 nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT);
113 break;
114 case NM_PPP_STATUS_DEAD:
115 nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED);
116 break;
117 case NM_PPP_STATUS_AUTHENTICATE:
118 nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
119 break;
120 default:
121 break;
122 }
123}
124
125static void
126ppp_ip4_config (NMPPPManager *ppp_manager,
127 const char *iface,
128 NMIP4Config *config,
129 gpointer user_data)
130{
131 NMDevice *device = NM_DEVICE (user_data);
132
133 nm_device_set_ip_iface (device, iface);
134 NM_MODEM_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config);
135 nm_device_activate_schedule_stage4_ip_config_get (device);
136}
137
138static void
139ppp_stats (NMPPPManager *ppp_manager,
140 guint32 in_bytes,
141 guint32 out_bytes,
142 gpointer user_data)
143{
144 NMModem *self = NM_MODEM (user_data);
145 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
146
147 if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) {
148 priv->in_bytes = in_bytes;
149 priv->out_bytes = out_bytes;
150
151 g_signal_emit (self, signals[PPP_STATS], 0, in_bytes, out_bytes);
152 }
153}
154
155static NMActStageReturn
156real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
157{
158 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device);
159 NMActRequest *req;
160 const char *ppp_name = NULL;
161 GError *err = NULL;
162 NMActStageReturn ret;
163
164 req = nm_device_get_act_request (device);
165 g_assert (req);
166
167 ppp_name = nm_modem_get_ppp_name (NM_MODEM (device),
168 nm_act_request_get_connection (req));
169
170 priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (device));
171 if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, &err)) {
172 g_signal_connect (priv->ppp_manager, "state-changed",
173 G_CALLBACK (ppp_state_changed),
174 device);
175 g_signal_connect (priv->ppp_manager, "ip4-config",
176 G_CALLBACK (ppp_ip4_config),
177 device);
178 g_signal_connect (priv->ppp_manager, "stats",
179 G_CALLBACK (ppp_stats),
180 device);
181
182 ret = NM_ACT_STAGE_RETURN_POSTPONE;
183 } else {
184 nm_warning ("%s", err->message);
185 g_error_free (err);
186
187 g_object_unref (priv->ppp_manager);
188 priv->ppp_manager = NULL;
189
190 *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
191 ret = NM_ACT_STAGE_RETURN_FAILURE;
192 }
193
194 return ret;
195}
196
197static NMActStageReturn
198real_act_stage4_get_ip4_config (NMDevice *device,
199 NMIP4Config **config,
200 NMDeviceStateReason *reason)
201{
202 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device);
203
204 *config = priv->pending_ip4_config;
205 priv->pending_ip4_config = NULL;
206
207 return NM_ACT_STAGE_RETURN_SUCCESS;
208}
209
210static void
211real_deactivate_quickly (NMDevice *device)
212{
213 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device);
214
215 nm_device_set_ip_iface (device, NULL);
216
217 if (priv->pending_ip4_config) {
218 g_object_unref (priv->pending_ip4_config);
219 priv->pending_ip4_config = NULL;
220 }
221
222 priv->in_bytes = priv->out_bytes = 0;
223
224 if (priv->ppp_manager) {
225 g_object_unref (priv->ppp_manager);
226 priv->ppp_manager = NULL;
227 }
228
229 dbus_g_proxy_call_no_reply (nm_modem_get_proxy (NM_MODEM (device), NULL),
230 "Enable", G_TYPE_BOOLEAN, FALSE, G_TYPE_INVALID);
231}
232
233static guint32
234real_get_generic_capabilities (NMDevice *dev)
235{
236 return NM_DEVICE_CAP_NM_SUPPORTED;
237}
238
239
240static void
241connect_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
242{
243 NMDevice *device = NM_DEVICE (user_data);
244 GError *error = NULL;
245
246 if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID))
247 nm_device_activate_schedule_stage2_device_config (device);
248 else {
249 nm_warning ("Connect failed: %s", error->message);
250 g_error_free (error);
251 nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED);
252 }
253}
254
255static void
256real_connect (NMModem *modem, const char *number)
257{
258 dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM),
259 "Connect", connect_done,
260 modem, NULL, 60000,
261 G_TYPE_STRING, number ? number : "",
262 G_TYPE_INVALID);
263}
264
265static gboolean
266unavailable_to_disconnected (gpointer user_data)
267{
268 nm_device_state_changed (NM_DEVICE (user_data),
269 NM_DEVICE_STATE_DISCONNECTED,
270 NM_DEVICE_STATE_REASON_NONE);
271 return FALSE;
272}
273
274static void
275device_state_changed (NMDeviceInterface *device,
276 NMDeviceState new_state,
277 NMDeviceState old_state,
278 NMDeviceStateReason reason,
279 gpointer user_data)
280{
281 NMModem *self = NM_MODEM (user_data);
282 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
283
284 /* Remove any previous delayed transition to disconnected */
285 if (priv->state_to_disconnected_id) {
286 g_source_remove (priv->state_to_disconnected_id);
287 priv->state_to_disconnected_id = 0;
288 }
289
290 /* If transitioning to UNAVAILBLE and we have a carrier, transition to
291 * DISCONNECTED because the device is ready to use. Otherwise the carrier-on
292 * handler will handle the transition to DISCONNECTED when the carrier is detected.
293 */
294 if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
295 priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, user_data);
296
297 /* Make sure we don't leave the serial device open */
298 switch (new_state) {
299 case NM_DEVICE_STATE_NEED_AUTH:
300 if (priv->ppp_manager)
301 break;
302 /* else fall through */
303 case NM_DEVICE_STATE_UNMANAGED:
304 case NM_DEVICE_STATE_UNAVAILABLE:
305 case NM_DEVICE_STATE_FAILED:
306 case NM_DEVICE_STATE_DISCONNECTED:
307 dbus_g_proxy_call_no_reply (nm_modem_get_proxy (self, NULL),
308 "Disconnect", G_TYPE_INVALID);
309 break;
310 default:
311 break;
312 }
313}
314
315/*****************************************************************************/
316
317static void
318nm_modem_init (NMModem *self)
319{
320 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
321
322 priv->dbus_mgr = nm_dbus_manager_get ();
323}
324
325static GObject*
326constructor (GType type,
327 guint n_construct_params,
328 GObjectConstructParam *construct_params)
329{
330 GObject *object;
331 NMModemPrivate *priv;
332
333 object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type,
334 n_construct_params,
335 construct_params);
336 if (!object)
337 return NULL;
338
339 priv = NM_MODEM_GET_PRIVATE (object);
340
341 if (!priv->path) {
342 g_warning ("DBus path not provided");
343 goto err;
344 }
345
346 priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
347 MM_DBUS_SERVICE, priv->path, MM_DBUS_INTERFACE_MODEM);
348
349 g_signal_connect (object, "state-changed", G_CALLBACK (device_state_changed), object);
350
351 return object;
352
353 err:
354 g_object_unref (object);
355 return NULL;
356}
357
358static void
359get_property (GObject *object, guint prop_id,
360 GValue *value, GParamSpec *pspec)
361{
362 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
363
364 switch (prop_id) {
365 case PROP_PATH:
366 g_value_set_string (value, priv->path);
367 break;
368 default:
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 break;
371 }
372
373}
374
375static void
376set_property (GObject *object, guint prop_id,
377 const GValue *value, GParamSpec *pspec)
378{
379 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
380
381 switch (prop_id) {
382 case PROP_PATH:
383 /* Construct only */
384 priv->path = g_value_dup_string (value);
385 break;
386 default:
387 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
388 break;
389 }
390}
391
392static void
393finalize (GObject *object)
394{
395 NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
396
397 if (priv->state_to_disconnected_id) {
398 g_source_remove (priv->state_to_disconnected_id);
399 priv->state_to_disconnected_id = 0;
400 }
401
402 if (priv->proxy)
403 g_object_unref (priv->proxy);
404
405 g_object_unref (priv->dbus_mgr);
406
407 G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object);
408}
409
410static void
411nm_modem_class_init (NMModemClass *klass)
412{
413 GObjectClass *object_class = G_OBJECT_CLASS (klass);
414 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
415
416 g_type_class_add_private (object_class, sizeof (NMModemPrivate));
417
418 /* Virtual methods */
419 object_class->constructor = constructor;
420 object_class->set_property = set_property;
421 object_class->get_property = get_property;
422 object_class->finalize = finalize;
423
424 device_class->get_generic_capabilities = real_get_generic_capabilities;
425 device_class->act_stage2_config = real_act_stage2_config;
426 device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
427 device_class->deactivate_quickly = real_deactivate_quickly;
428
429 klass->connect = real_connect;
430
431 /* Properties */
432 g_object_class_install_property
433 (object_class, PROP_PATH,
434 g_param_spec_string (NM_MODEM_PATH,
435 "DBus path",
436 "DBus path",
437 NULL,
438 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
439
440 /* Signals */
441 signals[PPP_STATS] =
442 g_signal_new ("ppp-stats",
443 G_OBJECT_CLASS_TYPE (object_class),
444 G_SIGNAL_RUN_FIRST,
445 G_STRUCT_OFFSET (NMModemClass, ppp_stats),
446 NULL, NULL,
447 _nm_marshal_VOID__UINT_UINT,
448 G_TYPE_NONE, 2,
449 G_TYPE_UINT, G_TYPE_UINT);
450
451 signals[PROPERTIES_CHANGED] =
452 nm_properties_changed_signal_new (object_class,
453 G_STRUCT_OFFSET (NMModemClass, properties_changed));
454
455 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
456 &dbus_glib_nm_serial_device_object_info);
457}
diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h
new file mode 100644
index 0000000000..36b9bd8202
--- /dev/null
+++ b/src/modem-manager/nm-modem.h
@@ -0,0 +1,55 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3#ifndef NM_MODEM_H
4#define NM_MODEM_H
5
6#include <dbus/dbus-glib.h>
7#include <nm-device.h>
8#include "ppp-manager/nm-ppp-manager.h"
9
10G_BEGIN_DECLS
11
12#define NM_TYPE_MODEM (nm_modem_get_type ())
13#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM, NMModem))
14#define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM, NMModemClass))
15#define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM))
16#define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM))
17#define NM_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM, NMModemClass))
18
19#define NM_MODEM_PATH "path"
20
21typedef struct {
22 NMDevice parent;
23} NMModem;
24
25typedef struct {
26 NMDeviceClass parent;
27
28 void (*connect) (NMModem *self,
29 const char *number);
30
31 const char *(*get_ppp_name) (NMModem *self,
32 NMConnection *connection);
33
34 /* Signals */
35 void (*ppp_stats) (NMModem *self, guint32 in_bytes, guint32 out_bytes);
36 void (*properties_changed) (NMModem *self, GHashTable *properties);
37} NMModemClass;
38
39GType nm_modem_get_type (void);
40
41/* Protected */
42
43NMPPPManager *nm_modem_get_ppp_manager (NMModem *self);
44DBusGProxy *nm_modem_get_proxy (NMModem *self,
45 const char *interface);
46
47void nm_modem_connect (NMModem *self,
48 const char *number);
49
50const char *nm_modem_get_ppp_name (NMModem *self,
51 NMConnection *connection);
52
53G_END_DECLS
54
55#endif /* NM_MODEM_H */
diff --git a/src/nm-cdma-device.c b/src/nm-cdma-device.c
deleted file mode 100644
index c1c9b06b77..0000000000
--- a/src/nm-cdma-device.c
+++ /dev/null
@@ -1,593 +0,0 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 Red Hat, Inc.
19 * Copyright (C) 2008 Novell, Inc.
20 */
21
22#include <stdio.h>
23#include <string.h>
24#include "nm-cdma-device.h"
25#include "nm-device-interface.h"
26#include "nm-device-private.h"
27#include "nm-setting-cdma.h"
28#include "nm-utils.h"
29#include "nm-properties-changed-signal.h"
30#include "nm-cdma-device-glue.h"
31#include "nm-setting-connection.h"
32
33G_DEFINE_TYPE (NMCdmaDevice, nm_cdma_device, NM_TYPE_SERIAL_DEVICE)
34
35#define NM_CDMA_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CDMA_DEVICE, NMCdmaDevicePrivate))
36
37typedef struct {
38 char *monitor_iface;
39 NMSerialDevice *monitor_device;
40
41 guint state_to_disconnected_id;
42} NMCdmaDevicePrivate;
43
44enum {
45 PROP_0,
46 PROP_MONITOR_IFACE,
47
48 LAST_PROP
49};
50
51enum {
52 PROPERTIES_CHANGED,
53
54 LAST_SIGNAL
55};
56
57static guint signals[LAST_SIGNAL] = { 0 };
58
59
60NMCdmaDevice *
61nm_cdma_device_new (const char *udi,
62 const char *data_iface,
63 const char *monitor_iface,
64 const char *driver,
65 gboolean managed)
66{
67 g_return_val_if_fail (udi != NULL, NULL);
68 g_return_val_if_fail (data_iface != NULL, NULL);
69 g_return_val_if_fail (driver != NULL, NULL);
70
71 return (NMCdmaDevice *) g_object_new (NM_TYPE_CDMA_DEVICE,
72 NM_DEVICE_INTERFACE_UDI, udi,
73 NM_DEVICE_INTERFACE_IFACE, data_iface,
74 NM_DEVICE_INTERFACE_DRIVER, driver,
75 NM_CDMA_DEVICE_MONITOR_IFACE, monitor_iface,
76 NM_DEVICE_INTERFACE_MANAGED, managed,
77 NULL);
78}
79
80static NMSetting *
81cdma_device_get_setting (NMCdmaDevice *device, GType setting_type)
82{
83 NMActRequest *req;
84 NMSetting *setting = NULL;
85
86 req = nm_device_get_act_request (NM_DEVICE (device));
87 if (req) {
88 NMConnection *connection;
89
90 connection = nm_act_request_get_connection (req);
91 if (connection)
92 setting = nm_connection_get_setting (connection, setting_type);
93 }
94
95 return setting;
96}
97
98static void
99dial_done (NMSerialDevice *device,
100 int reply_index,
101 const char *reply,
102 gpointer user_data)
103{
104 NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_UNKNOWN;
105 gboolean success = FALSE;
106
107 switch (reply_index) {
108 case 0:
109 nm_info ("Connected, Woo!");
110 success = TRUE;
111 break;
112 case 1:
113 nm_info ("Busy");
114 reason = NM_DEVICE_STATE_REASON_MODEM_BUSY;
115 break;
116 case 2:
117 nm_warning ("No dial tone");
118 reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE;
119 break;
120 case 3:
121 nm_warning ("No carrier");
122 reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER;
123 break;
124 case -1:
125 nm_warning ("Dialing timed out");
126 reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
127 break;
128 default:
129 nm_warning ("Dialing failed");
130 break;
131 }
132
133 if (success)
134 nm_device_activate_schedule_stage2_device_config (NM_DEVICE (device));
135 else
136 nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, reason);
137}
138
139static void
140do_dial (NMSerialDevice *device)
141{
142 NMSettingCdma *setting;
143 char *command;
144 guint id = 0;
145 const char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL };
146
147 setting = NM_SETTING_CDMA (cdma_device_get_setting (NM_CDMA_DEVICE (device), NM_TYPE_SETTING_CDMA));
148
149 command = g_strconcat ("ATDT", nm_setting_cdma_get_number (setting), NULL);
150 if (nm_serial_device_send_command_string (device, command))
151 id = nm_serial_device_wait_for_reply (device, 60, responses, responses, dial_done, NULL);
152 g_free (command);
153
154 if (id == 0)
155 nm_device_state_changed (NM_DEVICE (device),
156 NM_DEVICE_STATE_FAILED,
157 NM_DEVICE_STATE_REASON_UNKNOWN);
158}
159
160static void
161power_up_response (NMSerialDevice *device,
162 int reply_index,
163 const char *reply,
164 gpointer user_data)
165{
166 /* Ignore errors */
167 do_dial (device);
168}
169
170static void
171power_up (NMSerialDevice *device)
172{
173 const char *responses[] = { "OK", "ERROR", "ERR", NULL };
174 guint id = 0;
175
176 /* Only works on Sierra cards */
177 nm_info ("(%s): powering up...", nm_device_get_iface (NM_DEVICE (device)));
178 if (nm_serial_device_send_command_string (device, "at!pcstate=1"))
179 id = nm_serial_device_wait_for_reply (device, 10, responses, responses, power_up_response, NULL);
180
181 /* Ignore errors */
182 if (id == 0)
183 do_dial (device);
184}
185
186static void
187init_done (NMSerialDevice *device,
188 int reply_index,
189 const char *reply,
190 gpointer user_data)
191{
192 switch (reply_index) {
193 case 0:
194 power_up (device);
195 break;
196 case -1:
197 nm_warning ("Modem initialization timed out");
198 nm_device_state_changed (NM_DEVICE (device),
199 NM_DEVICE_STATE_FAILED,
200 NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
201 break;
202 default:
203 nm_warning ("Modem initialization failed");
204 nm_device_state_changed (NM_DEVICE (device),
205 NM_DEVICE_STATE_FAILED,
206 NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
207 return;
208 }
209}
210
211static void
212init_modem (NMSerialDevice *device, gpointer user_data)
213{
214 guint id = 0;
215 const char *responses[] = { "OK", "ERROR", "ERR", NULL };
216
217 if (nm_serial_device_send_command_string (device, "ATZ E0"))
218 id = nm_serial_device_wait_for_reply (device, 10, responses, responses, init_done, NULL);
219
220 if (id == 0)
221 nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
222}
223
224static NMActStageReturn
225real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
226{
227 NMSerialDevice *serial_device = NM_SERIAL_DEVICE (device);
228 NMSettingSerial *setting;
229 guint id;
230
231 setting = NM_SETTING_SERIAL (cdma_device_get_setting (NM_CDMA_DEVICE (device), NM_TYPE_SETTING_SERIAL));
232
233 if (!nm_serial_device_open (serial_device, setting)) {
234 *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
235 return NM_ACT_STAGE_RETURN_FAILURE;
236 }
237
238 id = nm_serial_device_flash (serial_device, 100, init_modem, NULL);
239 if (!id)
240 *reason = NM_DEVICE_STATE_REASON_UNKNOWN;
241
242 return id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE;
243}
244
245static NMConnection *
246real_get_best_auto_connection (NMDevice *dev,
247 GSList *connections,
248 char **specific_object)
249{
250 GSList *iter;
251
252 for (iter = connections; iter; iter = g_slist_next (iter)) {
253 NMConnection *connection = NM_CONNECTION (iter->data);
254 NMSettingConnection *s_con;
255
256 s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
257 g_assert (s_con);
258
259 if (!nm_setting_connection_get_autoconnect (s_con))
260 continue;
261
262 if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME))
263 continue;
264
265 return connection;
266 }
267 return NULL;
268}
269
270static guint32
271real_get_generic_capabilities (NMDevice *dev)
272{
273 return NM_DEVICE_CAP_NM_SUPPORTED;
274}
275
276static void
277real_connection_secrets_updated (NMDevice *dev,
278 NMConnection *connection,
279 GSList *updated_settings,
280 RequestSecretsCaller caller)
281{
282 NMActRequest *req;
283 gboolean found = FALSE;
284 GSList *iter;
285
286 if (caller == SECRETS_CALLER_PPP) {
287 NMPPPManager *ppp_manager;
288 NMSettingCdma *s_cdma = NULL;
289
290 ppp_manager = nm_serial_device_get_ppp_manager (NM_SERIAL_DEVICE (dev));
291 g_return_if_fail (ppp_manager != NULL);
292
293 s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
294 if (!s_cdma) {
295 /* Shouldn't ever happen */
296 nm_ppp_manager_update_secrets (ppp_manager,
297 nm_device_get_iface (dev),
298 NULL,
299 NULL,
300 "missing CDMA setting; no secrets could be found.");
301 } else {
302 const char *cdma_username = nm_setting_cdma_get_username (s_cdma);
303 const char *cdma_password = nm_setting_cdma_get_password (s_cdma);
304
305 nm_ppp_manager_update_secrets (ppp_manager,
306 nm_device_get_iface (dev),
307 cdma_username ? cdma_username : "",
308 cdma_password ? cdma_password : "",
309 NULL);
310 }
311 return;
312 }
313
314 g_return_if_fail (caller == SECRETS_CALLER_CDMA);
315 g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH);
316
317 for (iter = updated_settings; iter; iter = g_slist_next (iter)) {
318 const char *setting_name = (const char *) iter->data;
319
320 if (!strcmp (setting_name, NM_SETTING_CDMA_SETTING_NAME))
321 found = TRUE;
322 else
323 nm_warning ("Ignoring updated secrets for setting '%s'.", setting_name);
324 }
325
326 if (!found)
327 return;
328
329 req = nm_device_get_act_request (dev);
330 g_assert (req);
331
332 g_return_if_fail (nm_act_request_get_connection (req) == connection);
333
334 nm_device_activate_schedule_stage1_device_prepare (dev);
335}
336
337static const char *
338real_get_ppp_name (NMSerialDevice *device, NMActRequest *req)
339{
340 NMConnection *connection;
341 NMSettingCdma *s_cdma;
342
343 connection = nm_act_request_get_connection (req);
344 g_assert (connection);
345
346 s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
347 g_assert (s_cdma);
348
349 return nm_setting_cdma_get_username (s_cdma);
350}
351
352/*****************************************************************************/
353/* Monitor device handling */
354
355static gboolean
356monitor_device_got_data (GIOChannel *source,
357 GIOCondition condition,
358 gpointer data)
359{
360 gsize bytes_read;
361 char buf[4096];
362 GIOStatus status;
363
364 if (condition & G_IO_IN) {
365 do {
366 status = g_io_channel_read_chars (source, buf, 4096, &bytes_read, NULL);
367
368 if (bytes_read) {
369 buf[bytes_read] = '\0';
370 /* Do nothing with the data for now */
371 nm_debug ("Monitor got unhandled data: '%s'", buf);
372 }
373 } while (bytes_read == 4096 || status == G_IO_STATUS_AGAIN);
374 }
375
376 if (condition & G_IO_HUP || condition & G_IO_ERR) {
377 return FALSE;
378 }
379
380 return TRUE;
381}
382
383static gboolean
384setup_monitor_device (NMCdmaDevice *device)
385{
386 NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (device);
387 GIOChannel *channel;
388 NMSettingSerial *setting;
389
390 if (!priv->monitor_iface) {
391 nm_debug ("No monitoring udi provided");
392 return FALSE;
393 }
394
395 priv->monitor_device = g_object_new (NM_TYPE_SERIAL_DEVICE,
396 NM_DEVICE_INTERFACE_UDI, nm_device_get_udi (NM_DEVICE (device)),
397 NM_DEVICE_INTERFACE_IFACE, priv->monitor_iface,
398 NULL);
399
400 if (!priv->monitor_device) {
401 nm_warning ("Creation of the monitoring device failed");
402 return FALSE;
403 }
404
405 setting = NM_SETTING_SERIAL (nm_setting_serial_new ());
406 if (!nm_serial_device_open (priv->monitor_device, setting)) {
407 nm_warning ("Monitoring device open failed");
408 g_object_unref (setting);
409 g_object_unref (priv->monitor_device);
410 return FALSE;
411 }
412
413 g_object_unref (setting);
414
415 channel = nm_serial_device_get_io_channel (priv->monitor_device);
416 g_io_add_watch (channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
417 monitor_device_got_data, device);
418
419 g_io_channel_unref (channel);
420
421 return TRUE;
422}
423
424/*****************************************************************************/
425
426static void
427nm_cdma_device_init (NMCdmaDevice *self)
428{
429 nm_device_set_device_type (NM_DEVICE (self), NM_DEVICE_TYPE_CDMA);
430}
431
432static gboolean
433unavailable_to_disconnected (gpointer user_data)
434{
435 nm_device_state_changed (NM_DEVICE (user_data),
436 NM_DEVICE_STATE_DISCONNECTED,
437 NM_DEVICE_STATE_REASON_NONE);
438 return FALSE;
439}
440
441static void
442device_state_changed (NMDeviceInterface *device,
443 NMDeviceState new_state,
444 NMDeviceState old_state,
445 NMDeviceStateReason reason,
446 gpointer user_data)
447{
448 NMCdmaDevice *self = NM_CDMA_DEVICE (user_data);
449 NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (self);
450
451 /* Remove any previous delayed transition to disconnected */
452 if (priv->state_to_disconnected_id) {
453 g_source_remove (priv->state_to_disconnected_id);
454 priv->state_to_disconnected_id = 0;
455 }
456
457 /* If transitioning to UNAVAILBLE and we have a carrier, transition to
458 * DISCONNECTED because the device is ready to use. Otherwise the carrier-on
459 * handler will handle the transition to DISCONNECTED when the carrier is detected.
460 */
461 if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
462 priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
463
464 /* Make sure we don't leave the serial device open */
465 switch (new_state) {
466 case NM_DEVICE_STATE_UNMANAGED:
467 case NM_DEVICE_STATE_UNAVAILABLE:
468 case NM_DEVICE_STATE_FAILED:
469 case NM_DEVICE_STATE_DISCONNECTED:
470 nm_serial_device_close (NM_SERIAL_DEVICE (self));
471 break;
472 default:
473 break;
474 }
475}
476
477static GObject*
478constructor (GType type,
479 guint n_construct_params,
480 GObjectConstructParam *construct_params)
481{
482 GObject *object;
483
484 object = G_OBJECT_CLASS (nm_cdma_device_parent_class)->constructor (type,
485 n_construct_params,
486 construct_params);
487 if (!object)
488 return NULL;
489
490 /* FIXME: Make the monitor device not required for now */
491 setup_monitor_device (NM_CDMA_DEVICE (object));
492#if 0
493 if (!setup_monitor_device (NM_CDMA_DEVICE (object))) {
494 g_object_unref (object);
495 object = NULL;
496 }
497#endif
498
499 g_signal_connect (NM_DEVICE (object), "state-changed",
500 G_CALLBACK (device_state_changed), NM_CDMA_DEVICE (object));
501
502 return object;
503}
504
505static void
506set_property (GObject *object, guint prop_id,
507 const GValue *value, GParamSpec *pspec)
508{
509 NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (object);
510
511 switch (prop_id) {
512 case PROP_MONITOR_IFACE:
513 /* Construct only */
514 priv->monitor_iface = g_value_dup_string (value);
515 break;
516 default:
517 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
518 break;
519 }
520}
521
522static void
523get_property (GObject *object, guint prop_id,
524 GValue *value, GParamSpec *pspec)
525{
526 NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (object);
527
528 switch (prop_id) {
529 case PROP_MONITOR_IFACE:
530 g_value_set_string (value, priv->monitor_iface);
531 break;
532 default:
533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
534 break;
535 }
536}
537
538static void
539finalize (GObject *object)
540{
541 NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (object);
542
543 if (priv->monitor_device)
544 g_object_unref (priv->monitor_device);
545
546 g_free (priv->monitor_iface);
547
548 if (priv->state_to_disconnected_id) {
549 g_source_remove (priv->state_to_disconnected_id);
550 priv->state_to_disconnected_id = 0;
551 }
552
553 G_OBJECT_CLASS (nm_cdma_device_parent_class)->finalize (object);
554}
555
556static void
557nm_cdma_device_class_init (NMCdmaDeviceClass *klass)
558{
559 GObjectClass *object_class = G_OBJECT_CLASS (klass);
560 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
561 NMSerialDeviceClass *serial_class = NM_SERIAL_DEVICE_CLASS (klass);
562
563 g_type_class_add_private (object_class, sizeof (NMCdmaDevicePrivate));
564
565 object_class->constructor = constructor;
566 object_class->get_property = get_property;
567 object_class->set_property = set_property;
568 object_class->finalize = finalize;
569
570 device_class->get_best_auto_connection = real_get_best_auto_connection;
571 device_class->get_generic_capabilities = real_get_generic_capabilities;
572 device_class->act_stage1_prepare = real_act_stage1_prepare;
573 device_class->connection_secrets_updated = real_connection_secrets_updated;
574
575 serial_class->get_ppp_name = real_get_ppp_name;
576
577 /* Properties */
578 g_object_class_install_property
579 (object_class, PROP_MONITOR_IFACE,
580 g_param_spec_string (NM_CDMA_DEVICE_MONITOR_IFACE,
581 "Monitoring interface",
582 "Monitoring interface",
583 NULL,
584 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
585
586 /* Signals */
587 signals[PROPERTIES_CHANGED] =
588 nm_properties_changed_signal_new (object_class,
589 G_STRUCT_OFFSET (NMCdmaDeviceClass, properties_changed));
590
591 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
592 &dbus_glib_nm_cdma_device_object_info);
593}
diff --git a/src/nm-cdma-device.h b/src/nm-cdma-device.h
deleted file mode 100644
index 50c44a3ed8..0000000000
--- a/src/nm-cdma-device.h
+++ /dev/null
@@ -1,59 +0,0 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 Red Hat, Inc.
19 * Copyright (C) 2008 Novell, Inc.
20 */
21
22#ifndef NM_CDMA_DEVICE_H
23#define NM_CDMA_DEVICE_H
24
25#include <nm-serial-device.h>
26
27G_BEGIN_DECLS
28
29#define NM_TYPE_CDMA_DEVICE (nm_cdma_device_get_type ())
30#define NM_CDMA_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CDMA_DEVICE, NMCdmaDevice))
31#define NM_CDMA_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CDMA_DEVICE, NMCdmaDeviceClass))
32#define NM_IS_CDMA_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CDMA_DEVICE))
33#define NM_IS_CDMA_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CDMA_DEVICE))
34#define NM_CDMA_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CDMA_DEVICE, NMCdmaDeviceClass))
35
36#define NM_CDMA_DEVICE_MONITOR_IFACE "monitor-iface"
37
38typedef struct {
39 NMSerialDevice parent;
40} NMCdmaDevice;
41
42typedef struct {
43 NMSerialDeviceClass parent;
44
45 /* Signals */
46 void (*properties_changed) (NMCdmaDevice *device, GHashTable *properties);
47} NMCdmaDeviceClass;
48
49GType nm_cdma_device_get_type (void);
50
51NMCdmaDevice *nm_cdma_device_new (const char *udi,
52 const char *data_iface,
53 const char *monitor_iface,
54 const char *driver,
55 gboolean managed);
56
57G_END_DECLS
58
59#endif /* NM_CDMA_DEVICE_H */
diff --git a/src/nm-hal-manager.c b/src/nm-hal-manager.c
index e7179c028f..ff308e8f4b 100644
--- a/src/nm-hal-manager.c
+++ b/src/nm-hal-manager.c
@@ -33,9 +33,6 @@
33#include "nm-utils.h" 33#include "nm-utils.h"
34#include "nm-device-wifi.h" 34#include "nm-device-wifi.h"
35#include "nm-device-ethernet.h" 35#include "nm-device-ethernet.h"
36#include "nm-gsm-device.h"
37#include "nm-hso-gsm-device.h"
38#include "nm-cdma-device.h"
39 36
40/* Killswitch poll frequency in seconds */ 37/* Killswitch poll frequency in seconds */
41#define RFKILL_POLL_FREQUENCY 6 38#define RFKILL_POLL_FREQUENCY 6
@@ -220,145 +217,6 @@ wireless_device_creator (NMHalManager *self, const char *udi, gboolean managed)
220 return device; 217 return device;
221} 218}
222 219
223/* Modem device creator */
224
225static gboolean
226is_modem_device (NMHalManager *self, const char *udi)
227{
228 NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
229 gboolean is_modem = FALSE;
230
231 if (libhal_device_property_exists (priv->hal_ctx, udi, "info.category", NULL)) {
232 char *category;
233
234 category = libhal_device_get_property_string (priv->hal_ctx, udi, "info.category", NULL);
235 if (category) {
236 is_modem = strcmp (category, "serial") == 0;
237 libhal_free_string (category);
238 }
239 }
240
241 return is_modem;
242}
243
244static char *
245get_hso_netdev (LibHalContext *ctx, const char *udi)
246{
247 char *serial_parent, *netdev = NULL;
248 char **netdevs;
249 int num, i;
250
251 /* Get the serial interface's originating device UDI, used to find the
252 * originating device's netdev.
253 */
254 serial_parent = libhal_device_get_property_string (ctx, udi, "serial.originating_device", NULL);
255 if (!serial_parent)
256 serial_parent = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
257 if (!serial_parent)
258 return NULL;
259
260 /* Look for the originating device's netdev */
261 netdevs = libhal_find_device_by_capability (ctx, "net", &num, NULL);
262 for (i = 0; netdevs && !netdev && (i < num); i++) {
263 char *netdev_parent, *tmp;
264
265 netdev_parent = libhal_device_get_property_string (ctx, netdevs[i], "net.originating_device", NULL);
266 if (!netdev_parent)
267 netdev_parent = libhal_device_get_property_string (ctx, netdevs[i], "net.physical_device", NULL);
268 if (!netdev_parent)
269 continue;
270
271 if (!strcmp (netdev_parent, serial_parent)) {
272 /* We found it */
273 tmp = libhal_device_get_property_string (ctx, netdevs[i], "net.interface", NULL);
274 if (tmp) {
275 netdev = g_strdup (tmp);
276 libhal_free_string (tmp);
277 }
278 }
279
280 libhal_free_string (netdev_parent);
281 }
282 libhal_free_string_array (netdevs);
283 libhal_free_string (serial_parent);
284
285 return netdev;
286}
287
288static GObject *
289modem_device_creator (NMHalManager *self, const char *udi, gboolean managed)
290{
291 NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
292 char *serial_device;
293 char *parent_udi;
294 char *driver_name = NULL;
295 GObject *device = NULL;
296 char **capabilities, **iter;
297 gboolean type_gsm = FALSE;
298 gboolean type_cdma = FALSE;
299 char *netdev = NULL;
300
301 serial_device = libhal_device_get_property_string (priv->hal_ctx, udi, "serial.device", NULL);
302
303 /* Get the driver */
304 parent_udi = libhal_device_get_property_string (priv->hal_ctx, udi, "info.parent", NULL);
305 if (parent_udi) {
306 driver_name = libhal_device_get_property_string (priv->hal_ctx, parent_udi, "info.linux.driver", NULL);
307 libhal_free_string (parent_udi);
308 }
309
310 if (!serial_device || !driver_name)
311 goto out;
312
313 capabilities = libhal_device_get_property_strlist (priv->hal_ctx, udi, "modem.command_sets", NULL);
314 /* 'capabilites' may be NULL */
315 for (iter = capabilities; iter && *iter; iter++) {
316 if (!strcmp (*iter, "GSM-07.07")) {
317 type_gsm = TRUE;
318 break;
319 }
320 if (!strcmp (*iter, "IS-707-A")) {
321 type_cdma = TRUE;
322 break;
323 }
324 }
325 g_strfreev (capabilities);
326
327 /* Compatiblity with the pre-specification bits */
328 if (!type_gsm && !type_cdma) {
329 capabilities = libhal_device_get_property_strlist (priv->hal_ctx, udi, "info.capabilities", NULL);
330 for (iter = capabilities; *iter; iter++) {
331 if (!strcmp (*iter, "gsm")) {
332 type_gsm = TRUE;
333 break;
334 }
335 if (!strcmp (*iter, "cdma")) {
336 type_cdma = TRUE;
337 break;
338 }
339 }
340 g_strfreev (capabilities);
341 }
342
343 /* Special handling of 'hso' cards (until punted out to a modem manager) */
344 if (type_gsm && !strcmp (driver_name, "hso"))
345 netdev = get_hso_netdev (priv->hal_ctx, udi);
346
347 if (type_gsm) {
348 if (netdev)
349 device = (GObject *) nm_hso_gsm_device_new (udi, serial_device + strlen ("/dev/"), NULL, netdev, driver_name, managed);
350 else
351 device = (GObject *) nm_gsm_device_new (udi, serial_device + strlen ("/dev/"), NULL, driver_name, managed);
352 } else if (type_cdma)
353 device = (GObject *) nm_cdma_device_new (udi, serial_device + strlen ("/dev/"), NULL, driver_name, managed);
354
355out:
356 libhal_free_string (serial_device);
357 libhal_free_string (driver_name);
358
359 return device;
360}
361
362static void 220static void
363register_built_in_creators (NMHalManager *self) 221register_built_in_creators (NMHalManager *self)
364{ 222{
@@ -380,14 +238,6 @@ register_built_in_creators (NMHalManager *self)
380 creator->is_device_fn = is_wireless_device; 238 creator->is_device_fn = is_wireless_device;
381 creator->creator_fn = wireless_device_creator; 239 creator->creator_fn = wireless_device_creator;
382 priv->device_creators = g_slist_append (priv->device_creators, creator); 240 priv->device_creators = g_slist_append (priv->device_creators, creator);
383
384 /* Modem */
385 creator = g_slice_new0 (DeviceCreator);
386 creator->device_type_name = g_strdup ("Modem");
387 creator->capability_str = g_strdup ("modem");
388 creator->is_device_fn = is_modem_device;
389 creator->creator_fn = modem_device_creator;
390 priv->device_creators = g_slist_append (priv->device_creators, creator);
391} 241}
392 242
393static void 243static void
diff --git a/src/nm-hso-gsm-device.c b/src/nm-hso-gsm-device.c
deleted file mode 100644
index 15032a3c15..0000000000
--- a/src/nm-hso-gsm-device.c
+++ /dev/null
@@ -1,593 +0,0 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 Red Hat, Inc.
19 */
20
21#include <stdio.h>
22#include <string.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <arpa/inet.h>
26#include <dbus/dbus-glib.h>
27
28#include "nm-device.h"
29#include "nm-hso-gsm-device.h"
30#include "nm-gsm-device.h"
31#include "nm-device-interface.h"
32#include "nm-device-private.h"
33#include "nm-setting-gsm.h"
34#include "nm-utils.h"
35#include "nm-properties-changed-signal.h"
36#include "nm-setting-connection.h"
37#include "NetworkManagerSystem.h"
38
39G_DEFINE_TYPE (NMHsoGsmDevice, nm_hso_gsm_device, NM_TYPE_GSM_DEVICE)
40
41#define NM_HSO_GSM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_HSO_GSM_DEVICE, NMHsoGsmDevicePrivate))
42
43extern const DBusGObjectInfo dbus_glib_nm_gsm_device_object_info;
44
45#define GSM_CID "gsm-cid"
46#define HSO_SECRETS_TRIES "gsm-secrets-tries"
47
48typedef struct {
49 char *netdev_iface;
50 NMIP4Config *pending_ip4_config;
51} NMHsoGsmDevicePrivate;
52
53enum {
54 PROP_0,
55 PROP_NETDEV_IFACE,
56
57 LAST_PROP
58};
59
60NMHsoGsmDevice *
61nm_hso_gsm_device_new (const char *udi,
62 const char *data_iface,
63 const char *monitor_iface,
64 const char *netdev_iface,
65 const char *driver,
66 gboolean managed)
67{
68 g_return_val_if_fail (udi != NULL, NULL);
69 g_return_val_if_fail (data_iface != NULL, NULL);
70 g_return_val_if_fail (driver != NULL, NULL);
71 g_return_val_if_fail (netdev_iface != NULL, NULL);
72
73 return (NMHsoGsmDevice *) g_object_new (NM_TYPE_HSO_GSM_DEVICE,
74 NM_DEVICE_INTERFACE_UDI, udi,
75 NM_DEVICE_INTERFACE_IFACE, data_iface,
76 NM_DEVICE_INTERFACE_DRIVER, driver,
77 NM_GSM_DEVICE_MONITOR_IFACE, monitor_iface,
78 NM_HSO_GSM_DEVICE_NETDEV_IFACE, netdev_iface,
79 NM_DEVICE_INTERFACE_MANAGED, managed,
80 NULL);
81}
82
83static void
84modem_wait_for_reply (NMGsmDevice *self,
85 const char *command,
86 guint timeout,
87 const char **responses,
88 const char **terminators,
89 NMSerialWaitForReplyFn callback,
90 gpointer user_data)
91{
92 NMSerialDevice *serial = NM_SERIAL_DEVICE (self);
93 guint id = 0;
94
95 if (nm_serial_device_send_command_string (serial, command))
96 id = nm_serial_device_wait_for_reply (serial, timeout, responses, terminators, callback, user_data);
97
98 if (id == 0)
99 nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
100}
101
102static NMSetting *
103gsm_device_get_setting (NMGsmDevice *device, GType setting_type)
104{
105 NMActRequest *req;
106 NMSetting *setting = NULL;
107
108 req = nm_device_get_act_request (NM_DEVICE (device));
109 if (req) {
110 NMConnection *connection;
111
112 connection = nm_act_request_get_connection (req);
113 if (connection)
114 setting = nm_connection_get_setting (connection, setting_type);
115 }
116
117 return setting;
118}
119
120static void
121hso_call_done (NMSerialDevice *device,
122 int reply_index,
123 const char *reply,
124 gpointer user_data)
125{
126 gboolean success = FALSE;
127
128 switch (reply_index) {
129 case 0:
130 nm_info ("Connected, Woo!");
131 success = TRUE;
132 break;
133 default:
134 nm_warning ("Connect request failed");
135 break;
136 }
137
138 if (success)
139 nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (device));
140 else
141 nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED);
142}
143
144static void
145hso_clear_done (NMSerialDevice *device,
146 int reply_index,
147 const char *reply,
148 gpointer user_data)
149{
150 const char *responses[] = { "_OWANCALL: ", "ERROR", NULL };
151 guint cid = GPOINTER_TO_UINT (user_data);
152 char *command;
153
154 /* Try to connect */
155 command = g_strdup_printf ("AT_OWANCALL=%d,1,1", cid);
156 modem_wait_for_reply (NM_GSM_DEVICE (device), command, 10, responses, responses, hso_call_done, NULL);
157 g_free (command);
158}
159
160static void
161hso_auth_done (NMSerialDevice *device,
162 int reply_index,
163 const char *reply,
164 gpointer user_data)
165{
166 gboolean success = FALSE;
167 const char *responses[] = { "_OWANCALL: ", "ERROR", "NO CARRIER", NULL };
168 guint cid = GPOINTER_TO_UINT (user_data);
169 char *command;
170
171 switch (reply_index) {
172 case 0:
173 nm_info ("Authentication successful!");
174 success = TRUE;
175 break;
176 default:
177 nm_warning ("Authentication failed");
178 break;
179 }
180
181 if (!success) {
182 nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED);
183 return;
184 }
185
186 /* Kill any existing connection */
187 command = g_strdup_printf ("AT_OWANCALL=%d,0,1", cid);
188 modem_wait_for_reply (NM_GSM_DEVICE (device), command, 5, responses, responses, hso_clear_done, GUINT_TO_POINTER (cid));
189 g_free (command);
190}
191
192static void
193do_hso_auth (NMHsoGsmDevice *device)
194{
195 NMSettingGsm *s_gsm;
196 NMActRequest *req;
197 const char *responses[] = { "OK", "ERROR", "ERR", NULL };
198 char *command;
199 const char *gsm_username;
200 const char *gsm_password;
201 guint cid;
202
203 req = nm_device_get_act_request (NM_DEVICE (device));
204 g_assert (req);
205
206 cid = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (req), GSM_CID));
207
208 s_gsm = NM_SETTING_GSM (gsm_device_get_setting (NM_GSM_DEVICE (device), NM_TYPE_SETTING_GSM));
209
210 gsm_username = nm_setting_gsm_get_username (s_gsm);
211 gsm_password = nm_setting_gsm_get_password (s_gsm);
212
213 command = g_strdup_printf ("AT$QCPDPP=%d,1,\"%s\",\"%s\"",
214 cid,
215 gsm_password ? gsm_password : "",
216 gsm_username ? gsm_username : "");
217 modem_wait_for_reply (NM_GSM_DEVICE (device), command, 5, responses, responses, hso_auth_done, GUINT_TO_POINTER (cid));
218 g_free (command);
219}
220
221static NMActStageReturn
222real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
223{
224 NMActRequest *req;
225 NMConnection *connection;
226 const char *setting_name;
227 GPtrArray *hints = NULL;
228 const char *hint1 = NULL, *hint2 = NULL;
229 guint32 tries;
230
231 req = nm_device_get_act_request (device);
232 g_assert (req);
233 connection = nm_act_request_get_connection (req);
234 g_assert (connection);
235
236 setting_name = nm_connection_need_secrets (connection, &hints);
237 if (!setting_name) {
238 do_hso_auth (NM_HSO_GSM_DEVICE (device));
239 return NM_ACT_STAGE_RETURN_POSTPONE;
240 }
241
242 if (hints) {
243 if (hints->len > 0)
244 hint1 = g_ptr_array_index (hints, 0);
245 if (hints->len > 1)
246 hint2 = g_ptr_array_index (hints, 1);
247 }
248
249 nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
250
251 tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), HSO_SECRETS_TRIES));
252 nm_act_request_request_connection_secrets (req,
253 setting_name,
254 tries ? TRUE : FALSE,
255 SECRETS_CALLER_HSO_GSM,
256 hint1,
257 hint2);
258 g_object_set_data (G_OBJECT (connection), HSO_SECRETS_TRIES, GUINT_TO_POINTER (++tries));
259
260 if (hints)
261 g_ptr_array_free (hints, TRUE);
262
263 return NM_ACT_STAGE_RETURN_POSTPONE;
264}
265
266static void
267real_do_dial (NMGsmDevice *device, guint cid)
268{
269 NMActRequest *req;
270
271 req = nm_device_get_act_request (NM_DEVICE (device));
272 g_assert (req);
273 g_object_set_data (G_OBJECT (req), GSM_CID, GUINT_TO_POINTER (cid));
274
275 nm_device_activate_schedule_stage2_device_config (NM_DEVICE (device));
276}
277
278#define OWANDATA_TAG "_OWANDATA: "
279
280static void
281hso_ip4_config_response (NMSerialDevice *device,
282 int reply_index,
283 const char *response,
284 gpointer user_data)
285{
286 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (device);
287 NMActRequest *req;
288 char **items, **iter;
289 guint cid, i;
290 guint32 dns1 = 0, dns2 = 0, ip4_address = 0;
291
292 if ( (reply_index < 0)
293 || !response
294 || strncmp (response, OWANDATA_TAG, strlen (OWANDATA_TAG))) {
295 nm_device_activate_schedule_stage4_ip_config_timeout (NM_DEVICE (device));
296 return;
297 }
298
299 req = nm_device_get_act_request (NM_DEVICE (device));
300 g_assert (req);
301 cid = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (req), GSM_CID));
302
303 items = g_strsplit (response + strlen (OWANDATA_TAG), ", ", 0);
304 for (iter = items, i = 0; *iter; iter++, i++) {
305 if (i == 0) { /* CID */
306 long int tmp;
307
308 errno = 0;
309 tmp = strtol (*iter, NULL, 10);
310 if (errno != 0 || tmp < 0 || (guint) tmp != cid) {
311 nm_warning ("%s: unknown CID in OWANDATA response (got %d, expected %d)",
312 nm_device_get_iface (NM_DEVICE (device)),
313 (guint) tmp, cid);
314 goto out;
315 }
316 } else if (i == 1) { /* IP address */
317 if (inet_pton (AF_INET, *iter, &ip4_address) <= 0)
318 ip4_address = 0;
319 } else if (i == 3) { /* DNS 1 */
320 if (inet_pton (AF_INET, *iter, &dns1) <= 0)
321 dns1 = 0;
322 } else if (i == 4) { /* DNS 2 */
323 if (inet_pton (AF_INET, *iter, &dns2) <= 0)
324 dns2 = 0;
325 }
326 }
327
328out:
329 g_strfreev (items);
330
331 if (ip4_address) {
332 NMIP4Address *addr;
333
334 priv->pending_ip4_config = nm_ip4_config_new ();
335
336 addr = nm_ip4_address_new ();
337 nm_ip4_address_set_address (addr, ip4_address);
338 nm_ip4_address_set_prefix (addr, 32);
339
340 nm_ip4_config_take_address (priv->pending_ip4_config, addr);
341
342 if (dns1)
343 nm_ip4_config_add_nameserver (priv->pending_ip4_config, dns1);
344 if (dns2)
345 nm_ip4_config_add_nameserver (priv->pending_ip4_config, dns2);
346
347 nm_device_activate_schedule_stage4_ip_config_get (NM_DEVICE (device));
348 } else {
349 nm_device_state_changed (NM_DEVICE (device),
350 NM_DEVICE_STATE_FAILED,
351 NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
352 }
353}
354
355static NMActStageReturn
356real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason)
357{
358 NMActRequest *req;
359 char *command;
360 gint cid;
361 const char *responses[] = { "_OWANDATA: ", NULL };
362 const char *terminators[] = { "OK", "ERROR", "ERR", NULL };
363
364 req = nm_device_get_act_request (device);
365 g_assert (req);
366
367 cid = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (req), GSM_CID));
368 command = g_strdup_printf ("AT_OWANDATA=%d", cid);
369 modem_wait_for_reply (NM_GSM_DEVICE (device), command, 5, responses, terminators, hso_ip4_config_response, NULL);
370 g_free (command);
371
372 return NM_ACT_STAGE_RETURN_POSTPONE;
373}
374
375static NMActStageReturn
376real_act_stage4_get_ip4_config (NMDevice *device,
377 NMIP4Config **config,
378 NMDeviceStateReason *reason)
379{
380 NMHsoGsmDevice *self = NM_HSO_GSM_DEVICE (device);
381 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (self);
382 gboolean no_firmware = FALSE;
383
384 g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
385 g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
386
387 nm_device_set_ip_iface (device, priv->netdev_iface);
388 if (!nm_device_hw_bring_up (device, TRUE, &no_firmware)) {
389 if (no_firmware)
390 *reason = NM_DEVICE_STATE_REASON_FIRMWARE_MISSING;
391 else
392 *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
393 return NM_ACT_STAGE_RETURN_FAILURE;
394 }
395
396 *config = priv->pending_ip4_config;
397 priv->pending_ip4_config = NULL;
398 return NM_ACT_STAGE_RETURN_SUCCESS;
399}
400
401static void
402real_connection_secrets_updated (NMDevice *device,
403 NMConnection *connection,
404 GSList *updated_settings,
405 RequestSecretsCaller caller)
406{
407 g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH);
408
409 if (caller == SECRETS_CALLER_HSO_GSM) { /* HSO PPP auth */
410 nm_device_activate_schedule_stage2_device_config (device);
411 return;
412 }
413
414 /* Let parent handle other auth like PIN/PUK */
415 NM_DEVICE_CLASS (nm_hso_gsm_device_parent_class)->connection_secrets_updated (device, connection, updated_settings, caller);
416}
417
418static void
419real_deactivate_quickly (NMDevice *device)
420{
421 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (device);
422 NMActRequest *req;
423 guint cid;
424 char *command;
425
426 if (priv->pending_ip4_config) {
427 g_object_unref (priv->pending_ip4_config);
428 priv->pending_ip4_config = NULL;
429 }
430
431 /* Don't leave the modem connected */
432 req = nm_device_get_act_request (device);
433 if (req) {
434 cid = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (req), GSM_CID));
435 if (cid) {
436 const char *responses[] = { "OK", "ERROR", "ERR", NULL };
437 int reply;
438
439 /* Disconnect and disable asynchonous notification to keep serial
440 * buffer empty after the OK.
441 */
442 command = g_strdup_printf ("AT_OWANCALL=%d,0,0", cid);
443 nm_serial_device_send_command_string (NM_SERIAL_DEVICE (device), command);
444 reply = nm_serial_device_wait_reply_blocking (NM_SERIAL_DEVICE (device), 5, responses, responses);
445 g_free (command);
446 }
447 }
448
449 if (NM_DEVICE_CLASS (nm_hso_gsm_device_parent_class)->deactivate_quickly)
450 NM_DEVICE_CLASS (nm_hso_gsm_device_parent_class)->deactivate_quickly (device);
451}
452
453static void
454real_deactivate (NMDevice *device)
455{
456 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (device);
457
458 if (priv->netdev_iface) {
459 nm_system_device_flush_ip4_routes_with_iface (priv->netdev_iface);
460 nm_system_device_flush_ip4_addresses_with_iface (priv->netdev_iface);
461 nm_system_device_set_up_down_with_iface (priv->netdev_iface, FALSE, NULL);
462 }
463 nm_device_set_ip_iface (device, NULL);
464
465 if (NM_DEVICE_CLASS (nm_hso_gsm_device_parent_class)->deactivate)
466 NM_DEVICE_CLASS (nm_hso_gsm_device_parent_class)->deactivate (device);
467}
468
469static gboolean
470real_hw_is_up (NMDevice *device)
471{
472 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (device);
473 NMDeviceState state;
474
475 state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
476
477 if ( priv->pending_ip4_config
478 || (state == NM_DEVICE_STATE_IP_CONFIG)
479 || (state == NM_DEVICE_STATE_ACTIVATED))
480 return nm_system_device_is_up_with_iface (priv->netdev_iface);
481
482 return TRUE;
483}
484
485static gboolean
486real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
487{
488 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (device);
489 NMDeviceState state;
490
491 state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
492
493 if ( priv->pending_ip4_config
494 || (state == NM_DEVICE_STATE_IP_CONFIG)
495 || (state == NM_DEVICE_STATE_ACTIVATED))
496 return nm_system_device_set_up_down_with_iface (priv->netdev_iface, TRUE, no_firmware);
497
498 return TRUE;
499}
500
501static void
502nm_hso_gsm_device_init (NMHsoGsmDevice *self)
503{
504}
505
506static GObject*
507constructor (GType type,
508 guint n_params,
509 GObjectConstructParam *params)
510{
511 return G_OBJECT_CLASS (nm_hso_gsm_device_parent_class)->constructor (type, n_params, params);
512}
513
514static void
515set_property (GObject *object, guint prop_id,
516 const GValue *value, GParamSpec *pspec)
517{
518 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (object);
519
520 switch (prop_id) {
521 case PROP_NETDEV_IFACE:
522 /* Construct only */
523 priv->netdev_iface = g_value_dup_string (value);
524 break;
525 default:
526 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
527 break;
528 }
529}
530
531static void
532get_property (GObject *object, guint prop_id,
533 GValue *value, GParamSpec *pspec)
534{
535 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (object);
536
537 switch (prop_id) {
538 case PROP_NETDEV_IFACE:
539 g_value_set_string (value, priv->netdev_iface);
540 break;
541 default:
542 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
543 break;
544 }
545}
546
547static void
548finalize (GObject *object)
549{
550 NMHsoGsmDevicePrivate *priv = NM_HSO_GSM_DEVICE_GET_PRIVATE (object);
551
552 g_free (priv->netdev_iface);
553
554 G_OBJECT_CLASS (nm_hso_gsm_device_parent_class)->finalize (object);
555}
556
557static void
558nm_hso_gsm_device_class_init (NMHsoGsmDeviceClass *klass)
559{
560 GObjectClass *object_class = G_OBJECT_CLASS (klass);
561 NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
562 NMGsmDeviceClass *gsm_class = NM_GSM_DEVICE_CLASS (klass);
563
564 g_type_class_add_private (object_class, sizeof (NMHsoGsmDevicePrivate));
565
566 object_class->constructor = constructor;
567 object_class->get_property = get_property;
568 object_class->set_property = set_property;
569 object_class->finalize = finalize;
570
571 device_class->act_stage2_config = real_act_stage2_config;
572 device_class->act_stage3_ip_config_start = real_act_stage3_ip_config_start;
573 device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
574 device_class->connection_secrets_updated = real_connection_secrets_updated;
575 device_class->deactivate_quickly = real_deactivate_quickly;
576 device_class->deactivate = real_deactivate;
577 device_class->hw_is_up = real_hw_is_up;
578 device_class->hw_bring_up = real_hw_bring_up;
579
580 gsm_class->do_dial = real_do_dial;
581
582 /* Properties */
583 g_object_class_install_property
584 (object_class, PROP_NETDEV_IFACE,
585 g_param_spec_string (NM_HSO_GSM_DEVICE_NETDEV_IFACE,
586 "Network interface",
587 "Network interface",
588 NULL,
589 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
590
591 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
592 &dbus_glib_nm_gsm_device_object_info);
593}
diff --git a/src/nm-hso-gsm-device.h b/src/nm-hso-gsm-device.h
deleted file mode 100644
index 5b6b48ac66..0000000000
--- a/src/nm-hso-gsm-device.h
+++ /dev/null
@@ -1,56 +0,0 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 Red Hat, Inc.
19 */
20
21#ifndef NM_HSO_GSM_DEVICE_H
22#define NM_HSO_GSM_DEVICE_H
23
24#include <nm-gsm-device.h>
25
26G_BEGIN_DECLS
27
28#define NM_TYPE_HSO_GSM_DEVICE (nm_hso_gsm_device_get_type ())
29#define NM_HSO_GSM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_HSO_GSM_DEVICE, NMHsoGsmDevice))
30#define NM_HSO_GSM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_HSO_GSM_DEVICE, NMHsoGsmDeviceClass))
31#define NM_IS_HSO_GSM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_HSO_GSM_DEVICE))
32#define NM_IS_HSO_GSM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_HSO_GSM_DEVICE))
33#define NM_HSO_GSM_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_HSO_GSM_DEVICE, NMHsoGsmDeviceClass))
34
35#define NM_HSO_GSM_DEVICE_NETDEV_IFACE "netdev-iface"
36
37typedef struct {
38 NMGsmDevice parent;
39} NMHsoGsmDevice;
40
41typedef struct {
42 NMGsmDeviceClass parent;
43} NMHsoGsmDeviceClass;
44
45GType nm_hso_gsm_device_get_type (void);
46
47NMHsoGsmDevice *nm_hso_gsm_device_new (const char *udi,
48 const char *data_iface,
49 const char *monitor_iface,
50 const char *netdev_iface,
51 const char *driver,
52 gboolean managed);
53
54G_END_DECLS
55
56#endif /* NM_HSO_GSM_DEVICE_H */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 1b40834432..e0d8f71e68 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -29,6 +29,7 @@
29#include "nm-utils.h" 29#include "nm-utils.h"
30#include "nm-dbus-manager.h" 30#include "nm-dbus-manager.h"
31#include "nm-vpn-manager.h" 31#include "nm-vpn-manager.h"
32#include "nm-modem-manager.h"
32#include "nm-device-interface.h" 33#include "nm-device-interface.h"
33#include "nm-device-private.h" 34#include "nm-device-private.h"
34#include "nm-device-wifi.h" 35#include "nm-device-wifi.h"
@@ -96,6 +97,9 @@ static void system_settings_properties_changed_cb (DBusGProxy *proxy,
96 GHashTable *properties, 97 GHashTable *properties,
97 gpointer user_data); 98 gpointer user_data);
98 99
100static void add_device (NMManager *self, NMDevice *device, const char *type_name);
101static void remove_one_device (NMManager *manager, NMDevice *device);
102
99#define SSD_POKE_INTERVAL 120 103#define SSD_POKE_INTERVAL 120
100 104
101typedef struct { 105typedef struct {
@@ -134,6 +138,10 @@ typedef struct {
134 NMVPNManager *vpn_manager; 138 NMVPNManager *vpn_manager;
135 guint vpn_manager_id; 139 guint vpn_manager_id;
136 140
141 NMModemManager *modem_manager;
142 guint modem_added_id;
143 guint modem_removed_id;
144
137 DBusGProxy *aipd_proxy; 145 DBusGProxy *aipd_proxy;
138 146
139 gboolean disposed; 147 gboolean disposed;
@@ -242,6 +250,36 @@ vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
242} 250}
243 251
244static void 252static void
253modem_added (NMModemManager *modem_manager,
254 NMDevice *modem,
255 gpointer user_data)
256{
257 NMDeviceType type;
258 const char *type_name;
259
260 type = nm_device_get_device_type (NM_DEVICE (modem));
261 if (type == NM_DEVICE_TYPE_GSM)
262 type_name = "GSM modem";
263 else if (type == NM_DEVICE_TYPE_CDMA)
264 type_name = "CDMA modem";
265 else
266 type_name = "Unknown modem";
267
268 add_device (NM_MANAGER (user_data), NM_DEVICE (g_object_ref (modem)), type_name);
269}
270
271static void
272modem_removed (NMModemManager *modem_manager,
273 NMDevice *modem,
274 gpointer user_data)
275{
276 NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data);
277
278 remove_one_device (NM_MANAGER (user_data), modem);
279 priv->devices = g_slist_remove (priv->devices, modem);
280}
281
282static void
245aipd_handle_event (DBusGProxy *proxy, 283aipd_handle_event (DBusGProxy *proxy,
246 const char *event, 284 const char *event,
247 const char *iface, 285 const char *iface,
@@ -304,6 +342,12 @@ nm_manager_init (NMManager *manager)
304 g_free, 342 g_free,
305 g_object_unref); 343 g_object_unref);
306 344
345 priv->modem_manager = nm_modem_manager_get ();
346 priv->modem_added_id = g_signal_connect (priv->modem_manager, "device-added",
347 G_CALLBACK (modem_added), manager);
348 priv->modem_removed_id = g_signal_connect (priv->modem_manager, "device-removed",
349 G_CALLBACK (modem_removed), manager);
350
307 priv->vpn_manager = nm_vpn_manager_get (); 351 priv->vpn_manager = nm_vpn_manager_get ();
308 id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated", 352 id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
309 G_CALLBACK (vpn_manager_connection_deactivated_cb), manager); 353 G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
@@ -503,6 +547,16 @@ dispose (GObject *object)
503 } 547 }
504 g_object_unref (priv->vpn_manager); 548 g_object_unref (priv->vpn_manager);
505 549
550 if (priv->modem_added_id) {
551 g_source_remove (priv->modem_added_id);
552 priv->modem_added_id = 0;
553 }
554 if (priv->modem_removed_id) {
555 g_source_remove (priv->modem_removed_id);
556 priv->modem_removed_id = 0;
557 }
558 g_object_unref (priv->modem_manager);
559
506 g_object_unref (priv->dbus_mgr); 560 g_object_unref (priv->dbus_mgr);
507 g_object_unref (priv->hal_mgr); 561 g_object_unref (priv->hal_mgr);
508 562
@@ -1645,58 +1699,66 @@ next:
1645} 1699}
1646 1700
1647static void 1701static void
1648hal_manager_udi_added_cb (NMHalManager *hal_mgr, 1702add_device (NMManager *self, NMDevice *device, const char *type_name)
1649 const char *udi,
1650 const char *type_name,
1651 NMDeviceCreatorFn creator_fn,
1652 gpointer user_data)
1653{ 1703{
1654 NMManager *self = NM_MANAGER (user_data);
1655 NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); 1704 NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
1656 GObject *device;
1657 const char *iface; 1705 const char *iface;
1658 1706
1659 if (priv->sleeping)
1660 return;
1661
1662 /* Make sure the device is not already in the device list */
1663 if (nm_manager_get_device_by_udi (self, udi))
1664 return;
1665
1666 device = creator_fn (hal_mgr, udi, nm_manager_udi_is_managed (self, udi));
1667 if (!device)
1668 return;
1669
1670 priv->devices = g_slist_append (priv->devices, device); 1707 priv->devices = g_slist_append (priv->devices, device);
1671 1708
1672 g_signal_connect (device, "state-changed", 1709 g_signal_connect (device, "state-changed",
1673 G_CALLBACK (manager_device_state_changed), 1710 G_CALLBACK (manager_device_state_changed),
1674 self); 1711 self);
1675 1712
1676 /* Attach to the access-point-added signal so that the manager can fill 1713 /* Attach to the access-point-added signal so that the manager can fill
1677 * non-SSID-broadcasting APs with an SSID. 1714 * non-SSID-broadcasting APs with an SSID.
1678 */ 1715 */
1679 if (NM_IS_DEVICE_WIFI (device)) { 1716 if (NM_IS_DEVICE_WIFI (device)) {
1680 g_signal_connect (device, "hidden-ap-found", 1717 g_signal_connect (device, "hidden-ap-found",
1681 G_CALLBACK (manager_hidden_ap_found), 1718 G_CALLBACK (manager_hidden_ap_found),
1682 self); 1719 self);
1683 1720
1684 /* Set initial rfkill state */ 1721 /* Set initial rfkill state */
1685 nm_device_wifi_set_enabled (NM_DEVICE_WIFI (device), priv->wireless_enabled); 1722 nm_device_wifi_set_enabled (NM_DEVICE_WIFI (device), priv->wireless_enabled);
1686 } 1723 }
1687 1724
1688 iface = nm_device_get_iface (NM_DEVICE (device)); 1725 iface = nm_device_get_iface (device);
1689 nm_info ("Found new %s device '%s'.", type_name, iface); 1726 nm_info ("Found new %s device '%s'.", type_name, iface);
1690 1727
1691 dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr), 1728 dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
1692 nm_device_get_udi (NM_DEVICE (device)), 1729 nm_device_get_udi (NM_DEVICE (device)),
1693 device); 1730 G_OBJECT (device));
1694 nm_info ("(%s): exported as %s", iface, udi); 1731 nm_info ("(%s): exported as %s", iface, nm_device_get_udi (device));
1695 1732
1696 g_signal_emit (self, signals[DEVICE_ADDED], 0, device); 1733 g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
1697} 1734}
1698 1735
1699static void 1736static void
1737hal_manager_udi_added_cb (NMHalManager *hal_mgr,
1738 const char *udi,
1739 const char *type_name,
1740 NMDeviceCreatorFn creator_fn,
1741 gpointer user_data)
1742{
1743 NMManager *self = NM_MANAGER (user_data);
1744 NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
1745 GObject *device;
1746
1747 if (priv->sleeping)
1748 return;
1749
1750 /* Make sure the device is not already in the device list */
1751 if (nm_manager_get_device_by_udi (self, udi))
1752 return;
1753
1754 device = creator_fn (hal_mgr, udi, nm_manager_udi_is_managed (self, udi));
1755 if (!device)
1756 return;
1757
1758 add_device (self, NM_DEVICE (device), type_name);
1759}
1760
1761static void
1700hal_manager_udi_removed_cb (NMHalManager *manager, 1762hal_manager_udi_removed_cb (NMHalManager *manager,
1701 const char *udi, 1763 const char *udi,
1702 gpointer user_data) 1764 gpointer user_data)
diff --git a/src/nm-serial-device.c b/src/nm-serial-device.c
deleted file mode 100644
index 18cd2d8d13..0000000000
--- a/src/nm-serial-device.c
+++ /dev/null
@@ -1,1180 +0,0 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2007 - 2008 Novell, Inc.
19 * Copyright (C) 2007 - 2008 Red Hat, Inc.
20 */
21
22#define _GNU_SOURCE /* for strcasestr() */
23
24#include <termio.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <errno.h>
30#include <sys/ioctl.h>
31#include <string.h>
32#include <stdlib.h>
33#include <glib.h>
34
35#include "nm-glib-compat.h"
36#include "nm-serial-device.h"
37#include "nm-device-interface.h"
38#include "nm-device-private.h"
39#include "ppp-manager/nm-ppp-manager.h"
40#include "nm-setting-ppp.h"
41#include "nm-marshal.h"
42#include "nm-utils.h"
43#include "nm-serial-device-glue.h"
44#include "NetworkManagerUtils.h"
45
46static gboolean serial_debug = FALSE;
47
48#define SERIAL_BUF_SIZE 2048
49
50G_DEFINE_TYPE (NMSerialDevice, nm_serial_device, NM_TYPE_DEVICE)
51
52#define NM_SERIAL_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SERIAL_DEVICE, NMSerialDevicePrivate))
53
54typedef struct {
55 int fd;
56 GIOChannel *channel;
57 NMPPPManager *ppp_manager;
58 NMIP4Config *pending_ip4_config;
59 struct termios old_t;
60
61 guint pending_id;
62 guint timeout_id;
63
64 /* PPP stats */
65 guint32 in_bytes;
66 guint32 out_bytes;
67} NMSerialDevicePrivate;
68
69enum {
70 PPP_STATS,
71
72 LAST_SIGNAL
73};
74
75static guint signals[LAST_SIGNAL] = { 0 };
76
77static int
78parse_baudrate (guint i)
79{
80 int speed;
81
82 switch (i) {
83 case 0:
84 speed = B0;
85 break;
86 case 50:
87 speed = B50;
88 break;
89 case 75:
90 speed = B75;
91 break;
92 case 110:
93 speed = B110;
94 break;
95 case 150:
96 speed = B150;
97 break;
98 case 300:
99 speed = B300;
100 break;
101 case 600:
102 speed = B600;
103 break;
104 case 1200:
105 speed = B1200;
106 break;
107 case 2400:
108 speed = B2400;
109 break;
110 case 4800:
111 speed = B4800;
112 break;
113 case 9600:
114 speed = B9600;
115 break;
116 case 19200:
117 speed = B19200;
118 break;
119 case 38400:
120 speed = B38400;
121 break;
122 case 57600:
123 speed = B57600;
124 break;
125 case 115200:
126 speed = B115200;
127 break;
128 case 460800:
129 speed = B460800;
130 break;
131 default:
132 g_warning ("Invalid baudrate '%d'", i);
133 speed = B9600;
134 }
135
136 return speed;
137}
138
139static int
140parse_bits (guint i)
141{
142 int bits;
143
144 switch (i) {
145 case 5:
146 bits = CS5;
147 break;
148 case 6:
149 bits = CS6;
150 break;
151 case 7:
152 bits = CS7;
153 break;
154 case 8:
155 bits = CS8;
156 break;
157 default:
158 g_warning ("Invalid bits (%d). Valid values are 5, 6, 7, 8.", i);
159 bits = CS8;
160 }
161
162 return bits;
163}
164
165static int
166parse_parity (char c)
167{
168 int parity;
169
170 switch (c) {
171 case 'n':
172 case 'N':
173 parity = 0;
174 break;
175 case 'e':
176 case 'E':
177 parity = PARENB;
178 break;
179 case 'o':
180 case 'O':
181 parity = PARENB | PARODD;
182 break;
183 default:
184 g_warning ("Invalid parity (%c). Valid values are n, e, o", c);
185 parity = 0;
186 }
187
188 return parity;
189}
190
191static int
192parse_stopbits (guint i)
193{
194 int stopbits;
195
196 switch (i) {
197 case 1:
198 stopbits = 0;
199 break;
200 case 2:
201 stopbits = CSTOPB;
202 break;
203 default:
204 g_warning ("Invalid stop bits (%d). Valid values are 1 and 2)", i);
205 stopbits = 0;
206 }
207
208 return stopbits;
209}
210
211static inline void
212nm_serial_debug (const char *prefix, const char *data, int len)
213{
214 GString *str;
215 int i;
216
217 if (!serial_debug)
218 return;
219
220 str = g_string_sized_new (len);
221 for (i = 0; i < len; i++) {
222 if (data[i] == '\0')
223 g_string_append_c (str, ' ');
224 else if (data[i] == '\r')
225 g_string_append_c (str, '\n');
226 else
227 g_string_append_c (str, data[i]);
228 }
229
230 nm_debug ("%s '%s'", prefix, str->str);
231 g_string_free (str, TRUE);
232}
233
234static NMSetting *
235serial_device_get_setting (NMSerialDevice *device, GType setting_type)
236{
237 NMActRequest *req;
238 NMSetting *setting = NULL;
239
240 req = nm_device_get_act_request (NM_DEVICE (device));
241 if (req) {
242 NMConnection *connection;
243
244 connection = nm_act_request_get_connection (req);
245 if (connection)
246 setting = nm_connection_get_setting (connection, setting_type);
247 }
248
249 return setting;
250}
251
252/* Timeout handling */
253
254static void
255nm_serial_device_timeout_removed (gpointer data)
256{
257 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (data);
258
259 priv->timeout_id = 0;
260}
261
262static gboolean
263nm_serial_device_timed_out (gpointer data)
264{
265 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (data);
266
267 /* Cancel data reading */
268 if (priv->pending_id)
269 g_source_remove (priv->pending_id);
270 else
271 nm_warning ("Timeout reached, but there's nothing to time out");
272
273 return FALSE;
274}
275
276static void
277nm_serial_device_add_timeout (NMSerialDevice *self, guint timeout)
278{
279 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (self);
280
281 if (priv->pending_id == 0)
282 nm_warning ("Adding a time out while not waiting for any data");
283
284 if (priv->timeout_id) {
285 nm_warning ("Trying to add a new time out while the old one still exists");
286 g_source_remove (priv->timeout_id);
287 }
288
289 priv->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
290 timeout,
291 nm_serial_device_timed_out,
292 self,
293 nm_serial_device_timeout_removed);
294 if (G_UNLIKELY (priv->timeout_id == 0))
295 nm_warning ("Registering serial device time out failed.");
296}
297
298static void
299nm_serial_device_remove_timeout (NMSerialDevice *self)
300{
301 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (self);
302
303 if (priv->timeout_id)
304 g_source_remove (priv->timeout_id);
305}
306
307/* Pending data reading */
308
309static guint
310nm_serial_device_set_pending (NMSerialDevice *device,
311 guint timeout,
312 GIOFunc callback,
313 gpointer user_data,
314 GDestroyNotify notify)
315{
316 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
317
318 if (G_UNLIKELY (priv->pending_id)) {
319 /* FIXME: Probably should queue up pending calls instead? */
320 /* Multiple pending calls on the same GIOChannel doesn't work, so let's cancel the previous one. */
321 nm_warning ("Adding new pending call while previous one isn't finished.");
322 nm_warning ("Cancelling the previous pending call.");
323 g_source_remove (priv->pending_id);
324 }
325
326 priv->pending_id = g_io_add_watch_full (priv->channel,
327 G_PRIORITY_DEFAULT,
328 G_IO_IN | G_IO_ERR | G_IO_HUP,
329 callback, user_data, notify);
330
331 nm_serial_device_add_timeout (device, timeout);
332
333 return priv->pending_id;
334}
335
336static void
337nm_serial_device_pending_done (NMSerialDevice *self)
338{
339 NM_SERIAL_DEVICE_GET_PRIVATE (self)->pending_id = 0;
340 nm_serial_device_remove_timeout (self);
341}
342
343/****/
344
345static gboolean
346config_fd (NMSerialDevice *device, NMSettingSerial *setting)
347{
348 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
349 struct termio stbuf;
350 int speed;
351 int bits;
352 int parity;
353 int stopbits;
354
355 speed = parse_baudrate (nm_setting_serial_get_baud (setting));
356 bits = parse_bits (nm_setting_serial_get_bits (setting));
357 parity = parse_parity (nm_setting_serial_get_parity (setting));
358 stopbits = parse_stopbits (nm_setting_serial_get_stopbits (setting));
359
360 ioctl (priv->fd, TCGETA, &stbuf);
361
362 stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
363 stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
364 stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
365 stbuf.c_lflag &= ~(ECHO | ECHOE);
366 stbuf.c_cc[VMIN] = 1;
367 stbuf.c_cc[VTIME] = 0;
368 stbuf.c_cc[VEOF] = 1;
369
370 stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
371 stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits);
372
373 if (ioctl (priv->fd, TCSETA, &stbuf) < 0) {
374 nm_warning ("(%s) cannot control device (errno %d)",
375 nm_device_get_iface (NM_DEVICE (device)), errno);
376 return FALSE;
377 }
378
379 return TRUE;
380}
381
382gboolean
383nm_serial_device_open (NMSerialDevice *device,
384 NMSettingSerial *setting)
385{
386 NMSerialDevicePrivate *priv;
387 const char *iface;
388 char *path;
389
390 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), FALSE);
391 g_return_val_if_fail (NM_IS_SETTING_SERIAL (setting), FALSE);
392
393 priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
394 iface = nm_device_get_iface (NM_DEVICE (device));
395
396 nm_debug ("(%s) opening device...", iface);
397
398 path = g_build_filename ("/dev", iface, NULL);
399 priv->fd = open (path, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
400 g_free (path);
401
402 if (priv->fd < 0) {
403 nm_warning ("(%s) cannot open device (errno %d)", iface, errno);
404 return FALSE;
405 }
406
407 if (ioctl (priv->fd, TCGETA, &priv->old_t) < 0) {
408 nm_warning ("(%s) cannot control device (errno %d)", iface, errno);
409 close (priv->fd);
410 return FALSE;
411 }
412
413 if (!config_fd (device, setting)) {
414 close (priv->fd);
415 return FALSE;
416 }
417
418 priv->channel = g_io_channel_unix_new (priv->fd);
419 g_io_channel_set_encoding (priv->channel, NULL, NULL);
420
421 return TRUE;
422}
423
424void
425nm_serial_device_close (NMSerialDevice *device)
426{
427 NMSerialDevicePrivate *priv;
428
429 g_return_if_fail (NM_IS_SERIAL_DEVICE (device));
430
431 priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
432
433 if (priv->pending_id)
434 g_source_remove (priv->pending_id);
435
436 if (priv->ppp_manager) {
437 nm_ppp_manager_stop (priv->ppp_manager);
438 g_object_unref (priv->ppp_manager);
439 priv->ppp_manager = NULL;
440 }
441
442 if (priv->fd) {
443 nm_debug ("Closing device '%s'", nm_device_get_iface (NM_DEVICE (device)));
444
445 if (priv->channel) {
446 g_io_channel_unref (priv->channel);
447 priv->channel = NULL;
448 }
449
450 ioctl (priv->fd, TCSETA, &priv->old_t);
451 close (priv->fd);
452 priv->fd = 0;
453 }
454}
455
456gboolean
457nm_serial_device_send_command (NMSerialDevice *device, GByteArray *command)
458{
459 int fd;
460 NMSettingSerial *setting;
461 int i, eagain_count = 1000;
462 ssize_t written;
463 guint32 send_delay = 0;
464
465 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), FALSE);
466 g_return_val_if_fail (command != NULL, FALSE);
467
468 fd = NM_SERIAL_DEVICE_GET_PRIVATE (device)->fd;
469 setting = NM_SETTING_SERIAL (serial_device_get_setting (device, NM_TYPE_SETTING_SERIAL));
470 if (setting)
471 send_delay = nm_setting_serial_get_send_delay (setting);
472 if (send_delay == 0)
473 send_delay = G_USEC_PER_SEC / 1000;
474
475 nm_serial_debug ("Sending:", (char *) command->data, command->len);
476
477 for (i = 0; i < command->len && eagain_count > 0;) {
478 written = write (fd, command->data + i, 1);
479
480 if (written > 0)
481 i += written;
482 else {
483 /* Treat written == 0 as EAGAIN to ensure we break out of the
484 * for() loop eventually.
485 */
486 if ((written < 0) && (errno != EAGAIN)) {
487 g_warning ("Error in writing (errno %d)", errno);
488 return FALSE;
489 }
490 eagain_count--;
491 }
492 g_usleep (send_delay);
493 }
494
495 if (eagain_count <= 0)
496 nm_serial_debug ("Error: too many retries sending:", (char *) command->data, command->len);
497
498 return TRUE;
499}
500
501gboolean
502nm_serial_device_send_command_string (NMSerialDevice *device, const char *str)
503{
504 GByteArray *command;
505 gboolean ret;
506
507 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), FALSE);
508 g_return_val_if_fail (str != NULL, FALSE);
509
510 command = g_byte_array_new ();
511 g_byte_array_append (command, (guint8 *) str, strlen (str));
512 g_byte_array_append (command, (guint8 *) "\r", 1);
513
514 ret = nm_serial_device_send_command (device, command);
515 g_byte_array_free (command, TRUE);
516
517 return ret;
518}
519
520static gboolean
521find_terminator (const char *line, const char **terminators)
522{
523 int i;
524
525 for (i = 0; terminators[i]; i++) {
526 if (!strncasecmp (line, terminators[i], strlen (terminators[i])))
527 return TRUE;
528 }
529 return FALSE;
530}
531
532static const char *
533find_response (const char *line, const char **responses, gint *idx)
534{
535 int i;
536
537 /* Don't look for a result again if we got one previously */
538 for (i = 0; responses[i]; i++) {
539 if (strcasestr (line, responses[i])) {
540 *idx = i;
541 return line;
542 }
543 }
544 return NULL;
545}
546
547#define RESPONSE_LINE_MAX 128
548
549int
550nm_serial_device_wait_reply_blocking (NMSerialDevice *device,
551 guint32 timeout_secs,
552 const char **needles,
553 const char **terminators)
554{
555 char buf[SERIAL_BUF_SIZE + 1];
556 int fd, reply_index = -1, bytes_read;
557 GString *result = NULL;
558 time_t end;
559 const char *response = NULL;
560 gboolean done = FALSE;
561
562 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), -1);
563 g_return_val_if_fail (timeout_secs <= 60, -1);
564 g_return_val_if_fail (needles != NULL, -1);
565
566 fd = NM_SERIAL_DEVICE_GET_PRIVATE (device)->fd;
567 if (fd < 0)
568 return -1;
569
570 end = time (NULL) + timeout_secs;
571 result = g_string_sized_new (20);
572 do {
573 bytes_read = read (fd, buf, SERIAL_BUF_SIZE);
574 if (bytes_read < 0 && errno != EAGAIN) {
575 nm_warning ("%s: read error: %d (%s)",
576 nm_device_get_iface (NM_DEVICE (device)),
577 errno,
578 strerror (errno));
579 return -1;
580 }
581
582 if (bytes_read == 0)
583 break; /* EOF */
584 else if (bytes_read > 0) {
585 buf[bytes_read] = 0;
586 g_string_append (result, buf);
587
588 nm_serial_debug ("Got:", result->str, result->len);
589 }
590
591 /* Look for needles and terminators */
592 if ((bytes_read > 0) && result->str) {
593 char *p = result->str;
594
595 /* Break the response up into lines and process each one */
596 while ((p < result->str + strlen (result->str)) && !done) {
597 char line[RESPONSE_LINE_MAX] = { '\0', };
598 char *tmp;
599 int i;
600 gboolean got_something = FALSE;
601
602 for (i = 0; *p && (i < RESPONSE_LINE_MAX - 1); p++) {
603 /* Ignore front CR/LF */
604 if ((*p == '\n') || (*p == '\r')) {
605 if (got_something)
606 break;
607 } else {
608 line[i++] = *p;
609 got_something = TRUE;
610 }
611 }
612 line[i] = '\0';
613
614 tmp = g_strstrip (line);
615 if (tmp && strlen (tmp)) {
616 done = find_terminator (tmp, terminators);
617 if (reply_index == -1)
618 response = find_response (tmp, needles, &reply_index);
619 }
620 }
621 }
622
623 /* Limit the size of the buffer */
624 if (result->len > SERIAL_BUF_SIZE) {
625 g_warning ("%s (%s): response buffer filled before repsonse received",
626 __func__, nm_device_get_iface (NM_DEVICE (device)));
627 break;
628 }
629
630 if (!done)
631 g_usleep (100);
632 } while (!done && (time (NULL) < end));
633
634 return reply_index;
635}
636
637typedef struct {
638 NMSerialDevice *device;
639 char **str_needles;
640 char **terminators;
641 GString *result;
642 NMSerialWaitForReplyFn callback;
643 gpointer user_data;
644 int reply_index;
645 char *reply_line;
646 time_t end;
647} WaitForReplyInfo;
648
649static void
650wait_for_reply_done (gpointer data)
651{
652 WaitForReplyInfo *info = (WaitForReplyInfo *) data;
653
654 nm_serial_device_pending_done (info->device);
655
656 /* Call the callback */
657 info->callback (info->device, info->reply_index, info->reply_line, info->user_data);
658
659 /* Free info */
660 if (info->result)
661 g_string_free (info->result, TRUE);
662
663 g_free (info->reply_line);
664
665 g_strfreev (info->str_needles);
666 g_strfreev (info->terminators);
667 g_slice_free (WaitForReplyInfo, info);
668}
669
670static gboolean
671wait_for_reply_got_data (GIOChannel *source,
672 GIOCondition condition,
673 gpointer data)
674{
675 WaitForReplyInfo *info = (WaitForReplyInfo *) data;
676 gchar buf[SERIAL_BUF_SIZE + 1];
677 gsize bytes_read;
678 GIOStatus status;
679 gboolean done = FALSE;
680
681 if (condition & G_IO_HUP || condition & G_IO_ERR)
682 return FALSE;
683
684 do {
685 GError *err = NULL;
686
687 status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err);
688 if (status == G_IO_STATUS_ERROR) {
689 g_warning ("%s", err->message);
690 g_error_free (err);
691 err = NULL;
692 }
693
694 if (bytes_read > 0) {
695 buf[bytes_read] = 0;
696 g_string_append (info->result, buf);
697
698 nm_serial_debug ("Got:", info->result->str, info->result->len);
699 }
700
701 /* Look for needles and terminators */
702 if ((bytes_read > 0) && info->result->str) {
703 char *p = info->result->str;
704
705 /* Break the response up into lines and process each one */
706 while ((p < info->result->str + strlen (info->result->str)) && !done) {
707 char line[RESPONSE_LINE_MAX] = { '\0', };
708 char *tmp;
709 int i;
710 gboolean got_something = FALSE;
711
712 for (i = 0; *p && (i < RESPONSE_LINE_MAX - 1); p++) {
713 /* Ignore front CR/LF */
714 if ((*p == '\n') || (*p == '\r')) {
715 if (got_something)
716 break;
717 } else {
718 line[i++] = *p;
719 got_something = TRUE;
720 }
721 }
722 line[i] = '\0';
723
724 tmp = g_strstrip (line);
725 if (tmp && strlen (tmp)) {
726 done = find_terminator (tmp, (const char **) info->terminators);
727 if (info->reply_index == -1) {
728 if (find_response (tmp, (const char **) info->str_needles, &(info->reply_index)))
729 info->reply_line = g_strdup (tmp);
730 }
731 }
732 }
733 }
734
735 /* Limit the size of the buffer */
736 if (info->result->len > SERIAL_BUF_SIZE) {
737 nm_warning ("(%s): response buffer filled before repsonse received",
738 nm_device_get_iface (NM_DEVICE (info->device)));
739 done = TRUE;
740 break;
741 }
742
743 /* Make sure we don't go over the timeout, in addition to the timeout
744 * handler that's been scheduled. If for some reason this loop doesn't
745 * terminate (terminator not found, whatever) then this should make
746 * sure that NM doesn't spin the CPU forever.
747 */
748 if (time (NULL) > info->end) {
749 done = TRUE;
750 break;
751 } else if (!done)
752 g_usleep (50);
753 } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
754
755 return !done;
756}
757
758guint
759nm_serial_device_wait_for_reply (NMSerialDevice *device,
760 guint timeout,
761 const char **responses,
762 const char **terminators,
763 NMSerialWaitForReplyFn callback,
764 gpointer user_data)
765{
766 WaitForReplyInfo *info;
767
768 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), 0);
769 g_return_val_if_fail (responses != NULL, 0);
770 g_return_val_if_fail (callback != NULL, 0);
771
772 info = g_slice_new0 (WaitForReplyInfo);
773 info->device = device;
774 info->str_needles = g_strdupv ((char **) responses);
775 info->terminators = g_strdupv ((char **) terminators);
776 info->result = g_string_new (NULL);
777 info->callback = callback;
778 info->user_data = user_data;
779 info->reply_index = -1;
780 info->end = time (NULL) + timeout;
781
782 return nm_serial_device_set_pending (device, timeout, wait_for_reply_got_data, info, wait_for_reply_done);
783}
784
785#if 0
786typedef struct {
787 NMSerialDevice *device;
788 gboolean timed_out;
789 NMSerialWaitQuietFn callback;
790 gpointer user_data;
791} WaitQuietInfo;
792
793static void
794wait_quiet_done (gpointer data)
795{
796 WaitQuietInfo *info = (WaitQuietInfo *) data;
797
798 nm_serial_device_pending_done (info->device);
799
800 /* Call the callback */
801 info->callback (info->device, info->timed_out, info->user_data);
802
803 /* Free info */
804 g_slice_free (WaitQuietInfo, info);
805}
806
807static gboolean
808wait_quiet_quiettime (gpointer data)
809{
810 WaitQuietInfo *info = (WaitQuietInfo *) data;
811
812 info->timed_out = FALSE;
813 g_source_remove (NM_SERIAL_DEVICE_GET_PRIVATE (info->device)->pending);
814
815 return FALSE;
816}
817
818static gboolean
819wait_quiet_got_data (GIOChannel *source,
820 GIOCondition condition,
821 gpointer data)
822{
823 WaitQuietInfo *info = (WaitQuietInfo *) data;
824 gsize bytes_read;
825 char buf[4096];
826 GIOStatus status;
827
828 if (condition & G_IO_HUP || condition & G_IO_ERR)
829 return FALSE;
830
831 if (condition & G_IO_IN) {
832 do {
833 status = g_io_channel_read_chars (source, buf, 4096, &bytes_read, NULL);
834
835 if (bytes_read) {
836 /* Reset the quiet time timeout */
837 g_source_remove (info->quiet_id);
838 info->quiet_id = g_timeout_add (info->quiet_time, wait_quiet_quiettime, info);
839 }
840 } while (bytes_read == 4096 || status == G_IO_STATUS_AGAIN);
841 }
842
843 return TRUE;
844}
845
846void
847nm_serial_device_wait_quiet (NMSerialDevice *device,
848 guint timeout,
849 guint quiet_time,
850 NMSerialWaitQuietFn callback,
851 gpointer user_data)
852{
853 WaitQuietInfo *info;
854
855 g_return_if_fail (NM_IS_SERIAL_DEVICE (device));
856 g_return_if_fail (callback != NULL);
857
858 info = g_slice_new0 (WaitQuietInfo);
859 info->device = device;
860 info->timed_out = TRUE;
861 info->callback = callback;
862 info->user_data = user_data;
863 info->quiet_id = g_timeout_add (quiet_time,
864 wait_quiet_timeout,
865 info);
866
867 return nm_serial_device_set_pending (device, timeout, wait_quiet_got_data, info, wait_quiet_done);
868}
869
870#endif
871
872typedef struct {
873 NMSerialDevice *device;
874 speed_t current_speed;
875 NMSerialFlashFn callback;
876 gpointer user_data;
877} FlashInfo;
878
879static speed_t
880get_speed (NMSerialDevice *device)
881{
882 struct termios options;
883
884 tcgetattr (NM_SERIAL_DEVICE_GET_PRIVATE (device)->fd, &options);
885
886 return cfgetospeed (&options);
887}
888
889static void
890set_speed (NMSerialDevice *device, speed_t speed)
891{
892 struct termios options;
893 int fd;
894
895 fd = NM_SERIAL_DEVICE_GET_PRIVATE (device)->fd;
896 tcgetattr (fd, &options);
897
898 cfsetispeed (&options, speed);
899 cfsetospeed (&options, speed);
900
901 options.c_cflag |= (CLOCAL | CREAD);
902 tcsetattr (fd, TCSANOW, &options);
903}
904
905static void
906flash_done (gpointer data)
907{
908 FlashInfo *info = (FlashInfo *) data;
909
910 NM_SERIAL_DEVICE_GET_PRIVATE (info->device)->pending_id = 0;
911
912 info->callback (info->device, info->user_data);
913
914 g_slice_free (FlashInfo, info);
915}
916
917static gboolean
918flash_do (gpointer data)
919{
920 FlashInfo *info = (FlashInfo *) data;
921
922 set_speed (info->device, info->current_speed);
923
924 return FALSE;
925}
926
927guint
928nm_serial_device_flash (NMSerialDevice *device,
929 guint32 flash_time,
930 NMSerialFlashFn callback,
931 gpointer user_data)
932{
933 FlashInfo *info;
934 guint id;
935
936 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), 0);
937 g_return_val_if_fail (callback != NULL, 0);
938
939 info = g_slice_new0 (FlashInfo);
940 info->device = device;
941 info->current_speed = get_speed (device);
942 info->callback = callback;
943 info->user_data = user_data;
944
945 set_speed (device, B0);
946
947 id = g_timeout_add_full (G_PRIORITY_DEFAULT,
948 flash_time,
949 flash_do,
950 info,
951 flash_done);
952
953 NM_SERIAL_DEVICE_GET_PRIVATE (device)->pending_id = id;
954
955 return id;
956}
957
958GIOChannel *
959nm_serial_device_get_io_channel (NMSerialDevice *device)
960{
961 NMSerialDevicePrivate *priv;
962
963 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), 0);
964
965 priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
966 if (priv->channel)
967 return g_io_channel_ref (priv->channel);
968
969 return NULL;
970}
971
972NMPPPManager *
973nm_serial_device_get_ppp_manager (NMSerialDevice *device)
974{
975 g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), NULL);
976
977 return NM_SERIAL_DEVICE_GET_PRIVATE (device)->ppp_manager;
978}
979
980static void
981ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data)
982{
983 NMDevice *device = NM_DEVICE (user_data);
984
985 switch (status) {
986 case NM_PPP_STATUS_NETWORK:
987 nm_device_state_changed (device, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
988 break;
989 case NM_PPP_STATUS_DISCONNECT:
990 nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT);
991 break;
992 case NM_PPP_STATUS_DEAD:
993 nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED);
994 break;
995 case NM_PPP_STATUS_AUTHENTICATE:
996 nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
997 break;
998 default:
999 break;
1000 }
1001}
1002
1003static void
1004ppp_ip4_config (NMPPPManager *ppp_manager,
1005 const char *iface,
1006 NMIP4Config *config,
1007 gpointer user_data)
1008{
1009 NMDevice *device = NM_DEVICE (user_data);
1010
1011 nm_device_set_ip_iface (device, iface);
1012 NM_SERIAL_DEVICE_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config);
1013 nm_device_activate_schedule_stage4_ip_config_get (device);
1014}
1015
1016static void
1017ppp_stats (NMPPPManager *ppp_manager,
1018 guint32 in_bytes,
1019 guint32 out_bytes,
1020 gpointer user_data)
1021{
1022 NMSerialDevice *device = NM_SERIAL_DEVICE (user_data);
1023 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
1024
1025 if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) {
1026 priv->in_bytes = in_bytes;
1027 priv->out_bytes = out_bytes;
1028
1029 g_signal_emit (device, signals[PPP_STATS], 0, in_bytes, out_bytes);
1030 }
1031}
1032
1033static NMActStageReturn
1034real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
1035{
1036 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
1037 NMSerialDeviceClass *serial_class = NM_SERIAL_DEVICE_GET_CLASS (device);
1038 NMActRequest *req;
1039 GError *err = NULL;
1040 NMActStageReturn ret;
1041 const char *ppp_name = NULL;
1042
1043 req = nm_device_get_act_request (device);
1044 g_assert (req);
1045
1046 if (serial_class->get_ppp_name)
1047 ppp_name = serial_class->get_ppp_name (NM_SERIAL_DEVICE (device), req);
1048
1049 priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (device));
1050 if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, &err)) {
1051 g_signal_connect (priv->ppp_manager, "state-changed",
1052 G_CALLBACK (ppp_state_changed),
1053 device);
1054 g_signal_connect (priv->ppp_manager, "ip4-config",
1055 G_CALLBACK (ppp_ip4_config),
1056 device);
1057 g_signal_connect (priv->ppp_manager, "stats",
1058 G_CALLBACK (ppp_stats),
1059 device);
1060
1061 ret = NM_ACT_STAGE_RETURN_POSTPONE;
1062 } else {
1063 nm_warning ("%s", err->message);
1064 g_error_free (err);
1065
1066 g_object_unref (priv->ppp_manager);
1067 priv->ppp_manager = NULL;
1068
1069 *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
1070 ret = NM_ACT_STAGE_RETURN_FAILURE;
1071 }
1072
1073 return ret;
1074}
1075
1076static NMActStageReturn
1077real_act_stage4_get_ip4_config (NMDevice *device,
1078 NMIP4Config **config,
1079 NMDeviceStateReason *reason)
1080{
1081 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
1082 NMConnection *connection;
1083 NMSettingIP4Config *s_ip4;
1084
1085 g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
1086 g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
1087 g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
1088
1089 connection = nm_act_request_get_connection (nm_device_get_act_request (device));
1090 g_assert (connection);
1091
1092 s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
1093
1094 *config = priv->pending_ip4_config;
1095 priv->pending_ip4_config = NULL;
1096 nm_utils_merge_ip4_config (*config, s_ip4);
1097
1098 return NM_ACT_STAGE_RETURN_SUCCESS;
1099}
1100
1101static void
1102cleanup_device (NMSerialDevice *device)
1103{
1104 NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
1105
1106 nm_device_set_ip_iface (NM_DEVICE (device), NULL);
1107
1108 if (priv->pending_ip4_config) {
1109 g_object_unref (priv->pending_ip4_config);
1110 priv->pending_ip4_config = NULL;
1111 }
1112
1113 priv->in_bytes = priv->out_bytes = 0;
1114}
1115
1116static void
1117real_deactivate_quickly (NMDevice *device)
1118{
1119 NMSerialDevice *self = NM_SERIAL_DEVICE (device);
1120
1121 cleanup_device (self);
1122 nm_serial_device_close (self);
1123}
1124
1125static guint32
1126real_get_generic_capabilities (NMDevice *dev)
1127{
1128 return NM_DEVICE_CAP_NM_SUPPORTED;
1129}
1130
1131/*****************************************************************************/
1132
1133static void
1134nm_serial_device_init (NMSerialDevice *self)
1135{
1136 if (getenv ("NM_SERIAL_DEBUG"))
1137 serial_debug = TRUE;
1138}
1139
1140static void
1141finalize (GObject *object)
1142{
1143 NMSerialDevice *self = NM_SERIAL_DEVICE (object);
1144
1145 cleanup_device (self);
1146 nm_serial_device_close (self);
1147
1148 G_OBJECT_CLASS (nm_serial_device_parent_class)->finalize (object);
1149}
1150
1151static void
1152nm_serial_device_class_init (NMSerialDeviceClass *klass)
1153{
1154 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1155 NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
1156
1157 g_type_class_add_private (object_class, sizeof (NMSerialDevicePrivate));
1158
1159 /* Virtual methods */
1160 object_class->finalize = finalize;
1161
1162 parent_class->get_generic_capabilities = real_get_generic_capabilities;
1163 parent_class->act_stage2_config = real_act_stage2_config;
1164 parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
1165 parent_class->deactivate_quickly = real_deactivate_quickly;
1166
1167 /* Signals */
1168 signals[PPP_STATS] =
1169 g_signal_new ("ppp-stats",
1170 G_OBJECT_CLASS_TYPE (object_class),
1171 G_SIGNAL_RUN_FIRST,
1172 G_STRUCT_OFFSET (NMSerialDeviceClass, ppp_stats),
1173 NULL, NULL,
1174 _nm_marshal_VOID__UINT_UINT,
1175 G_TYPE_NONE, 2,
1176 G_TYPE_UINT, G_TYPE_UINT);
1177
1178 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
1179 &dbus_glib_nm_serial_device_object_info);
1180}
diff --git a/src/nm-serial-device.h b/src/nm-serial-device.h
deleted file mode 100644
index 6e9b53bef0..0000000000
--- a/src/nm-serial-device.h
+++ /dev/null
@@ -1,110 +0,0 @@
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2007 - 2008 Novell, Inc.
19 * Copyright (C) 2007 - 2008 Red Hat, Inc.
20 */
21
22#ifndef NM_SERIAL_DEVICE_H
23#define NM_SERIAL_DEVICE_H
24
25#include <nm-device.h>
26#include <nm-setting-serial.h>
27#include "ppp-manager/nm-ppp-manager.h"
28
29G_BEGIN_DECLS
30
31#define NM_TYPE_SERIAL_DEVICE (nm_serial_device_get_type ())
32#define NM_SERIAL_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SERIAL_DEVICE, NMSerialDevice))
33#define NM_SERIAL_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SERIAL_DEVICE, NMSerialDeviceClass))
34#define NM_IS_SERIAL_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SERIAL_DEVICE))
35#define NM_IS_SERIAL_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SERIAL_DEVICE))
36#define NM_SERIAL_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SERIAL_DEVICE, NMSerialDeviceClass))
37
38typedef struct {
39 NMDevice parent;
40} NMSerialDevice;
41
42typedef struct {
43 NMDeviceClass parent;
44
45 const char * (*get_ppp_name) (NMSerialDevice *device, NMActRequest *req);
46
47 /* Signals */
48 void (*ppp_stats) (NMSerialDevice *device, guint32 in_bytes, guint32 out_bytes);
49} NMSerialDeviceClass;
50
51GType nm_serial_device_get_type (void);
52
53typedef void (*NMSerialGetReplyFn) (NMSerialDevice *device,
54 const char *reply,
55 gpointer user_data);
56
57typedef void (*NMSerialWaitForReplyFn) (NMSerialDevice *device,
58 int reply_index,
59 const char *reply,
60 gpointer user_data);
61
62typedef void (*NMSerialWaitQuietFn) (NMSerialDevice *device,
63 gboolean timed_out,
64 gpointer user_data);
65
66typedef void (*NMSerialFlashFn) (NMSerialDevice *device,
67 gpointer user_data);
68
69
70
71gboolean nm_serial_device_open (NMSerialDevice *device,
72 NMSettingSerial *setting);
73
74void nm_serial_device_close (NMSerialDevice *device);
75gboolean nm_serial_device_send_command (NMSerialDevice *device,
76 GByteArray *command);
77
78gboolean nm_serial_device_send_command_string (NMSerialDevice *device,
79 const char *str);
80
81int nm_serial_device_wait_reply_blocking (NMSerialDevice *device,
82 guint32 timeout_secs,
83 const char **needles,
84 const char **terminators);
85
86guint nm_serial_device_wait_for_reply (NMSerialDevice *device,
87 guint timeout,
88 const char **responses,
89 const char **terminators,
90 NMSerialWaitForReplyFn callback,
91 gpointer user_data);
92
93void nm_serial_device_wait_quiet (NMSerialDevice *device,
94 guint timeout,
95 guint quiet_time,
96 NMSerialWaitQuietFn callback,
97 gpointer user_data);
98
99guint nm_serial_device_flash (NMSerialDevice *device,
100 guint32 flash_time,
101 NMSerialFlashFn callback,
102 gpointer user_data);
103
104GIOChannel *nm_serial_device_get_io_channel (NMSerialDevice *device);
105
106NMPPPManager *nm_serial_device_get_ppp_manager (NMSerialDevice *device);
107
108G_END_DECLS
109
110#endif /* NM_SERIAL_DEVICE_H */