From c0c8954828788033ad43f07d7915101378ee2605 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 15:45:50 -0800 Subject: gsm: fix PUK2 and other PIN unlock code recognition Longer entries first so we catch them before matching shorter substrings. Previously, the strcmp() would have treated PUK2 and PUK unlocks the same. --- src/mm-generic-gsm.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index dcb37c32..3cc0f566 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -156,21 +156,22 @@ typedef struct { } CPinResult; static CPinResult unlock_results[] = { - { "SIM PIN", "sim-pin", MM_MOBILE_ERROR_SIM_PIN }, - { "SIM PUK", "sim-puk", MM_MOBILE_ERROR_SIM_PUK }, - { "PH-SIM PIN", "ph-sim-pin", MM_MOBILE_ERROR_PH_SIM_PIN }, + /* Longer entries first so we catch the correct one with strcmp() */ + { "PH-NETSUB PIN", "ph-netsub-pin", MM_MOBILE_ERROR_NETWORK_SUBSET_PIN }, + { "PH-NETSUB PUK", "ph-netsub-puk", MM_MOBILE_ERROR_NETWORK_SUBSET_PUK }, { "PH-FSIM PIN", "ph-fsim-pin", MM_MOBILE_ERROR_PH_FSIM_PIN }, { "PH-FSIM PUK", "ph-fsim-puk", MM_MOBILE_ERROR_PH_FSIM_PUK }, - { "SIM PIN2", "sim-pin2", MM_MOBILE_ERROR_SIM_PIN2 }, - { "SIM PUK2", "sim-puk2", MM_MOBILE_ERROR_SIM_PUK2 }, + { "PH-CORP PIN", "ph-corp-pin", MM_MOBILE_ERROR_CORP_PIN }, + { "PH-CORP PUK", "ph-corp-puk", MM_MOBILE_ERROR_CORP_PUK }, + { "PH-SIM PIN", "ph-sim-pin", MM_MOBILE_ERROR_PH_SIM_PIN }, { "PH-NET PIN", "ph-net-pin", MM_MOBILE_ERROR_NETWORK_PIN }, { "PH-NET PUK", "ph-net-puk", MM_MOBILE_ERROR_NETWORK_PUK }, - { "PH-NETSUB PIN", "ph-netsub-pin", MM_MOBILE_ERROR_NETWORK_SUBSET_PIN }, - { "PH-NETSUB PUK", "ph-netsub-puk", MM_MOBILE_ERROR_NETWORK_SUBSET_PUK }, { "PH-SP PIN", "ph-sp-pin", MM_MOBILE_ERROR_SERVICE_PIN }, { "PH-SP PUK", "ph-sp-puk", MM_MOBILE_ERROR_SERVICE_PUK }, - { "PH-CORP PIN", "ph-corp-pin", MM_MOBILE_ERROR_CORP_PIN }, - { "PH-CORP PUK", "ph-corp-puk", MM_MOBILE_ERROR_CORP_PUK }, + { "SIM PIN2", "sim-pin2", MM_MOBILE_ERROR_SIM_PIN2 }, + { "SIM PUK2", "sim-puk2", MM_MOBILE_ERROR_SIM_PUK2 }, + { "SIM PIN", "sim-pin", MM_MOBILE_ERROR_SIM_PIN }, + { "SIM PUK", "sim-puk", MM_MOBILE_ERROR_SIM_PUK }, { NULL, NULL, MM_MOBILE_ERROR_PHONE_FAILURE }, }; -- cgit v1.2.3-70-g09d2 From 8f50dd319189c0a9aef4d41957450096029f4b60 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 15:56:27 -0800 Subject: gsm: close open ports on Enable errors --- src/mm-generic-gsm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 3cc0f566..e9100b34 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -665,11 +665,18 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, g_return_if_fail (MM_IS_GENERIC_GSM (self)); g_return_if_fail (info != NULL); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + if (error) { mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); + if (priv->primary && mm_serial_port_is_open (priv->primary)) + mm_serial_port_close (priv->primary); + if (priv->secondary && mm_serial_port_is_open (priv->secondary)) + mm_serial_port_close (priv->secondary); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; @@ -678,8 +685,6 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE); } - priv = MM_GENERIC_GSM_GET_PRIVATE (self); - /* Open the second port here if the modem has one. We'll use it for * signal strength and registration updates when the device is connected, * but also many devices will send unsolicited registration or other -- cgit v1.2.3-70-g09d2 From 13bc593a291a5bb5ff004b553268443b5d2c83aa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 16:30:58 -0800 Subject: gsm: ensure PDP context deactivation happens on disconnect The port is still connected until disconnect_done() runs, but by this point we already know it's been disconnected so it's safe to run the CGACT commands. --- src/mm-generic-gsm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index e9100b34..cab564ae 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -1966,13 +1966,19 @@ disconnect_flash_done (MMSerialPort *port, char *command; info->error = mm_modem_check_removed (info->modem, error); - if (info->error) { + /* Ignore NO_CARRIER errors and proceed with the PDP context deactivation */ + if ( info->error + && !g_error_matches (info->error, + MM_MODEM_CONNECT_ERROR, + MM_MODEM_CONNECT_ERROR_NO_CARRIER)) { mm_callback_info_schedule (info); return; } - /* Disconnect the PDP context */ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + mm_port_set_connected (priv->data, FALSE); + + /* Disconnect the PDP context */ if (priv->cid >= 0) command = g_strdup_printf ("+CGACT=0,%d", priv->cid); else { @@ -1980,7 +1986,7 @@ disconnect_flash_done (MMSerialPort *port, command = g_strdup_printf ("+CGACT=0"); } - mm_serial_port_queue_command (port, command, 60, disconnect_cgact_done, info); + mm_serial_port_queue_command (port, command, 3, disconnect_cgact_done, info); g_free (command); } -- cgit v1.2.3-70-g09d2 From 749f9c0eb569b29772dde9561b9856e4f878d9ef Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Mar 2010 13:20:43 -0800 Subject: core: stop probing known-unusable ports early Some ports we know we shouldn't use when we get certain responses from them. Reading from these ports triggers kernel bugs (at least on 2.6.31 and 2.6.32) relating to flow control in some drivers (*cough* hso *cough*), so lets try not to aggravate the kernel too much. This happens on Icera-based Option devices like the GI0322 (AT&T Quicksilver) for example. (note: AFAICT this doesn't have any relation to the recent XON/XOFF patch, since I get this problem without the XON/XOFF patch on both 2.6.31 and 2.6.32 as well) --- BUG: sleeping function called from invalid context at kernel/mutex.c:94 in_atomic(): 1, irqs_disabled(): 1, pid: 9295, name: modem-manager Pid: 9295, comm: modem-manager Not tainted 2.6.32.9-67.fc12.x86_64 #1 Call Trace: [] __might_sleep+0xed/0xef [] mutex_lock+0x24/0x50 [] ? enqueue_task_fair+0x2a/0x6d [] tty_throttle+0x1b/0x49 [] n_tty_receive_buf+0xdbb/0xe12 [] ? task_rq_unlock+0x11/0x13 [] ? try_to_wake_up+0x2f3/0x305 [] ? __kmalloc+0x37/0x15e [] ? __kmalloc+0x6d/0x15e [] flush_to_ldisc+0xf8/0x18d [] tty_flip_buffer_push+0x50/0x61 [] put_rxbuf_data+0xea/0x124 [hso] [] put_rxbuf_data_and_resubmit_bulk_urb+0x21/0x6b [hso] [] hso_std_serial_read_bulk_callback+0x14d/0x15f [hso] [] ? dma_unmap_single_attrs.clone.0+0x38/0x3a [] usb_hcd_giveback_urb+0x91/0xc5 [] ehci_urb_done+0x7b/0x90 [] ? try_to_wake_up+0x2f3/0x305 [] qh_completions+0x368/0x4b9 [] ? __wake_up_common+0x4e/0x84 [] ehci_work+0x95/0x732 [] ? __wake_up+0x44/0x4d [] ? insert_work+0x8e/0x9b [] ehci_irq+0x2be/0x420 [] ? __queue_work+0x3a/0x41 [] ? resched_cpu+0x6e/0x77 [] ? delayed_work_timer_fn+0x3c/0x3e [] ? __rcu_process_callbacks+0x7d/0x28a [] usb_hcd_irq+0x3f/0x7b [] handle_IRQ_event+0x60/0x121 [] handle_fasteoi_irq+0x8b/0xc7 [] handle_irq+0x8b/0x96 [] do_IRQ+0x5c/0xbc [] ret_from_intr+0x0/0x11 --- src/mm-plugin-base.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/mm-serial-port.c | 29 ++++++++++++++++++++------- src/mm-serial-port.h | 3 +++ 3 files changed, 79 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 202eaac9..4b74feb7 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -77,6 +77,8 @@ typedef enum { PROBE_STATE_LAST } ProbeState; +static void probe_complete (MMPluginBaseSupportsTask *task); + /*****************************************************************************/ G_DEFINE_TYPE (MMPluginBaseSupportsTask, mm_plugin_base_supports_task, G_TYPE_OBJECT) @@ -91,6 +93,7 @@ typedef struct { guint open_id; guint32 open_tries; + guint full_id; MMSerialPort *probe_port; guint32 probed_caps; @@ -198,6 +201,11 @@ mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task, priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); g_return_if_fail (priv->callback != NULL); + if (priv->full_id) { + g_source_remove (priv->full_id); + priv->full_id = 0; + } + subsys = g_udev_device_get_subsystem (priv->port); name = g_udev_device_get_name (priv->port); @@ -251,11 +259,15 @@ supports_task_dispose (GObject *object) if (priv->open_id) g_source_remove (priv->open_id); + if (priv->full_id) + g_source_remove (priv->full_id); if (priv->probe_id) g_source_remove (priv->probe_id); - if (priv->probe_port) + if (priv->probe_port) { + mm_serial_port_close (priv->probe_port); g_object_unref (priv->probe_port); + } G_OBJECT_CLASS (mm_plugin_base_supports_task_parent_class)->dispose (object); } @@ -349,6 +361,44 @@ parse_cgmm (const char *buf) return 0; } +static const char *dq_strings[] = { + "option/faema_", "os_logids.h", NULL +}; + +static void +port_buffer_full (MMSerialPort *port, GString *buffer, gpointer user_data) +{ + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (user_data); + const char **iter; + size_t iter_len; + int i; + + /* Check for an immediate disqualification response. There are some + * ports (Option Icera-based chipsets have them, as do Qualcomm Gobi + * devices before their firmware is loaded) that just shouldn't be + * probed if we get a certain response because we know they can't be + * used. Kernel bugs (at least with 2.6.31 and 2.6.32) also trigger port + * flow control kernel oopses if we read too much data for these ports. + */ + + for (iter = &dq_strings[0]; iter && *iter; iter++) { + /* Search in the response for the item; the response could have embedded + * nulls so we can't use memcmp() or strstr() on the whole response. + */ + iter_len = strlen (*iter); + for (i = 0; i < buffer->len - iter_len; i++) { + if (!memcmp (&buffer->str[i], *iter, iter_len)) { + /* Immediately close the port and complete probing */ + priv->probed_caps = 0; + mm_serial_port_close (priv->probe_port); + probe_complete (task); + return; + } + } + } +} + static gboolean emit_probe_result (gpointer user_data) { @@ -626,6 +676,9 @@ try_open (gpointer user_data) port = mm_plugin_base_supports_task_get_port (task); g_assert (port); + task_priv->full_id = g_signal_connect (task_priv->probe_port, "buffer-full", + G_CALLBACK (port_buffer_full), task); + g_debug ("(%s): probe requested by plugin '%s'", g_udev_device_get_name (port), mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 1d98a537..2134751f 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -730,9 +730,13 @@ data_available (GIOChannel *source, status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err); if (status == G_IO_STATUS_ERROR) { - g_warning ("%s", err->message); - g_error_free (err); - err = NULL; + if (err && err->message) + g_warning ("%s", err->message); + g_clear_error (&err); + + /* Serial port is closed; we're done */ + if (priv->watch_id == 0) + break; } /* If no bytes read, just let g_io_channel wait for more data */ @@ -745,10 +749,10 @@ data_available (GIOChannel *source, } /* Make sure the string doesn't grow too long */ - if (priv->response->len > SERIAL_BUF_SIZE) { - g_warning ("%s (%s): response buffer filled before repsonse received", - G_STRFUNC, mm_port_get_device (MM_PORT (self))); - g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); + if (priv->response->len > SERIAL_BUF_SIZE) { + /* Notify listeners and then trim the buffer */ + g_signal_emit_by_name (self, "buffer-full", priv->response); + g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); } if (parse_response (self, priv->response, &err)) @@ -888,6 +892,7 @@ mm_serial_port_close (MMSerialPort *self) if (priv->channel) { g_source_remove (priv->watch_id); + priv->watch_id = 0; g_io_channel_shutdown (priv->channel, TRUE, NULL); g_io_channel_unref (priv->channel); priv->channel = NULL; @@ -1293,4 +1298,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass) "Send delay", 0, G_MAXUINT64, 0, G_PARAM_READWRITE)); + + /* Signals */ + g_signal_new ("buffer-full", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMSerialPortClass, buffer_full), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); } + diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index a2697f30..dd5a6689 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -62,6 +62,9 @@ struct _MMSerialPort { struct _MMSerialPortClass { MMPortClass parent; + + /* Signals */ + void (*buffer_full) (MMSerialPort *port, const GString *buffer); }; GType mm_serial_port_get_type (void); -- cgit v1.2.3-70-g09d2