Style Cleanup Required
This article does not follow the style standards in the Wiki Guide. More info...

This howto will help you to set up a e-tech V2 ADSL USB modem.

Step 1 - drivers for the USB modem

Most USB modems contain a microprocessor (a 'simple' computer), which is programmable and therefore can do many different things, so it is sold a lot and can be cheap. The cxacru driver included in Ubuntu (since Ubuntu 6.x) will try to 'upload' a small program to the modem, allowing the microprocessor to do the 'modem-work'. This small program (called firmware) is often licensed.

Item 1.1: obtain firmware for the modem

The drivers in Ubuntu do not contain this firmware (otherwise it would be illegal), but you probably got a CD along with the modem. One of the files of this CD contains the firmware. If you have the modem working for Windows, the firmware is in the Windows partition. So you already have a legal copy of the firmware, the only problem is finding the firmware. The sourceforge site gives you some intsructions. I have found a programm called cxacru-fw.c (I lost the URL name, the code is in Annex 1 at the end of this article). After compiling cxacru-fw.c (the URL gives you clear instructions), cxacru-fw can extract the firmware from a file called CnxEtU.sys on the modem CD, or the Windows partition. Make sure that you name the firmware file cxacru-fw.bin

Check also UsbAdslModem/AccessRunner on this issue.

Item 2.1: install the firmware and check whether it works

Place the file cxacru-fw.bin in:


Once the cxacru-fw.bin file is in the adquate directory, and the modem is connected, the system log will report that a connection has been set up. You can check this by opening a terminal and issue the following command:

dmesg | egrep -e 'cxacru|ADSL'

If everything went well you see:

localhost kernel [4294759.585000] cxacru 1-1:1.0: ADSL line: training
localhost kernel [4294764.599000] cxacru 1-1:1.0: ADSL line: channel analysis
localhost kernel [4294769.585000] cxacru 1-1:1.0: ADSL line: up (384 Kib/s down | 128 Kib/s up)

Initially I got the following errors:

localhost kernel [4300944.253000] cxacru 1-1:1.0: firmware unavailable (hotplug configuration problem?)
localhost kernel [4295543.593000] cxacru 1-1:1.0: poll status: error -5

The 1. problem (firmware unavailable) was that I had put the firmware in a wrong location. The 2. problem (poll status...) may require newer firmware - but the modem works nevertheless

In the current versions of Ubuntu the http://sourceforge.net/projects/accessrunner programs that actually upload the firmware to the modem are already included in the kernel.

Note: the location of the firmware is Ubuntu specific - other Linux distributions use other locations. Note 2: the file cxacru-fw.bin is licensed, do not redistribute it. Note 3: the provider may assume that you logged in at the moment the firmware on the modem has connected to the network. This happens during linux startup. If you have to pay for the time being online, you have to dive in the details of cxacru to be able to logon and logoff at will.

Step 2 - connect the modem to the ethernet 'talk' of Ubuntu

The modem is now connected to the provider computer. It uses a communication mode called ATM (Asynchronous Transfer Mode). On the other hand, the operating system (Ubuntu) by default speaks a language called ethernet. To bridge the 'ethernet-talk' of Ubuntu to ATM, additional packages have to be installed. This is called a bridge.

Item 2.1: Setting up the bridge

You will need:

  1. the br2684ctl package (.deb file) for your installed ubuntu version (often i386), e.g. from


  1. the libatm1 package (.deb file) for your installed ubuntu version (often i386), e.g. from


These can be installed by putting the .deb files on the desktop. Then double-click on the file. Synaptic will start and try to install the packages.

To start the 'bridge' between the ATM modem and Ubuntu type in a terminal:

sudo modprobe br2684

There are various 'languages' that can be used to communicate through ATM, with names like 'AAL type 5'. Specific AAL5 dialects (encapsulation protocols) exist, such as LLC and VC-MUX.

Remark further that more than one providers work through the same telecom-network, their datastreams are distuinguished by VPI.VCI codes.

My provider:

  1. uses LLC encapsualtion
  2. VPI.VCI code is 0.0.32

There is a nice list http://faq.eagle-usb.org/wakka.php?wiki=ListConfigADSL here for some countries. If you don't find there the VP/VC numbers for your country/provider then you should ask your provider.

The syntax of the bridging command is the following :

br2684ctl [-c n -e 0|1 -b 0|1 -s buf_size -a [itf].vpi.vci ]+

-a [itf].vpi.vci : ATM PVC number, VPI and VCI. Mandatory
-c n : BR2684 interface number such as nas0,
nas1,... Mandatory
-e 0|1 : Encapsulation method. 0=LLC, 1=VC mux.
default is 0, LLC
-b 0|1 : Running background. 1=background,
0=foreground. Default is 0
-s buf_size : send buffer size. Default is 8192.

In my case the interface is created by:

sudo br2684ctl -b -e 0 -c 0 -a 0.0.32

Now an interface called nas0 is created. This interface can be pictured as a software version of an ethernetcard in the PC.

Item 2.2: Login

Once the bridge is working, you have to login. Again this is provider specific. I have detected three alternative procedures:

  1. DHCP
  2. PPPoA
  3. PPPoE

For DHCP you typically do not have to give a username and password (I guess the provider recognises you through your telephone number). For both PPP procedures you will have to provide your username and pasword.


If you use DHCP to login (this is used when you don't have to provide a password for connecting), use the dhcpclient command (in other linux distribution sthis is dhcpcd):

sudo dhclient nas0

It worked for me, although I always get a few warning-messages at the end)

sit0: unknown hardware address type 776
sit0: unknown hardware address type 776
Listening on LPF/nas0/00:d0:41:10:21:dc
Sending on   LPF/nas0/00:d0:41:10:21:dc
Sending on   Socket/fallback
DHCPREQUEST on nas0 to port 67
bound to -- renewal in 3125 seconds.


Follow the instructions on ADSLPPPoE

Note: Since I use DHCP, I could not test this.


Since I use DHCP, I could not test this. For your convenience, I copied this from another website. I gues it will not work for Ubuntu without modifications.

Check the other USBADSL modems referred to in this WIKI!!

if PPPoA , download from http://accessrunner.sourceforge.net/debian-scripts/ the peers-pppoa and put it in /etc/ppp/peers, edit that file especially the user and the VPC/VCI peers. Add also your login password in the /etc/ppp/pap-secrets /etc/ppp/chap-secrets in the form login * password *

insmod /lib/modules/2.6.10-5-386/kernel/net/atm/pppoatm.ko
pppd call peers-pppoa

if PPPoE Install apt-get install libatm1

also you ll need to download 2 package from the ubuntu

br2684ctl_20040226-1_i386.deb atm-tools_2.4.1-16_i386.deb ( I m not sure if that one needed)

then install them with the command dpkg -i xxxxxfilexxxxx.deb

download from http://accessrunner.sourceforge.net/debian-scripts/ the peers-pppoe and put it in /etc/ppp/peers, edit that file especially the user. Add also your login password in the /etc/ppp/pap-secrets /etc/ppp/chap-secrets in the form login * password *

after that modify the /etc/network/interfaces and add : auto nas0 iface nas0 inet static address netmask broadcast 0x0x gateway pre-up br2684ctl -b -c 0 -a 0.0.100 post-down kill $(cat /var/run/$IFACE.pid) (the 0.0.100 is the form itf.vpi.vci you should set vpi/vci accordingly to what you have see your ISP for this infos.)

Restart the network to get the nas0 match the atm interface insmod /lib/modules/2.6.10-5-386/kernel/net/atm/br2684.ko /etc/init.d/networking restart

And finally connect pppd call peers-pppoe

I m sorry it s a bit hard and maybe not well organized but it should give you a better idea of what you need to do.

Automated bridge and login

With the procedures above the login is manually. If it works the procedure can be automated. Presently I have a small executable text-file on my desktop:

sudo modprobe br2684
sudo br2684ctl -b -c 0 -a 0.0.32
sudo dhclient nas0
sleep 5d

If the connection is successfull the terminal window can be closed by typing Ctrl-C.

Note: the provider may assume that you logged in at the moment the firmware on the modem has connected to the network. This happens during linux startup. If you have to pay for the time being online, you have to dive in the details of cxacru to be able to logon and logoff at will.

Actually, the commands modprobe ..., br2684ctl .. and dhclient or ppp... can be executed during linux startup. I haven't tried it (yet), but you can check the site:


(in Dutch)

==== Annex 1 - code of cxacru-fw.c====

 *  cxacru-fw - utility to extract firmware for the USB ADSL modems based on
 *              Conexant AccessRunner chipset, from the Conexant driver for
 *              Windows(R)
 *  Copyright (C) 2005  Roman Kagan (rkagan % mail ! ru)
 *  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
 *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
#include <argp.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <endian.h>
#include <byteswap.h>

static inline uint16_t le16_to_cpup(uint16_t *x) {return bswap_16(*x);}
static inline uint32_t le32_to_cpup(uint32_t *x) {return bswap_32(*x);}
static inline uint16_t le16_to_cpup(uint16_t *x) {return *x;}
static inline uint32_t le32_to_cpup(uint32_t *x) {return *x;}

uint8_t *findfw(uint8_t *buf, int len, int *fwlen)
        const static uint8_t fwstart[] = {      /*              ARM LE asm                              */
                0x1c, 0x24, 0x9f, 0xe5,         /*      e59f241c        ldr     r2, [pc, #0x41c]        */
                0x00, 0x10, 0xa0, 0xe3,         /*      e3a01000        mov     r1, #0x0                */
                0x00, 0x10, 0x82, 0xe5,         /*      e5821000        str     r1, [r2]                */
                0x22, 0x00, 0x00, 0xeb,         /*      eb000022        bl      0x9c                    */

        const static uint8_t bpstart[] = {
                0x78, 0x20, 0x9f, 0xe5,         /*      e59f2078        ldr     r2, [pc, #0x78] */
                0x01, 0x10, 0xa0, 0xe3,         /*      e3a01001        mov     r1, #0x1        */
                0x00, 0x10, 0x82, 0xe5,         /*      e5821000        str     r1, [r2]                */
                0x70, 0x20, 0x9f, 0xe5,         /*      e59f2070        ldr     r2, [pc, #0x70] */

        uint8_t *fw, *bp, *nt_header, *sect_header;
        uint32_t tmp;
        uint16_t nsect;
        uint32_t dataoff, datalen;

        *fwlen = 0;

        /* IMAGE_DOS_HEADER size and .Signature */
        if (len < 0x40 || memcmp(buf, "MZ", 2)) {
                error(0, 0, "file is not a DOS executable");
                return NULL;

        /* IMAGE_NT_HEADERS size and .Signature */
        tmp = le32_to_cpup((uint32_t *) (buf + 0x3c));
        nt_header = buf + tmp;
        if (len < tmp + 0x18 || memcmp(nt_header, "PE\0\0", 4)) {
                error(0, 0, "file is not a portable executable (PE)");
                return NULL;

        /* IMAGE_NT_HEADERS.FileHeader.NumberOfSections */
        nsect = le16_to_cpup((uint16_t *) (nt_header + 0x04 + 0x2));

        /* IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader */
        tmp = le16_to_cpup((uint16_t *) (nt_header + 0x04 + 0x10));
        sect_header = nt_header + 0x18 + tmp;

        for (; nsect; nsect--, sect_header += 0x28) {
                if (sect_header + 0x28 > buf + len) {
                        error(0, 0, "file header corrupted");
                        return NULL;

                if (!memcmp(sect_header, ".data", 5))

        if (!nsect) {
                error(0, 0, "`.data' section not found");
                return NULL;

        /* IMAGE_SECTION_HEADER.SizeOfRawData */
        datalen = le32_to_cpup((uint32_t *) (sect_header + 0x10));
        /* IMAGE_SECTION_HEADER.PointerToRawData */
        dataoff = le32_to_cpup((uint32_t *) (sect_header + 0x14));
        if (dataoff + datalen > len) {
                error(0, 0, "`.data' section extends beyond end of file");
                return NULL;

        /* find the starting sequence of the firmware image */
        fw = (uint8_t *) memmem(buf + dataoff, datalen, fwstart, sizeof(fwstart));
        if (!fw) {
                error(0, 0, "firmware start sequence not found");
                return NULL;
        *fwlen = datalen - (fw - (buf + dataoff));

        /* find the starting sequence of the boot ROM patch, if present */
        bp = (uint8_t *) memmem(fw, *fwlen, bpstart, sizeof(bpstart));
        if (bp)
                *fwlen = bp - fw;
        return fw;

const char * argp_program_version = "002";
const char * argp_program_bug_address =
                "<accessrunner-general at lists dot sourceforge dot net>";
const static char args_doc[] = "INFILE OUTFILE";
const static char doc[] =
                "Firmware extractor for Conexant AccessRunner ADSL USB modems\n"
                "INFILE - Windows driver file containing firmware (usually CnxEtU.sys)\n"
                "OUTFILE - firmware image (usually cxacru-fw.bin)";

struct args {
        char *infile;
        char *outfile;

static error_t parse_opts(int key, char *arg, struct argp_state *state)
        struct args *args = state->input;
        switch (key) {
        case ARGP_KEY_ARG:
                switch (state->arg_num) {
                case 0:
                        args->infile = arg;
                case 1:
                        args->outfile = arg;
                        argp_usage (state);

        case ARGP_KEY_END:
                if (state->arg_num < 2)
                        argp_usage (state);

                return ARGP_ERR_UNKNOWN;
        return 0;

static struct argp argp = {0, parse_opts, args_doc, doc};

int main(int argc, char **argv)
        int ret, fd;
        struct args args;
        struct stat instat;
        uint8_t *buf, *fw;
        int len, fwlen;

        argp_parse(&argp, argc, argv, 0, NULL, &args);

        fd = open(args.infile, O_RDONLY);
        if (fd < 0)
                error(1, errno, "failed to open `%s' for reading", args.infile);

        ret = fstat(fd, &instat);
        if (ret)
                error(1, errno, "failed to obtain the size of `%s'", args.infile);
        len = instat.st_size;

        buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
        if (!buf)
                error(1, errno, "failed to mmap `%s'", args.infile);

        fw = findfw(buf, len, &fwlen);
        if (!fw)
                error(1, 0, "can't find AccessRunner firmware in `%s'", args.infile);

        fd = open(args.outfile, O_WRONLY | O_CREAT | O_EXCL,
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        if (fd < 0)
                error(1, errno, "failed to open `%s' for writing", args.outfile);

        if (write(fd, fw, fwlen) != fwlen)
                error(1, errno, "failed to write firmware to `%s'", args.outfile);

        munmap(buf, len);
        printf("found firmware in `%s' at offset %#x\n", args.infile, fw - buf);


UsbAdslModem/e-techV2 (last edited 2017-09-22 17:50:20 by ckimes)