Find the answer to your Linux question:
Results 1 to 4 of 4
Hello all, First, some side info, skip the next paragraph to read about the kernel module problem. A week ago I bought a Vodafone (Huawei) R201 device, which shares a ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Mar 2012
    Posts
    3

    [tun.ko] Kernel Oops, compiling expertise needed!


    Hello all,

    First, some side info, skip the next paragraph to read about the kernel module problem.

    A week ago I bought a Vodafone (Huawei) R201 device, which shares a 3g connection over wifi. The device runs the 2.6.25 linux kernel [PREEMPT, armv6l]. I've gained root access by looking into the firmware, found out the iptables blocks telnetd on all interfaces. Since the firmware was on a cramfs file, I could only change the binary's name to iptacles, so I got (root) telnet access after flashing the bogus rom (by pausing the original flashing process after the signature check, flipping the iptables bit and let the flash run -> in case people wonder how to do it and end up here through google: use a hex editor and process explorer. Ask me, but not in this thread.). After this little victory, I made some configtweaks (getting rid of max 5 connected clients) and I found the correct cross compiler and Linux kernel sources and started to cross compile the tuntap kernel module. I succeeded in this to me new task and insmod'ed the module correctly. Now the trouble starts.

    When I try to run a piece of software that makes use of the tun driver (own test code and openvpn) , I get a kernel Oops, because of a null reference. Since this is all new to me and I'm out of own options now, maybe someone can point me in the right direction. Any help is appreciated. See relevant dmesg info below.

    Also some info on the module (and a shipped one), the magic is the same:

    gebruiker(AT(forum disallows...)generic ~ $ file *.ko
    msm_serial_hs.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped
    tun.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped

    ~ # /mnt/flash/bin/h
    SEGV
    ~ # dmesg
    Code:
    Unable to handle kernel NULL pointer dereference at virtual address 00000024
    pgd = c2ac8000
    [00000024] *pgd=039c5031, *pte=00000000, *ppte=00000000
    Internal error: Oops: 817 [#1] PREEMPT
    Modules linked in: ar6000 tun msm_sdcc
    CPU: 0 Not tainted (2.6.25 #1)
    PC is at tun_setup+0x1c/0x7c [tun]
    LR is at alloc_netdev_mq+0xac/0xd8
    pc : [<bf006a40>] lr : [<c01b2f7c>] psr: 20000013
    sp : c4f23e98 ip : c4f23eb0 fp : c4f23eac
    r10: bf0073c8 r9 : bf006a24 r8 : 00000001
    r7 : 00000050 r6 : 00000480 r5 : c2aea000 r4 : 00000000
    r3 : 00000000 r2 : 00000020 r1 : 00000000 r0 : c2aea000
    Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
    Control: 00c5387f Table: 02cc8008 DAC: 00000015
    Process hans (pid: 2017, stack limit = 0xc4f22260)
    Stack: (0xc4f23e98 to 0xc4f24000)
    3e80: c2aea000 c2aea000 
    3ea0: c4f23edc c4f23eb0 c01b2f7c bf006a30 c004e430 00000001 bf00829c befc79f4 
    3ec0: bf00829c c4f22000 c4f23ee4 c355da40 c4f23f2c c4f23ee0 bf006eb4 c01b2edc 
    3ee0: c4f22000 00000000 00000000 00000000 00000000 00001001 00000000 00000000 
    3f00: 00000000 c355da40 400454ca befc79f4 00000036 c0022bc8 c4f22000 00000000 
    3f20: c4f23f4c c4f23f30 c00a3fa4 bf006b70 c4e05e00 c355da40 c475fda8 befc79f4 
    3f40: c4f23f7c c4f23f50 c00a426c c00a3f34 c355da40 00000004 c4f23f94 c355da40 
    3f60: fffffff7 400454ca c0022bc8 c4f22000 c4f23fa4 c4f23f80 c00a42dc c00a3fcc 
    3f80: 00000005 00000000 c4f23fa4 0000001c 00000005 00049efc 00000000 c4f23fa8 
    3fa0: c0022a20 c00a42a8 0000001c 00000005 00000004 400454ca befc79f4 befc79dc 
    3fc0: 0000001c 00000005 00049efc 00000036 00049004 00000007 000080b4 befc7a24 
    3fe0: 00000000 befc79c0 0001709c 0002a560 60000010 00000004 00000000 00000000 
    Backtrace: 
    [<bf006a24>] (tun_setup+0x0/0x7c [tun]) from [<c01b2f7c>] (alloc_netdev_mq+0xac/0xd8)
    r5:c2aea000 r4:c2aea000
    [<c01b2ed0>] (alloc_netdev_mq+0x0/0xd8) from [<bf006eb4>] (tun_chr_ioctl+0x350/0x65c [tun])
    [<bf006b64>] (tun_chr_ioctl+0x0/0x65c [tun]) from [<c00a3fa4>] (vfs_ioctl+0x7c/0x98)
    [<c00a3f28>] (vfs_ioctl+0x0/0x98) from [<c00a426c>] (do_vfs_ioctl+0x2ac/0x2dc)
    r6:befc79f4 r5:c475fda8 r4:c355da40
    [<c00a3fc0>] (do_vfs_ioctl+0x0/0x2dc) from [<c00a42dc>] (sys_ioctl+0x40/0x64)
    r9:c4f22000 r8:c0022bc8 r6:400454ca r5:fffffff7 r4:c355da40
    [<c00a429c>] (sys_ioctl+0x0/0x64) from [<c0022a20>] (ret_fast_syscall+0x0/0x2c)
    r6:00049efc r5:00000005 r4:0000001c
    Code: e590419c e3a03000 e2842020 e1a05000 (e5842024) 
    ---[ end trace fff8bfea0c633eef ]---

    ps. Useful info for r201 (rooted) owners : /mnt/flash is non-volatile, put a script called customer.rcS in /mnt/flash/ and it will run every boot. What I do there is insmod the sd drivers and mount a new (writable) filesystem with up to date binaries and a patched cms (the huawei primary binary). And of course the tun.ko whenever I fix this problem!

    Got some help from a good friend and found out with some printk's that the following function fails

    drivers/net/tun.c :

    Code:
    static void tun_setup(struct net_device *dev)
    {
    
    struct tun_struct *tun = netdev_priv(dev); // dev->priv
    
    skb_queue_head_init(&tun->readq);
    init_waitqueue_head(&tun->read_wait);
    
    tun->owner = -1;
    tun->group = -1;
    
    dev->open = tun_net_open;
    dev->hard_start_xmit = tun_net_xmit;
    dev->stop = tun_net_close;
    dev->ethtool_ops = &tun_ethtool_ops;
    dev->destructor = free_netdev;
    }
    tun = 0 after the netdev_priv(dev) call. (which actually is just a dev->priv call in netdevice.h.

    Then we tried to find the place where priv get's initialized, which is in include/linux/netdevice.h:

    Code:
    extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
    void (*setup)(struct net_device *),
    unsigned int queue_count);
    #define alloc_netdev(sizeof_priv, name, setup) \
    alloc_netdev_mq(sizeof_priv, name, setup, 1)
    which is called with : alloc_netdev(80, "/dev/tun", tun_setup);

    alloc_netdev_mq is in core/net/dev.c:

    Code:
    struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
    void (*setup)(struct net_device *), unsigned int queue_count)
    {
    void *p;
    struct net_device *dev;
    int alloc_size;
    
    BUG_ON(strlen(name) >= sizeof(dev->name));
    
    /* ensure 32-byte alignment of both the device and private area */
    alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST +
    (sizeof(struct net_device_subqueue) * (queue_count - 1))) &
    ~NETDEV_ALIGN_CONST;
    alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
    
    p = kzalloc(alloc_size, GFP_KERNEL);
    if (!p) {
    printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
    return NULL;
    }
    
    dev = (struct net_device *)
    (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
    dev->padded = (char *)dev - (char *)p;
    dev->nd_net = &init_net;
    
    if (sizeof_priv) {
    dev->priv = ((char *)dev +
    ((sizeof(struct net_device) +
    (sizeof(struct net_device_subqueue) *
    (queue_count - 1)) + NETDEV_ALIGN_CONST)
    & ~NETDEV_ALIGN_CONST));
    }
    
    dev->egress_subqueue_count = queue_count;
    
    dev->get_stats = internal_stats;
    netpoll_netdev_init(dev);
    setup(dev);
    strcpy(dev->name, name);
    return dev;
    }
    And that's where I'm stuck, it looks like it should work I'm about to copy this code with constants into the tun class..

    For referencing:

    Code:
    struct tun_struct {
    struct list_head list;
    unsigned long flags;
    int	 attached;
    uid_t	 owner;
    gid_t	 group;
    
    wait_queue_head_t	read_wait;
    struct sk_buff_head	readq;
    
    struct net_device	*dev;
    
    struct fasync_struct *fasync;
    
    unsigned long if_flags;
    u8 dev_addr[ETH_ALEN];
    u32 chr_filter[2];
    u32 net_filter[2];
    
    #ifdef TUN_DEBUG
    int debug;
    #endif
    };
    When I init dev->priv myself I get an exception later on, with the notice that I try to init a already initialized value. I can't seem to see where things go wrong. Anyone?

    ps. I post this message at linuxquestions.org first, but that didnt seem to be the right place.

    pps. I can't recompile the whole kernel, since it's flashed into the device and not (easy) upgradable.
    Last edited by snempaa; 03-19-2012 at 07:18 PM. Reason: formatting

  2. #2
    Just Joined!
    Join Date
    Mar 2012
    Posts
    3
    I found the correct sources here and got the kernel config from the rom. Then I crosscompiled the normal way and got this working module :

    wouter.ru/tun.ko

    Have fun with it too

  3. #3
    Just Joined!
    Join Date
    Mar 2012
    Posts
    3
    Hello my friends,

    I started working with the r201 again and I need your help again! I am trying to get rid of the maximum of 5 connected clients in this device but that looked easier than it is.

    Since the device runs hostapd i though just to change the configfile; doesn't work, gets detected by firmware and deauths the 6th client. Same when using wmiconfig to set maxsta to >5.

    I found out that the max of 5 gets saved in NVRAM, along with ssid settings and other wifi settings. Since the settings is sent in the webinterface (ssid, maxAssoc) in JavaScript I used BURP as a proxy to change the values but again this (of course) gets checked serverside and fails.

    On the server I found two libs, libnv.so and libnvram_api.so, which have some function calls to recv of set nvram values. I have no experience in working with shared libs and dynamic linking, but i have made the following code to talk to the lib:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <dlfcn.h>
    
    int main(int argc, char **argv) {
        void *handle;
        int (*func)();
        char *error;
        handle = dlopen ("libnv.so", RTLD_LAZY);
        if (!handle) {
            fprintf (stderr, "%s\n", dlerror());
            exit(1);
        }
        dlerror();    /* Clear any existing error */
        func = dlsym(handle, "xdr_nv_recv_nv_wifi_sta_para");
        if ((error = dlerror()) != NULL)  {
            fprintf (stderr, "%s\n", error);
            exit(1);
    	}
        printf ("%d\n", (*func)());
        dlclose(handle);
        return 0;
    }
    You can guess, it fails, since it depends on other source the know some enums/variables. When I strace, I see that the lib gets opened and right after, before the actual function call (function found by nm -D lbnv.so), the error gets written to stdout. What am I not seeing/knowing about dynamic linking to make this work?

    Anybody?

    Thanks in advance!

    Cross compile command:
    Code:
    arm-none-linux-gnueabi-gcc ~/nv/testapp.c -o ~/nv/sharedlibtest -ldl
    Code:
    /mnt/sd # ./sharedlibtest
    /opt/qcom/lib/libnv.so: undefined symbol: xdr_op_err_msg
    Some info for nm:

    Code:
    000153d4 T xdr_nv_send_nv_wifi_st
    00014bf4 T xdr_nv_send_nv_wifi_sta_para
    ...
    000157b0 T xdr_nv_recv_nv_wifi_st
    00014c98 T xdr_nv_recv_nv_wifi_sta_para
    ...
             U xdr_op_err_msg
    ps. Maybe also usefull, I have no sources, headerfiles or whatever on all nvram libs / binaries (a test binary to read the values! and a binary for getting and setting mac/imei, although imei is in a strange format).

  4. $spacer_open
    $spacer_close
  5. #4
    Just Joined!
    Join Date
    Mar 2012
    Posts
    1
    just curiosity: did you have any progress on this?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •