Send commitlog mailing list submissions to
        commitlog@lists.openmoko.org

To subscribe or unsubscribe via the World Wide Web, visit
        http://lists.openmoko.org/mailman/listinfo/commitlog
or, via email, send a message with subject or body 'help' to
        commitlog-requ...@lists.openmoko.org

You can reach the person managing the list at
        commitlog-ow...@lists.openmoko.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of commitlog digest..."
Today's Topics:

   1. r4884 - in developers/werner: . wolfhammer
      (wer...@docs.openmoko.org)
   2. r4885 - developers/werner/wolfhammer (wer...@docs.openmoko.org)
   3. r4886 - in developers/werner: . wlan wlan/connman
      (wer...@docs.openmoko.org)
--- Begin Message ---
Author: werner
Date: 2009-01-13 18:03:14 +0100 (Tue, 13 Jan 2009)
New Revision: 4884

Added:
   developers/werner/wolfhammer/
   developers/werner/wolfhammer/Makefile
   developers/werner/wolfhammer/wolfhammer.c
Log:
Hammer the Wolfson, for MICBIAS testing.



Added: developers/werner/wolfhammer/Makefile
===================================================================
--- developers/werner/wolfhammer/Makefile                               (rev 0)
+++ developers/werner/wolfhammer/Makefile       2009-01-13 17:03:14 UTC (rev 
4884)
@@ -0,0 +1,35 @@
+CC=arm-angstrom-linux-gnueabi-gcc
+
+CFLAGS=-Wall -Wshadow -g -O
+LDFLAGS=-lm
+
+PREFIX=/usr
+
+NAME=wolfhammer
+OBJS=wolfhammer.o
+
+.PHONY:                all install uninstall clean depend spotless
+
+all:           $(NAME)
+
+$(NAME):       $(OBJS)
+
+install:       $(NAME)
+               install -D $(NAME) $(PREFIX)/bin/$(NAME)
+
+uninstall:
+               rm -f $(PREFIX)/bin/$(NAME)
+
+depend:
+               $(CPP) $(CFLAGS) -MM -MG *.c >.depend || \
+                 { rm -f .depend; exit 1; }
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+clean:
+               rm -f $(OBJS) .depend
+
+spotless:      clean
+               rm -f $(NAME)

Added: developers/werner/wolfhammer/wolfhammer.c
===================================================================
--- developers/werner/wolfhammer/wolfhammer.c                           (rev 0)
+++ developers/werner/wolfhammer/wolfhammer.c   2009-01-13 17:03:14 UTC (rev 
4884)
@@ -0,0 +1,113 @@
+/*
+ * wolfhammer.c - Hammer the Wolfson codec over I2C (toggle MICBIAS)
+ *
+ * Copyright (C) 2009 by OpenMoko, Inc.
+ * Written by Werner Almesberger <wer...@openmoko.org>
+ * All Rights Reserved
+ *  
+ * 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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+
+#define I2C_DEVICE     "/dev/i2c-0"
+#define I2C_ADDRESS    0x1a
+
+
+/*
+ * Register 0x14, Power Management (1)
+ *
+ * Bit#
+ * 7-8 VMIDSEL         3 = max
+ *  6  VREF            1 = on
+ *  5  MICB            0 = off, 1 = on
+ *  4  VDAC            0 = off
+ *  3  DACL            0 = off
+ *  2  DACR            0 = off
+ *  1  0
+ *  0  DIGENB          0 = MCLK enabled
+ *
+ * Register 0x33, Mic Bias comp control
+ *
+ * Bit#
+ *  8  MBVSEL          0 = 0.9*AVDD, 1 = 0.75*AVDD
+ * 5-6 MICSEL
+ * 4-5 MBSCTHRESH
+ * 1-3 MBTHRESH
+ *  0  MBCEN
+ */
+
+#define MICBIAS_ON     0x14 << 1 | 1, 0xe0
+#define MICBIAS_OFF    0x14 << 1 | 1, 0xc0
+
+
+static void codec_write(int fd, uint8_t reg, uint8_t value)
+{
+       struct i2c_smbus_ioctl_data msg = {
+               .read_write     = I2C_SMBUS_WRITE,
+               .command        = reg,
+               .size           = I2C_SMBUS_BYTE_DATA,
+               .data           = (void *) &value,
+       };
+
+       if (ioctl(fd, I2C_SMBUS, (void *) &msg) < 0) {
+               perror("ioctl(I2C_SMBUS)");
+               exit(1);
+       }
+}
+
+
+static int codec_open(void)
+{
+       int fd;
+
+       fd = open(I2C_DEVICE, O_RDWR);
+       if (fd < 0) {
+               perror(I2C_DEVICE);
+               exit(1);
+       }
+       if (ioctl(fd, I2C_SLAVE_FORCE, I2C_ADDRESS) < 0) {
+               perror("ioctl(I2C_SLAVE_FORCE)");
+               exit(1);
+       }
+       return fd;
+}
+
+
+static void usage(const char *name)
+{
+       fprintf(stderr, "usage: %s loops\n", name);
+       exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+       unsigned long n, i;
+       char *end;
+       int fd;
+
+       if (argc != 2)
+               usage(*argv);
+       n = strtoul(argv[1], &end, 0);
+       if (*end)
+               usage(*argv);
+
+       fd = codec_open();
+       for (i = 0; i != n; i++) {
+               codec_write(fd, MICBIAS_ON);
+               codec_write(fd, MICBIAS_OFF);
+       }
+       return 0;
+}




--- End Message ---
--- Begin Message ---
Author: werner
Date: 2009-01-14 00:51:53 +0100 (Wed, 14 Jan 2009)
New Revision: 4885

Modified:
   developers/werner/wolfhammer/wolfhammer.c
Log:
Changed frequency from 50Hz to 40Hz, to avoid confusion with mains.
http://people.openmoko.org/werner/a6-nrw-fft.png



Modified: developers/werner/wolfhammer/wolfhammer.c
===================================================================
--- developers/werner/wolfhammer/wolfhammer.c   2009-01-13 17:03:14 UTC (rev 
4884)
+++ developers/werner/wolfhammer/wolfhammer.c   2009-01-13 23:51:53 UTC (rev 
4885)
@@ -14,6 +14,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
@@ -107,6 +108,7 @@
        fd = codec_open();
        for (i = 0; i != n; i++) {
                codec_write(fd, MICBIAS_ON);
+               usleep(100);
                codec_write(fd, MICBIAS_OFF);
        }
        return 0;




--- End Message ---
--- Begin Message ---
Author: werner
Date: 2009-01-14 01:57:38 +0100 (Wed, 14 Jan 2009)
New Revision: 4886

Added:
   developers/werner/wlan/
   developers/werner/wlan/connman/
   developers/werner/wlan/connman/Makefile
   developers/werner/wlan/connman/detect.c
   developers/werner/wlan/connman/rtnl.c
Log:
connman compatibility test.



Added: developers/werner/wlan/connman/Makefile
===================================================================
--- developers/werner/wlan/connman/Makefile                             (rev 0)
+++ developers/werner/wlan/connman/Makefile     2009-01-14 00:57:38 UTC (rev 
4886)
@@ -0,0 +1,15 @@
+CC=arm-angstrom-linux-gnueabi-gcc
+CFLAGS=-Wall -g \
+       -I.. -I../../include \
+       -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include \
+       -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include
+
+OBJS=detect.o rtnl.o
+
+.PHONY:        all
+
+
+all:   try
+
+try:   $(OBJS)
+       $(CC) -o $@ $(OBJS) -lglib-2.0

Added: developers/werner/wlan/connman/detect.c
===================================================================
--- developers/werner/wlan/connman/detect.c                             (rev 0)
+++ developers/werner/wlan/connman/detect.c     2009-01-14 00:57:38 UTC (rev 
4886)
@@ -0,0 +1,324 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+#define        connman_debug(FMT, ARGS...)     fprintf(stderr, FMT "\n", ARGS)
+#define        connman_device_get_index(...)   0
+#define        connman_device_create(name, devtype) \
+       (fprintf(stderr, "connman_device_create(%s, %d)\n", name, devtype), \
+       (void *) 1)
+#define        connman_device_set_policy(...)
+#define        connman_device_set_mode(...)
+#define        connman_device_set_index(...)
+#define        connman_device_set_interface(device, devname) \
+       fprintf(stderr, "connman_device_set_interface(%s)\n", devname)
+#define        connman_device_register(...)    0
+#define        connman_device_unref(...)
+#define        connman_device_unregister(...)
+
+static GSList *device_list = NULL;
+
+static struct connman_device *find_device(int index)
+{
+       GSList *list;
+
+       for (list = device_list; list; list = list->next) {
+               struct connman_device *device = list->data;
+
+               if (connman_device_get_index(device) == index)
+                       return device;
+       }
+
+       return NULL;
+}
+
+static char *index2name(int index)
+{
+       struct ifreq ifr;
+       int sk, err;
+
+       if (index < 0)
+               return NULL;
+
+       sk = socket(PF_INET, SOCK_DGRAM, 0);
+       if (sk < 0)
+               return NULL;
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_ifindex = index;
+
+       err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+       close(sk);
+
+       if (err < 0)
+               return NULL;
+
+       return strdup(ifr.ifr_name);
+}
+
+static char *index2ident(int index, const char *prefix)
+{
+       struct ifreq ifr;
+       struct ether_addr *eth;
+       char *str;
+       int sk, err, len;
+
+       if (index < 0)
+               return NULL;
+
+       sk = socket(PF_INET, SOCK_DGRAM, 0);
+       if (sk < 0)
+               return NULL;
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_ifindex = index;
+
+       err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+       if (err == 0)
+               err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+
+       close(sk);
+
+       if (err < 0)
+               return NULL;
+
+       len = prefix ? strlen(prefix) + 18 : 18;
+
+       str = malloc(len);
+       if (!str)
+               return NULL;
+
+       eth = (void *) &ifr.ifr_hwaddr.sa_data;
+       snprintf(str, len, "%s%02X_%02X_%02X_%02X_%02X_%02X",
+                                               prefix ? prefix : "",
+                                               eth->ether_addr_octet[0],
+                                               eth->ether_addr_octet[1],
+                                               eth->ether_addr_octet[2],
+                                               eth->ether_addr_octet[3],
+                                               eth->ether_addr_octet[4],
+                                               eth->ether_addr_octet[5]);
+
+       return str;
+}
+
+static void detect_newlink(unsigned short type, int index,
+                                       unsigned flags, unsigned change)
+{
+       enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+       enum connman_device_mode mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+       struct connman_device *device;
+       gchar *name, *devname;
+
+       DBG("type %d index %d", type, index);
+
+       device = find_device(index);
+       if (device != NULL)
+               return;
+
+       devname = index2name(index);
+       if (devname == NULL)
+               return;
+
+       if (type == ARPHRD_ETHER) {
+               char bridge_path[PATH_MAX], wimax_path[PATH_MAX];
+               struct stat st;
+               struct iwreq iwr;
+               int sk;
+
+               snprintf(bridge_path, PATH_MAX,
+                                       "/sys/class/net/%s/bridge", devname);
+               snprintf(wimax_path, PATH_MAX,
+                                       "/sys/class/net/%s/wimax", devname);
+
+               memset(&iwr, 0, sizeof(iwr));
+               strncpy(iwr.ifr_ifrn.ifrn_name, devname, IFNAMSIZ);
+
+               sk = socket(PF_INET, SOCK_DGRAM, 0);
+
+               if (g_str_has_prefix(devname, "bnep") == TRUE)
+                       devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+               else if (stat(bridge_path, &st) == 0 && (st.st_mode & S_IFDIR))
+                       devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+               else if (stat(wimax_path, &st) == 0 && (st.st_mode & S_IFDIR))
+                       devtype = CONNMAN_DEVICE_TYPE_WIMAX;
+               else if (ioctl(sk, SIOCGIWNAME, &iwr) == 0)
+                       devtype = CONNMAN_DEVICE_TYPE_WIFI;
+               else
+                       devtype = CONNMAN_DEVICE_TYPE_ETHERNET;
+
+               close(sk);
+       } else if (type == ARPHRD_NONE) {
+               if (g_str_has_prefix(devname, "hso") == TRUE)
+                       devtype = CONNMAN_DEVICE_TYPE_HSO;
+       }
+
+       switch (devtype) {
+       case CONNMAN_DEVICE_TYPE_UNKNOWN:
+               g_free(devname);
+               return;
+       case CONNMAN_DEVICE_TYPE_ETHERNET:
+       case CONNMAN_DEVICE_TYPE_WIFI:
+       case CONNMAN_DEVICE_TYPE_WIMAX:
+               name = index2ident(index, "dev_");
+               break;
+       case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+       case CONNMAN_DEVICE_TYPE_HSO:
+       case CONNMAN_DEVICE_TYPE_NOZOMI:
+       case CONNMAN_DEVICE_TYPE_HUAWEI:
+       case CONNMAN_DEVICE_TYPE_NOVATEL:
+       case CONNMAN_DEVICE_TYPE_VENDOR:
+               name = strdup(devname);
+               break;
+       }
+
+       device = connman_device_create(name, devtype);
+       if (device == NULL) {
+               g_free(devname);
+               g_free(name);
+               return;
+       }
+
+       switch (devtype) {
+       case CONNMAN_DEVICE_TYPE_UNKNOWN:
+       case CONNMAN_DEVICE_TYPE_VENDOR:
+       case CONNMAN_DEVICE_TYPE_NOZOMI:
+       case CONNMAN_DEVICE_TYPE_HUAWEI:
+       case CONNMAN_DEVICE_TYPE_NOVATEL:
+               mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+               break;
+       case CONNMAN_DEVICE_TYPE_ETHERNET:
+               mode = CONNMAN_DEVICE_MODE_TRANSPORT_IP;
+               break;
+       case CONNMAN_DEVICE_TYPE_WIFI:
+       case CONNMAN_DEVICE_TYPE_WIMAX:
+               mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
+               break;
+       case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+               mode = CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE;
+               break;
+       case CONNMAN_DEVICE_TYPE_HSO:
+               mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
+               connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
+               break;
+       }
+
+       connman_device_set_mode(device, mode);
+
+       connman_device_set_index(device, index);
+       connman_device_set_interface(device, devname);
+
+       g_free(devname);
+       g_free(name);
+
+       if (connman_device_register(device) < 0) {
+               connman_device_unref(device);
+               return;
+       }
+
+       device_list = g_slist_append(device_list, device);
+}
+
+static void detect_dellink(unsigned short type, int index,
+                                       unsigned flags, unsigned change)
+{
+       struct connman_device *device;
+
+       DBG("type %d index %d", type, index);
+
+       device = find_device(index);
+       if (device == NULL)
+               return;
+
+       device_list = g_slist_remove(device_list, device);
+
+       connman_device_unregister(device);
+       connman_device_unref(device);
+}
+
+static struct connman_rtnl detect_rtnl = {
+       .name           = "detect",
+       .priority       = CONNMAN_RTNL_PRIORITY_LOW,
+       .newlink        = detect_newlink,
+       .dellink        = detect_dellink,
+};
+
+int __connman_detect_init(void)
+{
+       int err;
+
+       err = connman_rtnl_register(&detect_rtnl);
+       if (err < 0)
+               return err;
+
+       connman_rtnl_send_getlink();
+
+       return 0;
+}
+
+void __connman_detect_cleanup(void)
+{
+       GSList *list;
+
+       connman_rtnl_unregister(&detect_rtnl);
+
+       for (list = device_list; list; list = list->next) {
+               struct connman_device *device = list->data;
+
+               connman_device_unregister(device);
+               connman_device_unref(device);
+       }
+
+       g_slist_free(device_list);
+       device_list = NULL;
+}
+
+
+int main(void)
+{
+       GMainLoop *loop;
+
+       loop = g_main_loop_new(NULL, TRUE);
+       __connman_rtnl_init();
+       __connman_detect_init();
+       g_main_loop_run(loop);
+       return 0;
+}

Added: developers/werner/wlan/connman/rtnl.c
===================================================================
--- developers/werner/wlan/connman/rtnl.c                               (rev 0)
+++ developers/werner/wlan/connman/rtnl.c       2009-01-14 00:57:38 UTC (rev 
4886)
@@ -0,0 +1,802 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+#define connman_debug(FMT, ARGS...)    fprintf(stderr, FMT "\n", ARGS)
+
+struct watch_data {
+       unsigned int id;
+       int index;
+       connman_rtnl_link_cb_t newlink;
+       void *user_data;
+};
+
+static GSList *watch_list = NULL;
+static unsigned int watch_id = 0;
+
+/**
+ * connman_rtnl_add_newlink_watch:
+ * @index: network device index
+ * @callback: callback function
+ * @user_data: callback data;
+ *
+ * Add a new RTNL watch for newlink events
+ *
+ * Returns: %0 on failure and a unique id on success
+ */
+unsigned int connman_rtnl_add_newlink_watch(int index,
+                       connman_rtnl_link_cb_t callback, void *user_data)
+{
+       struct watch_data *watch;
+
+       watch = g_try_new0(struct watch_data, 1);
+       if (watch == NULL)
+               return 0;
+
+       watch->id = ++watch_id;
+       watch->index = index;
+
+       watch->newlink = callback;
+       watch->user_data = user_data;
+
+       watch_list = g_slist_prepend(watch_list, watch);
+
+       DBG("id %d", watch->id);
+
+       return watch->id;
+}
+
+/**
+ * connman_rtnl_remove_watch:
+ * @id: watch identifier
+ *
+ * Remove the RTNL watch for the identifier
+ */
+void connman_rtnl_remove_watch(unsigned int id)
+{
+       GSList *list;
+
+       DBG("id %d", id);
+
+       if (id == 0)
+               return;
+
+       for (list = watch_list; list; list = list->next) {
+               struct watch_data *watch = list->data;
+
+               if (watch->id  == id) {
+                       watch_list = g_slist_remove(watch_list, watch);
+                       g_free(watch);
+                       break;
+               }
+       }
+}
+
+static GSList *rtnl_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+       const struct connman_rtnl *rtnl1 = a;
+       const struct connman_rtnl *rtnl2 = b;
+
+       return rtnl2->priority - rtnl1->priority;
+}
+
+/**
+ * connman_rtnl_register:
+ * @rtnl: RTNL module
+ *
+ * Register a new RTNL module
+ *
+ * Returns: %0 on success
+ */
+int connman_rtnl_register(struct connman_rtnl *rtnl)
+{
+       DBG("rtnl %p name %s", rtnl, rtnl->name);
+
+       rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
+                                                       compare_priority);
+
+       return 0;
+}
+
+/**
+ * connman_rtnl_unregister:
+ * @rtnl: RTNL module
+ *
+ * Remove a previously registered RTNL module
+ */
+void connman_rtnl_unregister(struct connman_rtnl *rtnl)
+{
+       DBG("rtnl %p name %s", rtnl, rtnl->name);
+
+       rtnl_list = g_slist_remove(rtnl_list, rtnl);
+}
+
+static void process_newlink(unsigned short type, int index,
+                                       unsigned flags, unsigned change)
+{
+       GSList *list;
+
+       for (list = rtnl_list; list; list = list->next) {
+               struct connman_rtnl *rtnl = list->data;
+
+               if (rtnl->newlink)
+                       rtnl->newlink(type, index, flags, change);
+       }
+
+       for (list = watch_list; list; list = list->next) {
+               struct watch_data *watch = list->data;
+
+               if (watch->index != index)
+                       continue;
+
+               if (watch->newlink)
+                       watch->newlink(flags, change, watch->user_data);
+       }
+}
+
+static void process_dellink(unsigned short type, int index,
+                                       unsigned flags, unsigned change)
+{
+       GSList *list;
+
+       for (list = rtnl_list; list; list = list->next) {
+               struct connman_rtnl *rtnl = list->data;
+
+               if (rtnl->dellink)
+                       rtnl->dellink(type, index, flags, change);
+       }
+}
+
+static char *extract_gateway(struct rtmsg *msg, int bytes, int *index)
+{
+       char *gateway = NULL;
+       struct in_addr addr;
+       struct rtattr *attr;
+
+       for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+                                       attr = RTA_NEXT(attr, bytes)) {
+               switch (attr->rta_type) {
+               case RTA_GATEWAY:
+                       addr = *((struct in_addr *) RTA_DATA(attr));
+                       g_free(gateway);
+                       gateway = g_strdup(inet_ntoa(addr));
+                       break;
+               case RTA_OIF:
+                       *index = *((int *) RTA_DATA(attr));
+                       break;
+               }
+       }
+
+       return gateway;
+}
+
+static void process_newgateway(struct rtmsg *msg, int bytes)
+{
+       int index = -1;
+       char *gateway;
+       GSList *list;
+
+       gateway = extract_gateway(msg, bytes, &index);
+       if (gateway == NULL || index < 0)
+               return;
+
+       for (list = rtnl_list; list; list = list->next) {
+               struct connman_rtnl *rtnl = list->data;
+
+               if (rtnl->newgateway)
+                       rtnl->newgateway(index, gateway);
+       }
+
+       g_free(gateway);
+}
+
+static void process_delgateway(struct rtmsg *msg, int bytes)
+{
+       int index = -1;
+       char *gateway;
+       GSList *list;
+
+       gateway = extract_gateway(msg, bytes, &index);
+       if (gateway == NULL || index < 0)
+               return;
+
+       for (list = rtnl_list; list; list = list->next) {
+               struct connman_rtnl *rtnl = list->data;
+
+               if (rtnl->delgateway)
+                       rtnl->delgateway(index, gateway);
+       }
+
+       g_free(gateway);
+}
+
+static inline void print_inet(struct rtattr *attr, const char *name, int 
family)
+{
+       if (family == AF_INET) {
+               struct in_addr addr;
+               addr = *((struct in_addr *) RTA_DATA(attr));
+               DBG("  attr %s (len %jd) %s\n",
+                               name, RTA_PAYLOAD(attr), inet_ntoa(addr));
+       } else
+               DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
+}
+
+static inline void print_char(struct rtattr *attr, const char *name)
+{
+       DBG("  attr %s (len %jd) %s\n", name, RTA_PAYLOAD(attr),
+                                               (char *) RTA_DATA(attr));
+}
+
+static inline void print_byte(struct rtattr *attr, const char *name)
+{
+       DBG("  attr %s (len %jd) 0x%02x\n", name, RTA_PAYLOAD(attr),
+                                       *((unsigned char *) RTA_DATA(attr)));
+}
+
+static inline void print_attr(struct rtattr *attr, const char *name)
+{
+       if (name)
+               DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
+       else
+               DBG("  attr %d (len %jd)\n",
+                                       attr->rta_type, RTA_PAYLOAD(attr));
+}
+
+static void rtnl_link(struct nlmsghdr *hdr)
+{
+#if 0
+       struct ifinfomsg *msg;
+       struct rtattr *attr;
+       int bytes;
+
+       msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+       bytes = IFLA_PAYLOAD(hdr);
+
+       DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
+
+       for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
+                                       attr = RTA_NEXT(attr, bytes)) {
+               switch (attr->rta_type) {
+               case IFLA_ADDRESS:
+                       print_attr(attr, "address");
+                       break;
+               case IFLA_BROADCAST:
+                       print_attr(attr, "broadcast");
+                       break;
+               case IFLA_IFNAME:
+                       print_char(attr, "ifname");
+                       break;
+               case IFLA_MTU:
+                       print_attr(attr, "mtu");
+                       break;
+               case IFLA_LINK:
+                       print_attr(attr, "link");
+                       break;
+               case IFLA_QDISC:
+                       print_attr(attr, "qdisc");
+                       break;
+               case IFLA_STATS:
+                       print_attr(attr, "stats");
+                       break;
+               case IFLA_COST:
+                       print_attr(attr, "cost");
+                       break;
+               case IFLA_PRIORITY:
+                       print_attr(attr, "priority");
+                       break;
+               case IFLA_MASTER:
+                       print_attr(attr, "master");
+                       break;
+               case IFLA_WIRELESS:
+                       print_attr(attr, "wireless");
+                       break;
+               case IFLA_PROTINFO:
+                       print_attr(attr, "protinfo");
+                       break;
+               case IFLA_TXQLEN:
+                       print_attr(attr, "txqlen");
+                       break;
+               case IFLA_MAP:
+                       print_attr(attr, "map");
+                       break;
+               case IFLA_WEIGHT:
+                       print_attr(attr, "weight");
+                       break;
+               case IFLA_OPERSTATE:
+                       print_byte(attr, "operstate");
+                       break;
+               case IFLA_LINKMODE:
+                       print_byte(attr, "linkmode");
+                       break;
+               default:
+                       print_attr(attr, NULL);
+                       break;
+               }
+       }
+#endif
+}
+
+static void rtnl_newlink(struct nlmsghdr *hdr)
+{
+       struct ifinfomsg *msg;
+
+       msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+
+       DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
+                                       msg->ifi_type, msg->ifi_index,
+                                       msg->ifi_flags, msg->ifi_change);
+
+       process_newlink(msg->ifi_type, msg->ifi_index,
+                                       msg->ifi_flags, msg->ifi_change);
+
+       rtnl_link(hdr);
+}
+
+static void rtnl_dellink(struct nlmsghdr *hdr)
+{
+       struct ifinfomsg *msg;
+
+       msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+
+       DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
+                                       msg->ifi_type, msg->ifi_index,
+                                       msg->ifi_flags, msg->ifi_change);
+
+       process_dellink(msg->ifi_type, msg->ifi_index,
+                                       msg->ifi_flags, msg->ifi_change);
+
+       rtnl_link(hdr);
+}
+
+static void rtnl_addr(struct nlmsghdr *hdr)
+{
+       struct ifaddrmsg *msg;
+       struct rtattr *attr;
+       int bytes;
+
+       msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
+       bytes = IFA_PAYLOAD(hdr);
+
+       DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
+
+       for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
+                                       attr = RTA_NEXT(attr, bytes)) {
+               switch (attr->rta_type) {
+               case IFA_ADDRESS:
+                       print_inet(attr, "address", msg->ifa_family);
+                       break;
+               case IFA_LOCAL:
+                       print_inet(attr, "local", msg->ifa_family);
+                       break;
+               case IFA_LABEL:
+                       print_char(attr, "label");
+                       break;
+               case IFA_BROADCAST:
+                       print_inet(attr, "broadcast", msg->ifa_family);
+                       break;
+               case IFA_ANYCAST:
+                       print_attr(attr, "anycast");
+                       break;
+               case IFA_CACHEINFO:
+                       print_attr(attr, "cacheinfo");
+                       break;
+               case IFA_MULTICAST:
+                       print_attr(attr, "multicast");
+                       break;
+               default:
+                       print_attr(attr, NULL);
+                       break;
+               }
+       }
+}
+
+static void rtnl_route(struct nlmsghdr *hdr)
+{
+#if 0
+       struct rtmsg *msg;
+       struct rtattr *attr;
+       int bytes;
+
+       msg = (struct rtmsg *) NLMSG_DATA(hdr);
+       bytes = RTM_PAYLOAD(hdr);
+
+       DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags);
+
+       for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+                                       attr = RTA_NEXT(attr, bytes)) {
+               switch (attr->rta_type) {
+               case RTA_DST:
+                       print_inet(attr, "dst", msg->rtm_family);
+                       break;
+               case RTA_SRC:
+                       print_inet(attr, "src", msg->rtm_family);
+                       break;
+               case RTA_IIF:
+                       print_char(attr, "iif");
+                       break;
+               case RTA_OIF:
+                       print_attr(attr, "oif");
+                       break;
+               case RTA_GATEWAY:
+                       print_inet(attr, "gateway", msg->rtm_family);
+                       break;
+               case RTA_PRIORITY:
+                       print_attr(attr, "priority");
+                       break;
+               case RTA_PREFSRC:
+                       print_inet(attr, "prefsrc", msg->rtm_family);
+                       break;
+               case RTA_METRICS:
+                       print_attr(attr, "metrics");
+                       break;
+               case RTA_TABLE:
+                       print_attr(attr, "table");
+                       break;
+               default:
+                       print_attr(attr, NULL);
+                       break;
+               }
+       }
+#endif
+}
+
+static void rtnl_newroute(struct nlmsghdr *hdr)
+{
+       struct rtmsg *msg;
+
+       msg = (struct rtmsg *) NLMSG_DATA(hdr);
+
+       if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
+                                       msg->rtm_scope == RT_SCOPE_UNIVERSE) {
+               DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
+                                       msg->rtm_table, msg->rtm_scope,
+                                       msg->rtm_type, msg->rtm_flags);
+               process_newgateway(msg, RTM_PAYLOAD(hdr));
+       }
+
+       rtnl_route(hdr);
+}
+
+static void rtnl_delroute(struct nlmsghdr *hdr)
+{
+       struct rtmsg *msg;
+
+       msg = (struct rtmsg *) NLMSG_DATA(hdr);
+
+       if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
+                                       msg->rtm_scope == RT_SCOPE_UNIVERSE) {
+               DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
+                                       msg->rtm_table, msg->rtm_scope,
+                                       msg->rtm_type, msg->rtm_flags);
+               process_delgateway(msg, RTM_PAYLOAD(hdr));
+       }
+
+       rtnl_route(hdr);
+}
+
+static const char *type2string(uint16_t type)
+{
+       switch (type) {
+       case NLMSG_NOOP:
+               return "NOOP";
+       case NLMSG_ERROR:
+               return "ERROR";
+       case NLMSG_DONE:
+               return "DONE";
+       case NLMSG_OVERRUN:
+               return "OVERRUN";
+       case RTM_GETLINK:
+               return "GETLINK";
+       case RTM_NEWLINK:
+               return "NEWLINK";
+       case RTM_DELLINK:
+               return "DELLINK";
+       case RTM_NEWADDR:
+               return "NEWADDR";
+       case RTM_DELADDR:
+               return "DELADDR";
+       case RTM_GETROUTE:
+               return "GETROUTE";
+       case RTM_NEWROUTE:
+               return "NEWROUTE";
+       case RTM_DELROUTE:
+               return "DELROUTE";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static GIOChannel *channel = NULL;
+
+struct rtnl_request {
+       struct nlmsghdr hdr;
+       struct rtgenmsg msg;
+};
+#define RTNL_REQUEST_SIZE  (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
+
+static GSList *request_list = NULL;
+static guint32 request_seq = 0;
+
+static struct rtnl_request *find_request(guint32 seq)
+{
+       GSList *list;
+
+       for (list = request_list; list; list = list->next) {
+               struct rtnl_request *req = list->data;
+
+               if (req->hdr.nlmsg_seq == seq)
+                       return req;
+       }
+
+       return NULL;
+}
+
+static int send_request(struct rtnl_request *req)
+{
+       struct sockaddr_nl addr;
+       int sk;
+
+       DBG("%s len %d type %d flags 0x%04x seq %d",
+                               type2string(req->hdr.nlmsg_type),
+                               req->hdr.nlmsg_len, req->hdr.nlmsg_type,
+                               req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+
+       sk = g_io_channel_unix_get_fd(channel);
+
+       memset(&addr, 0, sizeof(addr));
+       addr.nl_family = AF_NETLINK;
+
+       return sendto(sk, req, req->hdr.nlmsg_len, 0,
+                               (struct sockaddr *) &addr, sizeof(addr));
+}
+
+static int queue_request(struct rtnl_request *req)
+{
+       request_list = g_slist_append(request_list, req);
+
+       if (g_slist_length(request_list) > 1)
+               return 0;
+
+       return send_request(req);
+}
+
+static int process_response(guint32 seq)
+{
+       struct rtnl_request *req;
+
+       DBG("seq %d", seq);
+
+       req = find_request(seq);
+       if (req != NULL) {
+               request_list = g_slist_remove(request_list, req);
+               g_free(req);
+       }
+
+       req = g_slist_nth_data(request_list, 0);
+       if (req == NULL)
+               return 0;
+
+       return send_request(req);
+}
+
+static void rtnl_message(void *buf, size_t len)
+{
+       DBG("buf %p len %zd", buf, len);
+
+       while (len > 0) {
+               struct nlmsghdr *hdr = buf;
+               struct nlmsgerr *err;
+
+               if (!NLMSG_OK(hdr, len))
+                       break;
+
+               DBG("%s len %d type %d flags 0x%04x seq %d",
+                                       type2string(hdr->nlmsg_type),
+                                       hdr->nlmsg_len, hdr->nlmsg_type,
+                                       hdr->nlmsg_flags, hdr->nlmsg_seq);
+
+               switch (hdr->nlmsg_type) {
+               case NLMSG_NOOP:
+               case NLMSG_OVERRUN:
+                       return;
+               case NLMSG_DONE:
+                       process_response(hdr->nlmsg_seq);
+                       return;
+               case NLMSG_ERROR:
+                       err = NLMSG_DATA(hdr);
+                       DBG("error %d (%s)", -err->error,
+                                               strerror(-err->error));
+                       return;
+               case RTM_NEWLINK:
+                       rtnl_newlink(hdr);
+                       break;
+               case RTM_DELLINK:
+                       rtnl_dellink(hdr);
+                       break;
+               case RTM_NEWADDR:
+               case RTM_DELADDR:
+                       rtnl_addr(hdr);
+                       break;
+               case RTM_NEWROUTE:
+                       rtnl_newroute(hdr);
+                       break;
+               case RTM_DELROUTE:
+                       rtnl_delroute(hdr);
+                       break;
+               }
+
+               len -= hdr->nlmsg_len;
+               buf += hdr->nlmsg_len;
+       }
+}
+
+static gboolean netlink_event(GIOChannel *chan,
+                               GIOCondition cond, gpointer data)
+{
+       unsigned char buf[4096];
+       gsize len;
+       GIOError err;
+
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+               return FALSE;
+
+       memset(buf, 0, sizeof(buf));
+
+       err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
+       if (err) {
+               if (err == G_IO_ERROR_AGAIN)
+                       return TRUE;
+               return FALSE;
+       }
+
+       rtnl_message(buf, len);
+
+       return TRUE;
+}
+
+int connman_rtnl_send_getlink(void)
+{
+       struct rtnl_request *req;
+
+       DBG("");
+
+       req = g_try_malloc0(RTNL_REQUEST_SIZE);
+       if (req == NULL)
+               return -ENOMEM;
+
+       req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+       req->hdr.nlmsg_type = RTM_GETLINK;
+       req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       req->hdr.nlmsg_pid = 0;
+       req->hdr.nlmsg_seq = request_seq++;
+       req->msg.rtgen_family = AF_INET;
+
+       return queue_request(req);
+}
+
+int connman_rtnl_send_getroute(void)
+{
+       struct rtnl_request *req;
+
+       DBG("");
+
+       req = g_try_malloc0(RTNL_REQUEST_SIZE);
+       if (req == NULL)
+               return -ENOMEM;
+
+       req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+       req->hdr.nlmsg_type = RTM_GETROUTE;
+       req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       req->hdr.nlmsg_pid = 0;
+       req->hdr.nlmsg_seq = request_seq++;
+       req->msg.rtgen_family = AF_INET;
+
+       return queue_request(req);
+}
+
+int __connman_rtnl_init(void)
+{
+       struct sockaddr_nl addr;
+       int sk;
+
+       DBG("");
+
+       sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (sk < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.nl_family = AF_NETLINK;
+       addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
+       //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+       //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
+
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               close(sk);
+               return -1;
+       }
+
+       channel = g_io_channel_unix_new(sk);
+       g_io_channel_set_close_on_unref(channel, TRUE);
+
+       g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+                                                       netlink_event, NULL);
+
+       return 0;
+}
+
+void __connman_rtnl_cleanup(void)
+{
+       GSList *list;
+
+       DBG("");
+
+       for (list = watch_list; list; list = list->next) {
+               struct watch_data *watch = list->data;
+
+               DBG("removing watch %d", watch->id);
+
+               g_free(watch);
+               list->data = NULL;
+       }
+
+       g_slist_free(watch_list);
+       watch_list = NULL;
+
+       for (list = request_list; list; list = list->next) {
+               struct rtnl_request *req = list->data;
+
+               DBG("%s len %d type %d flags 0x%04x seq %d",
+                               type2string(req->hdr.nlmsg_type),
+                               req->hdr.nlmsg_len, req->hdr.nlmsg_type,
+                               req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+
+               g_free(req);
+               list->data = NULL;
+       }
+
+       g_slist_free(request_list);
+       request_list = NULL;
+
+       g_io_channel_shutdown(channel, TRUE, NULL);
+       g_io_channel_unref(channel);
+
+       channel = NULL;
+}




--- End Message ---
_______________________________________________
commitlog mailing list
commitlog@lists.openmoko.org
http://lists.openmoko.org/mailman/listinfo/commitlog

Reply via email to