Auto-generated Linux Kernel Documentation

January 25, 2012

This may be old news but I just discovered some handy auto-generated (with doxygen) kernel documentation:

http://kerneldox.com/

Enabling dev_dbg in the kernel

November 6, 2011

To enable dev_dbg messages in a specific kernel file:

 #define DEBUG

before including <linux/device.h>

Reference: https://lkml.org/lkml/2007/6/29/323

Retrieve information about the calling process from within a kernel module

October 18, 2011

From within a kernel module you can get information about the currently executing process using the current variable. current is of type struct task_struct. When a system call is executing (such as open, read, write, ioctl) the current process will be the caller.

For example to display the process id from within a read function:

	printk("%s: The calling process is \"%s\" (pid %i)\n",
				__FUNCTION__, current->comm, current->pid);

References:

J. Corbet, A. Rubini, & G. Kroah-Hartman. (2005). Linux Device Drivers, 3rd Ed. (p. 20)

 

Sending raw Ethernet packets from a specific interface in C on Linux

September 14, 2011

Lately I’ve been writing some code to send packets to a specific MAC address from a specific interface. I’m sure this will come in handy again so here is how it goes:

Includes:
(might not need all of these)

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ether.h>
#include <linux/if_packet.h>

Open the raw socket:

int sockfd;
...
/* Open RAW socket to send on */
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
    perror("socket");
}

Get the index of the interface to send on:

struct ifreq if_idx;
...
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, "eth0", IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFINDEX, &if_idx) < 0)
    perror("SIOCGIFINDEX");

Get the MAC address of the interface to send on:

struct ifreq if_mac;
...
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, "eth0", IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFHWADDR, &if_mac) < 0)
    perror("SIOCGIFHWADDR");

Get the IP address of the interface to send on:

struct ifreq if_ip;
...
memset(&if_ip, 0, sizeof(struct ifreq));
strncpy(if_ip.ifr_name, "eth0", IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFADDR, &if_ip) < 0)
    perror("SIOCGIFADDR");

Construct the Ethernet header:

int tx_len = 0;
char sendbuf[1024];
struct ether_header *eh = (struct ether_header *) sendbuf;
...
memset(sendbuf, 0, 1024);
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = MY_DEST_MAC0;
eh->ether_dhost[1] = MY_DEST_MAC1;
eh->ether_dhost[2] = MY_DEST_MAC2;
eh->ether_dhost[3] = MY_DEST_MAC3;
eh->ether_dhost[4] = MY_DEST_MAC4;
eh->ether_dhost[5] = MY_DEST_MAC5;
eh->ether_type = htons(ETH_P_IP);
tx_len += sizeof(struct ether_header);

Construct the IP header:

struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
...
/* IP Header */
iph->ihl = 5;
iph->version = 4;
iph->tos = 16; // Low delay
iph->id = htons(54321);
iph->ttl = ttl; // hops
iph->protocol = 17; // UDP
/* Source IP address, can be spoofed */
iph->saddr = inet_addr(inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
// iph->saddr = inet_addr("192.168.0.112");
/* Destination IP address */
iph->daddr = inet_addr("192.168.0.111");
tx_len += sizeof(struct iphdr);

Construct the UDP header:

struct udphdr *udph = (struct udphdr *) (sendbuf + sizeof(struct iphdr) + sizeof(struct ether_header));
...
/* UDP Header */
udph->source = htons(3423);
udph->dest = htons(5342);
udph->check = 0; // skip
tx_len += sizeof(struct udphdr);

Fill in UDP payload:

/* Packet data */
sendbuf[tx_len++] = 0xde;
sendbuf[tx_len++] = 0xad;
sendbuf[tx_len++] = 0xbe;
sendbuf[tx_len++] = 0xef;

Fill in remaining header info:

unsigned short csum(unsigned short *buf, int nwords)
{
    unsigned long sum;
    for(sum=0; nwords>0; nwords--)
        sum += *buf++;
    sum = (sum >> 16) + (sum &0xffff);
    sum += (sum >> 16);
    return (unsigned short)(~sum);
}
...
/* Length of UDP payload and header */
udph->len = htons(tx_len - sizeof(struct ether_header) - sizeof(struct iphdr));
/* Length of IP payload and header */
iph->tot_len = htons(tx_len - sizeof(struct ether_header));
/* Calculate IP checksum on completed header */
iph->check = csum((unsigned short *)(sendbuf+sizeof(struct ether_header)), sizeof(struct iphdr)/2);

Send the raw Ethernet packet:

/* Destination address */
struct sockaddr_ll socket_address;
...
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = MY_DEST_MAC0;
socket_address.sll_addr[1] = MY_DEST_MAC1;
socket_address.sll_addr[2] = MY_DEST_MAC2;
socket_address.sll_addr[3] = MY_DEST_MAC3;
socket_address.sll_addr[4] = MY_DEST_MAC4;
socket_address.sll_addr[5] = MY_DEST_MAC5;
/* Send packet */
if (sendto(sock, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
    printf("Send failed\n");

References:
http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html
http://www.tenouk.com/Module43a.html
http://linux.die.net/man/3/sendto

Initialising all elements of an array to a constant in C

August 16, 2011

Works in GCC 4.4.3:
int myArr[] = {[0 ... (MAX_NO_ELEMENTS-1)] = 3};

Reference: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

How to make your Tumblr display in chronological order

August 11, 2011
  1. Add a tag to every post (just something like ‘x’)
  2. Use the address 987fsdf98uj23r.tumblr.com/tagged/x/chrono

Reference: http://staff.tumblr.com/post/34933619/new-feature-tag-filtering

Copying files between Linux VirtualBox guest and host

August 8, 2011

In VirtualBox go to “Network Adapters…” from the Devices menu and set Attached to: Host-only Adapter.

Set up IP addresses in the same sub domain. On the host:
ifconfig vboxnet0 192.168.56.1 netmask 255.255.255.0
On the guest:
ifconfig eth0 192.168.56.2 netmask 255.255.255.0
route add default gw 192.168.56.1

Use secure copy to transfer files from host to guest. From the host:
scp filetocpy guestuser@192.168.56.2:/guestdir/

Lessons learned submitting my first Linux kernel patch

July 31, 2011
  • It takes a lot longer than one would expect
  • Follow all the instructions
  • Create patch with -upNr options:
    diff -upNr a/drivers/somefile.c b/drivers/somefile.c > mypatch.patch
  • Use the script to check for coding style errors:
    cd a
    scripts/checkpatch.pl ../mypatch.patch
  • When using Evolution to mail patches, turn off word wrapping by changing to Preformatted paragraph style:
  • More reading

Digitech Gigabit Ethernet ExpressCard on Ubuntu 10.04

June 8, 2011

Trick my colleague showed me to get the Digitech XC4146 PCMCIA-E-GLAN Gigabit Ethernet ExpressCard working on Ubuntu 10.04:

  • Restart WITHOUT the card inserted
  • Insert the card
  • Rescan the PCI bus: echo 1 | sudo tee /sys/bus/pci/rescan
  • ifconfig and set an IP
  • Vintage Game Console RF Frequencies

    June 4, 2011

    My LCD TV has a lot of trouble scanning for old game consoles. Here are mine as I tune them in:

    Console Channel switch Frequency (MHz)
    NES to the left 46.35

    Follow

    Get every new post delivered to your Inbox.