[PATCH 3/3] qcdm: add utility to display and set the IPv6 preference
Dan Williams
dcbw at redhat.com
Wed Nov 27 09:28:14 PST 2013
On Wed, 2013-11-27 at 12:54 +0100, Bjørn Mork wrote:
> Signed-off-by: Bjørn Mork <bjorn at mork.no>
Same thing, pref -> enabled everywhere maybe? Might make sense to leave
the executable as ipv6pref though, since having an executable named
ipv6enabled doesn't really mean what we want it to mean.
Dan
> ---
> .gitignore | 1 +
> libqcdm/tests/Makefile.am | 8 +-
> libqcdm/tests/ipv6pref.c | 316 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 324 insertions(+), 1 deletion(-)
> create mode 100644 libqcdm/tests/ipv6pref.c
>
> diff --git a/.gitignore b/.gitignore
> index 0c379af..8608a5d 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -61,6 +61,7 @@ vapi/libmm-glib.vapi
>
> libqcdm/tests/test-qcdm
> libqcdm/tests/modepref
> +libqcdm/tests/ipv6pref
> libwmc/tests/test-wmc
>
> data/org.freedesktop.ModemManager1.conf
> diff --git a/libqcdm/tests/Makefile.am b/libqcdm/tests/Makefile.am
> index ddf7d7b..241ae03 100644
> --- a/libqcdm/tests/Makefile.am
> +++ b/libqcdm/tests/Makefile.am
> @@ -1,6 +1,6 @@
> include $(top_srcdir)/gtester.make
>
> -noinst_PROGRAMS = test-qcdm modepref
> +noinst_PROGRAMS = test-qcdm modepref ipv6pref
> TEST_PROGS += test-qcdm
>
> INCLUDES = \
> @@ -26,10 +26,16 @@ modepref_SOURCES = modepref.c
> modepref_CPPFLAGS = $(MM_CFLAGS)
> modepref_LDADD = $(MM_LIBS)
>
> +ipv6pref_SOURCES = ipv6pref.c
> +ipv6pref_CPPFLAGS = $(MM_CFLAGS)
> +ipv6pref_LDADD = $(MM_LIBS)
> +
> if QCDM_STANDALONE
> test_qcdm_LDADD += $(top_builddir)/src/libqcdm.la
> modepref_LDADD += $(top_builddir)/src/libqcdm.la
> +ipv6pref_LDADD += $(top_builddir)/src/libqcdm.la
> else
> test_qcdm_LDADD += $(top_builddir)/libqcdm/src/libqcdm.la
> modepref_LDADD += $(top_builddir)/libqcdm/src/libqcdm.la
> +ipv6pref_LDADD += $(top_builddir)/libqcdm/src/libqcdm.la
> endif
> diff --git a/libqcdm/tests/ipv6pref.c b/libqcdm/tests/ipv6pref.c
> new file mode 100644
> index 0000000..8b97d0b
> --- /dev/null
> +++ b/libqcdm/tests/ipv6pref.c
> @@ -0,0 +1,316 @@
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
> +/* This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Copyright (C) 2012 Red Hat, Inc.
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <fcntl.h>
> +#include <termios.h>
> +#include <assert.h>
> +#include <unistd.h>
> +
> +#include "utils.h"
> +#include "errors.h"
> +#include "commands.h"
> +#include "com.h"
> +
> +static int debug = 0;
> +
> +static void
> +print_buf (const char *detail, const char *buf, size_t len)
> +{
> + int i = 0, z;
> + qcdmbool newline = FALSE;
> + char tmp[500];
> + u_int32_t flen;
> +
> + flen = snprintf (tmp, sizeof (tmp) - 1, "%s (%zu) ", detail, len);
> + fprintf (stdout, "%s", tmp);
> + for (i = 0; i < len; i++) {
> + fprintf (stdout, "%02x ", buf[i] & 0xFF);
> + if (((i + 1) % 16) == 0) {
> + fprintf (stdout, "\n");
> + z = flen;
> + while (z--)
> + fprintf (stdout, " ");
> + newline = TRUE;
> + } else
> + newline = FALSE;
> + }
> +
> + if (!newline)
> + fprintf (stdout, "\n");
> +}
> +
> +static int
> +com_setup (const char *port)
> +{
> + int ret, fd;
> +
> + errno = 0;
> + fd = open (port, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
> + if (fd < 0) {
> + fprintf (stderr, "E: failed to open port %s\n", port);
> + return -1;
> + }
> +
> + ret = ioctl (fd, TIOCEXCL);
> + if (ret) {
> + fprintf (stderr, "E: failed to lock port %s\n", port);
> + close (fd);
> + return -1;
> + }
> +
> + return fd;
> +}
> +
> +/******************************************************************/
> +
> +static qcdmbool
> +qcdm_send (int fd, char *buf, size_t len)
> +{
> + int status;
> + int eagain_count = 1000;
> + size_t i = 0;
> +
> + if (debug)
> + print_buf ("DM:ENC>>>", buf, len);
> +
> + while (i < len) {
> + errno = 0;
> + status = write (fd, &buf[i], 1);
> + if (status < 0) {
> + if (errno == EAGAIN) {
> + eagain_count--;
> + if (eagain_count <= 0)
> + return FALSE;
> + } else
> + assert (errno == 0);
> + } else
> + i++;
> +
> + usleep (1000);
> + }
> +
> + return TRUE;
> +}
> +
> +static size_t
> +qcdm_wait_reply (int fd, char *buf, size_t len)
> +{
> + fd_set in;
> + int result;
> + struct timeval timeout = { 1, 0 };
> + char readbuf[1024];
> + ssize_t bytes_read;
> + int total = 0, retries = 0;
> + size_t decap_len = 0;
> +
> + FD_ZERO (&in);
> + FD_SET (fd, &in);
> + result = select (fd + 1, &in, NULL, NULL, &timeout);
> + if (result != 1 || !FD_ISSET (fd, &in))
> + return 0;
> +
> + do {
> + errno = 0;
> + bytes_read = read (fd, &readbuf[total], 1);
> + if ((bytes_read == 0) || (errno == EAGAIN)) {
> + /* Haven't gotten the async control char yet */
> + if (retries > 20)
> + return 0; /* 2 seconds, give up */
> +
> + /* Otherwise wait a bit and try again */
> + usleep (100000);
> + retries++;
> + continue;
> + } else if (bytes_read == 1) {
> + qcdmbool more = FALSE;
> + qcdmbool success;
> + size_t used = 0;
> +
> + total++;
> + decap_len = 0;
> + success = dm_decapsulate_buffer (readbuf, total, buf, len, &decap_len, &used, &more);
> +
> + /* Discard used data */
> + if (used > 0) {
> + total -= used;
> + memmove (readbuf, &readbuf[used], total);
> + }
> +
> + if (success && !more) {
> + /* Success; we have a packet */
> + break;
> + }
> + } else {
> + /* Some error occurred */
> + return 0;
> + }
> + } while (total < sizeof (readbuf));
> +
> + if (debug)
> + print_buf ("QCDM:DEC<<", buf, decap_len);
> +
> + return decap_len;
> +}
> +
> +static int
> +qcdm_set_ipv6_pref (int fd, u_int8_t ipv6pref)
> +{
> + int err;
> + char buf[512];
> + size_t len;
> + QcdmResult *result;
> + size_t reply_len;
> +
> + len = qcdm_cmd_nv_set_ipv6_pref_new (buf, sizeof (buf), ipv6pref);
> + assert (len);
> +
> + /* Send the command */
> + if (!qcdm_send (fd, buf, len)) {
> + fprintf (stderr, "E: failed to send QCDM IPv6 pref command\n");
> + return -1;
> + }
> +
> + reply_len = qcdm_wait_reply (fd, buf, sizeof (buf));
> + if (!reply_len) {
> + fprintf (stderr, "E: failed to receive QCDM IPv6 pref command reply\n");
> + return -1;
> + }
> +
> + /* Parse the response into a result structure */
> + err = QCDM_SUCCESS;
> + result = qcdm_cmd_nv_set_ipv6_pref_result (buf, reply_len, &err);
> + if (!result) {
> + fprintf (stderr, "E: failed to parse QCDM IPv6 pref command reply: %d\n", err);
> + return -1;
> + }
> +
> + qcdm_result_unref (result);
> + return 0;
> +}
> +
> +static int
> +qcdm_get_ipv6_pref (int fd)
> +{
> + int err;
> + char buf[512];
> + size_t len;
> + QcdmResult *result;
> + size_t reply_len;
> + u_int8_t mode;
> +
> + len = qcdm_cmd_nv_get_ipv6_pref_new (buf, sizeof (buf));
> + assert (len);
> +
> + /* Send the command */
> + if (!qcdm_send (fd, buf, len)) {
> + fprintf (stderr, "E: failed to send QCDM IPv6 pref command\n");
> + return -1;
> + }
> +
> + reply_len = qcdm_wait_reply (fd, buf, sizeof (buf));
> + if (!reply_len) {
> + fprintf (stderr, "E: failed to receive QCDM IPv6 pref command reply\n");
> + return -1;
> + }
> +
> + /* Parse the response into a result structure */
> + err = QCDM_SUCCESS;
> + result = qcdm_cmd_nv_get_ipv6_pref_result (buf, reply_len, &err);
> + if (!result) {
> + /* An inactive NVRAM entry has the same effect as setting "disabled" */
> + if (err == -QCDM_ERROR_NV_ERROR_INACTIVE)
> + return QCDM_CMD_NV_IPV6_PREF_ITEM_REV_IPV6_OFF;
> +
> + fprintf (stderr, "E: failed to parse QCDM IPv6 pref command reply: %d\n", err);
> + return -1;
> + }
> +
> + err = qcdm_result_get_u8 (result, QCDM_CMD_NV_GET_IPV6_PREF_ITEM_IPV6_PREF, &mode);
> + qcdm_result_unref (result);
> + return mode;
> +}
> +
> +/******************************************************************/
> +
> +static void
> +usage (const char *prog)
> +{
> + fprintf (stderr, "Usage: %s <DM port> [--enable|--disable] [--debug]\n", prog);
> + fprintf (stderr, " Current mode will always be printed.\n\n");
> +}
> +
> +int
> +main (int argc, char *argv[])
> +{
> + const char *dmport = argv[1];
> + int fd, err, old, new = -1;
> +
> + if (argc < 2 || argc > 4) {
> + usage (argv[0]);
> + return 1;
> + }
> +
> + if (argc >= 3) {
> + if (strcasecmp (argv[2], "--debug") == 0)
> + debug = 1;
> + else if (strcasecmp (argv[2], "--enable") == 0)
> + new = QCDM_CMD_NV_IPV6_PREF_ITEM_REV_IPV6_ON;
> + else if (strcasecmp (argv[2], "--disable") == 0)
> + new = QCDM_CMD_NV_IPV6_PREF_ITEM_REV_IPV6_OFF;
> + else
> + usage (argv[0]);
> +
> + if (argc >= 4 && strcasecmp (argv[3], "--debug") == 0)
> + debug = 1;
> + }
> +
> + if (debug)
> + putenv ("QCDM_DEBUG=1");
> +
> + fd = com_setup (dmport);
> + if (fd < 0)
> + return 1;
> +
> + err = qcdm_port_setup (fd);
> + if (err != QCDM_SUCCESS) {
> + fprintf (stderr, "E: failed to set up DM port %s: %d\n", dmport, err);
> + return 1;
> + }
> +
> + old = qcdm_get_ipv6_pref (fd);
> + if (old < 0) {
> + fprintf (stderr, "E: failed to get IPv6 preference\n");
> + return 1;
> + }
> + fprintf (stdout, "IPv6: %s\n", old ? "enabled" : "disabled");
> +
> + if (new >=0 && old != new) {
> + if (qcdm_set_ipv6_pref (fd, new))
> + fprintf (stdout, "Failed to set IPv6 preference\n");
> + else
> + fprintf (stdout, "IPv6 successfully %s. Replug your device.\n", new ? "enabled" : "disabled");
> + }
> +
> + return 0;
> +}
> +
More information about the ModemManager-devel
mailing list