Thursday, October 7, 2010

configure: error: no termcap library found

Recently when I was trying to build gdbserver for embedded Linux running on MIPS target, I kept running in to this error.
configure: error: no termcap library found
I tried compiling and installing termcap to my cross-compiling tools but this error kept appearing. I tried copying the termpcap.a file to cross-compilers lib directory and setting environment variables so that the compiler can find it but it didnt work. Then I found a post on internet telling that although the error says termcap library, what the compiler is actually looking for is ncurses library and compiling ncurses for Mips and copying ncurses lib to my cross compiling tools did the trick for me but it really made me angry. Why cant the error say
configure: error: no ncurses library found
It wasted more than half of my workday :(. As a developer it made me learn that it is important to display correct and precise error messages.

Sunday, August 1, 2010

How to use Netlink Sockets

 After reading kernel source I finally managed to make netlink sockets work for me. Below is an example of Netlink socket basics i.e opening a netlink socket, reading and writing to it and closing it.



Kernel Module

#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>

#define NETLINK_USER 31

struct sock *nl_sk = NULL;

static void hello_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg="Hello from kernel";
    int res;

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
    
    msg_size=strlen(msg);
    
    nlh=(struct nlmsghdr*)skb->data;
    printk(KERN_INFO "Netlink received msg payload: %s\n",(char*)nlmsg_data(nlh));
    pid = nlh->nlmsg_pid; /*pid of sending process */

    skb_out = nlmsg_new(msg_size,0);

    if(!skb_out)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    } 
    nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);

    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
    strncpy(nlmsg_data(nlh),msg,msg_size);
    
    res=nlmsg_unicast(nl_sk,skb_out,pid);
    
    if(res<0)
        printk(KERN_INFO "Error while sending bak to user\n");
}

static int __init hello_init(void)
{
    printk("Entering: %s\n",__FUNCTION__);
    nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
    if(!nl_sk)
    {
        printk(KERN_ALERT "Error creating socket.\n");
        return -10;
    }
    return 0;
}

static void __exit hello_exit(void){
    printk(KERN_INFO "exiting hello module\n");
    netlink_kernel_release(nl_sk);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");


User Program

#include <sys/socket.h>
#include <linux/netlink.h>

#define NETLINK_USER 31

#define MAX_PAYLOAD 1024  /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;

void main() {
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
    if(sock_fd<0)
return -1;

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();  /* self pid */
    /* interested in group 1<<0 */
    bind(sock_fd, (struct sockaddr*)&src_addr,
        sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0;   /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */
    
    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh), "Hello");
    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("Sending message to kernel\n");
    sendmsg(sock_fd,&msg,0);
    printf("Waiting for message from kernel\n");

    /* Read message from kernel */
    recvmsg(sock_fd, &msg, 0);
    printf(" Received message payload: %s\n",
           NLMSG_DATA(nlh));
    close(sock_fd);
}

Friday, July 23, 2010

Interprocess communications between a Linux Kernel Module (LKM) and a user program

More ofter than not a Kernel Module will need to communicate with a user program. We really have following three options for communication between a user program and Kernel Module:
  1. A device file in /dev
  2. A file in /proc 
  3. A file in /sysfs
  4. Netlink sockets
/dev is usually used for device driver files i.e files that represent devices but these don't have to be "real" devices, they can be pseudo devices. A device file in /dev/ may be acceptable, even for modules that aren't really device drivers. So if your module is a driver or exposes a simple open/read/write/close interface then this is the your best option.

A file in /proc or /sysfs is not an actual file. Read or write operations on these files actually go to the associated kernel module. /proc was originally intended for processes related information but over the years it has become dumping ground for lot of other stuff, which kernel developers are not happy about. So its better to stay away from it unless you are providing some processes related information. If you want a file based mechanism of communication but dont want to create a device file then /sysfs is the better option.

Netlink sockets, in my opinion, is the best option if you are working on a Kernel Module which is not a device driver. It provides user programs with a familiar socket interface and does not requires the creation of any kind of file.

I will soon be posting a working example of how to use Netlink socket for communication between a user program and Linux Kernel Module

Friday, May 14, 2010

How to connect to Windows VPN from Ubuntu without the help of GUI

In Ubuntu, the easiest way to connect to VPN is using NetworkManager. But some times it is not possible. Like in my case NetworkManager wont detect my 3G Evdo modem, so I have to use gnome-ppp to connect to internet. And because of this NetworkManager thinks that there is no active connection and it wont let me connect to VPN. So I used pon and poff scripts to control my VPN connection. These scripts are provided by ppp package which is available in every Ubuntu installation by default. Given below is how I connected to a Windows PPTP VPN server.

First thing you need is to install pptp-linux package. So do
sudo apt-get install pptp-linux
Now create a file /etc/ppp/peers/vpnfile. You can change the file name vpnfile to any name you like but keep it simple as you will need it to connect to your VPN. Now add following lines to this file:

remotename myvpn
linkname myvpn
ipparam myvpn
pty "pptp  --nolaunchpppd "
name 
usepeerdns
require-mppe
refuse-eap
noauth
defaultroute

#defaults from the pptp-linux package
file /etc/ppp/options.pptp

The first three parameters provide name of the remote system, name for the link and a value to be passed to scripts in ip-up.d and ip-down.d directories, respectively. These values dont need to be same and can be different. The scripts in ip-up.d directories are called when a connection is established and the ones in ip-down.d are called when a connection is terminated. Next parameter i.e pty specifies that the given script should be used to communicate rather than any terminal device. Rest of the parameters control different attributes of the connection i.e what protocol to use or refuse or whether to use encryption or not and etc. The last parameter i.e defaultroute adds a default route to system routing table when this connection is established. This means that when this connection is active, by default all traffic is routed on this connection. If you dont need this behaviour, remove it and add scripts to ip-up.d and ip-down.d to add only your required routes.
More detailed explanation of these parameters can be found in manual entry for pppd i.e man pppd.

You will also need to add a line to file /etc/ppp/chap-secrets with username and password for this connection.

username connection-name password *


Connection name in this line must be same as remotename, which we have set to myvpn. 
Now to connect to vpn, issue command 
sudo pon vpnfile
and you are all set, connected to your vpn. To disconnect from the vpn, issue command
sudo poff vpnfile

Tuesday, March 30, 2010

A nice tool for conducting programming interviews

I have been interviewing people for developer jobs for some time now. At our company most interviews are conducted on phone because most of the candidates are located out of station. I have always found it difficult to judge a person's programming ability on phone because I think its easier to write code than to "speak" it. I recently came across a blog post on interviewing for programming jobs. It is an interesting post but I dont know how helpful it will be for me in future but there's a tool mentioned somewhere in there for conducting online coding interviews. This online tool at http://www.seemikecode.com/ seems interesting. I will try to use it for few interviews and then see how useful it really is.

Tuesday, January 19, 2010

Using ctags with Vim

I have been using vim for all my coding related tasks for a year now. I heard of ctags a while ago but I never tried using it. But recently I got tired of moving between files manually -looking for functions and other stuff- so I decided to give ctags a try. I never expected for it to be so simple. Just install ctags:
sudo apt-get install ctags
Generate tags file. To do this go to the main directory of your source tree. There just issue the command:
ctags -R
this will recursively traverse the source directory and generate a tags file containing information about all symbols -functions and variable- in the source files.
Using Vim with ctags is straight forward. Vim has builtin support for ctags so now you just need to issue vim command from the directory where you generated the tags file using ctags.
vim src/asdf/test.c
Now in the file move a cursor to some function or variable and press Ctrl-]. This will take you to the definition of that function or variable. To go back to where you came from press Ctrl-T, this will take you back to where your were before pressing Ctrl-]

If you have more than one tags files or you dont want to always use vim from one directory then add following line to your .vimrc file in your home directory:
set tags=tags;/

Monday, January 18, 2010

Connect To PTCL EVDO(Evo) from Ubuntu Linux

PTCL Evo connection comes with ZTE AC2726 USB modem. Its really easy to use it on Windows and Mac as there drivers are provided in the modem's memory but to use it on Linux is a bit tricky. Recently I succeeded in installing and configuring it on Ubuntu 9.10 and below are the steps which worked for me.
When you attach the modem to your linux machine it gets detected as a usb storage device and not as a usb modem. To use it as usb modem we need to convert it from usb-storage device to usbserial device in ubuntu. To do this I used -modeswitch utility which can be installed using following command:
sudo apt-get install usb-modeswitch
Unplug the modem and plug it back in. Use lsusb command to see list of usb devices attached to your system. You should see a line similar to
Bus xxx Device xxx: ID 19d2:fff1
Here 19d2 is vendor id for ZTE and fff1 is the device id for AC2726. If you dont see this line or see one with device id fff5 then you will need to restart your system. Now issue following command to load proper driver module in kernel:
sudo modprobe usbserial vendor=0x19d2 product=0xfff1
And thats it. Your modem is ready to be used. You will now need a dialer app to dial and establish the connection. I used gnome-ppp as it has the ability to dock. To install gnome-ppp issue following command:
sudo apt-get install gnome-ppp
You can now run gnome-ppp. You will need to run it as root. After it starts click on setup. On setup window click Detect so that it can detect your usb modem. Set type to be USB MODEM and speed to be 460800. Set phone line to Tone and volume to off. Now go to options tab and check the following:

  • Dock in notification area
  • Auto reconnect
  • Ignore terminal strings..
Now click close. You will be taken back to smaller window. Enter vwireless@ptcl.com as user name and ptcl as password. Enter #777 as phone number and click connect. and you will get connected to ptcl evo service.

UPDATE: if you are using Ubuntu 10.04 or later you can use a simpler method mentioned here