Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Внешние интерфейсы модуля | Вперед |
Драйверы: сетевой интерфейс
Примеры этого раздела заимствованы из [6] и находятся в архиве net.tgz.
lab1_network.c :
#include <linux/module.h> #include <linux/netdevice.h> #include <linux/init.h> static struct net_device *dev; static int my_open( struct net_device *dev ) { printk( KERN_INFO "Hit: my_open(%s)\n", dev->name ); /* start up the transmission queue */ netif_start_queue( dev ); return 0; } static int my_close( struct net_device *dev ) { printk( KERN_INFO "Hit: my_close(%s)\n", dev->name ); /* shutdown the transmission queue */ netif_stop_queue( dev ); return 0; } /* Note this method is only needed on some; without it module will fail upon removal or use. At any rate there is a memory leak whenever you try to send a packet through in any case*/ static int stub_start_xmit( struct sk_buff *skb, struct net_device *dev ) { dev_kfree_skb( skb ); return 0; } #ifdef HAVE_NET_DEVICE_OPS static struct net_device_ops ndo = { .ndo_open = my_open, .ndo_stop = my_close, .ndo_start_xmit = stub_start_xmit, }; #endif static void my_setup( struct net_device *dev ) { int j; printk( KERN_INFO "my_setup(%s)\n", dev->name ); /* Fill in the MAC address with a phoney */ for( j = 0; j < ETH_ALEN; ++j ) { dev->dev_addr[ j ] = (char)j; } ether_setup( dev ); #ifdef HAVE_NET_DEVICE_OPS dev->netdev_ops = &ndo; #else dev->open = my_open; dev->stop = my_close; dev->hard_start_xmit = stub_start_xmit; #endif } static int __init my_init( void ) { printk( KERN_INFO "Loading stub network module:...." ); dev = alloc_netdev( 0, "mynet%d", my_setup ); if( register_netdev( dev ) ) { printk( KERN_INFO " Failed to register\n" ); free_netdev( dev ); return -1; } printk( KERN_INFO "Succeeded in loading %s!\n\n", dev_name( &dev->dev ) ); return 0; } static void __exit my_exit( void ) { printk( KERN_INFO "Unloading stub network module\n\n" ); unregister_netdev( dev ); free_netdev( dev ); } module_init( my_init ); module_exit( my_exit ); MODULE_AUTHOR( "Bill Shubert" ); MODULE_AUTHOR( "Jerry Cooperstein" ); MODULE_AUTHOR( "Tatsuo Kawasaki" ); MODULE_DESCRIPTION( "LDD:1.0 s_24/lab1_network.c" ); MODULE_LICENSE( "GPL v2" );
Это сетевое устройство уже можно установить:
$ sudo ifconfig mynet0
mynet0: error fetching interface information: Device not found
$ sudo insmod lab1_network.ko
$ lsmod | head -n2
Module Size Used by lab1_network 1172 0
$ dmesg | tail -n6
Loading stub network module:.... my_setup() Succeeded in loading mynet0! Hit: my_open(mynet0) mynet0: no IPv6 routers present
И теперь мы можем с ним немного поработать:
$ sudo ifconfig mynet0
mynet0 Link encap:Ethernet HWaddr 00:01:02:03:04:05 BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
$ sudo ifconfig mynet0 up 192.168.1.200
$ sudo ifconfig mynet0
mynet0 Link encap:Ethernet HWaddr 00:01:02:03:04:05 inet addr:192.168.1.200 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::201:2ff:fe03:405/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
$ ping 192.168.1.200
PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.056 ms 64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=0.051 ms 64 bytes from 192.168.1.200: icmp_seq=3 ttl=64 time=0.055 ms 64 bytes from 192.168.1.200: icmp_seq=4 ttl=64 time=0.052 ms 64 bytes from 192.168.1.200: icmp_seq=5 ttl=64 time=0.054 ms 64 bytes from 192.168.1.200: icmp_seq=6 ttl=64 time=0.052 ms ^C --- 192.168.1.200 ping statistics --- 6 packets transmitted, 6 received, 0% packet loss, time 5440ms rtt min/avg/max/mdev = 0.051/0.053/0.056/0.006 ms
Удаляем сетевой интерфейс:
$ sudo rmmod lab1_network
$ dmesg | tail -n3
Unloading stub network module Hit: my_close(mynet0)
$ sudo ifconfig mynet0
mynet0: error fetching interface information: Device not found
Как уже отмечалось выше, основу структуры описания сетевого интерфейса составляет структура struct net_device, описанная в <linux/netdevice.h>. Это очень крупная структура, содержащая не только описание аппаратных средств, но и конфигурационные параметры сетевого интерфейса по отношению к выше лежащим протоколам, например:
struct net_device { char name[ IFNAMSIZ ] ; ... unsigned long mem_end; /* shared mem end */ unsigned long mem_start; /* shared mem start */ unsigned long base_addr; /* device I/O address */ unsigned int irq; /* device IRQ number */ ... unsigned mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ ... /* Interface address info. */ unsigned char perm_addr[ MAX_ADDR_LEN ]; /* permanent hw address */ unsigned char addr_len; /* hardware address length */ ... }
- где поле type, например, определяет тип аппаратного адаптера с точки зрения ARP-механизма разрешения MAC адресов (<linux/if_arp.h>):
... #define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ ... #define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ #define ARPHRD_ARCNET 7 /* ARCnet */ ... #define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ ... #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
Детальный разбор огромного числа полей struct net_device (этой и любой другой сопутствующей) или их возможных значений — бессмысленный, хотя бы потому, что эта структура радикально изменяется от подверсии к подверсии ядра; такой разбор должен проводиться «по месту».
Все структуры, описывающие доступные сетевые интерфейсы в системе, увязаны в связный список. Следующий пример диагностирует такой список:
lab1_devices.c :
#include <linux/module.h> #include <linux/init.h> #include <linux/netdevice.h> static int __init my_init( void ) { struct net_device *dev; printk( KERN_INFO "Hello: module loaded at 0x%p\n", my_init ); dev = first_net_device( &init_net ); printk( KERN_INFO "Hello: dev_base address=0x%p\n", dev ); while ( dev ) { printk( KERN_INFO "name = %6s irq=%4d trans_start=%12lu last_rx=%12lu\n", dev->name, dev->irq, dev->trans_start, dev->last_rx ); dev = next_net_device( dev ); } return 0; } static void __exit my_exit( void ) { printk( KERN_INFO "Module Unloading\n" ); } module_init( my_init ); module_exit( my_exit ); MODULE_AUTHOR( "Jerry Cooperstein" ); MODULE_DESCRIPTION( "LDD:1.0 s_25/lab1_devices.c" ); MODULE_LICENSE( "GPL v2" );
Выполнение (предварительно для убедительности загрузим ранее созданный модуль lab1_network.ko):
$ sudo insmod lab1_network.ko
$ sudo insmod lab1_devices.ko
$ dmesg | tail -n8
Hello: module loaded at 0xf8853000 Hello: dev_base address=0xf719c400 name = lo irq= 0 trans_start= 0 last_rx= 0 name = eth0 irq= 16 trans_start= 4294693516 last_rx= 0 name = wlan0 irq= 0 trans_start= 4294693412 last_rx= 0 name = pan0 irq= 0 trans_start= 0 last_rx= 0 name = cipsec0 irq= 0 trans_start= 2459232 last_rx= 0 name = mynet0 irq= 0 trans_start= 0 last_rx= 0
Предыдущий раздел: | Оглавление | Следующий раздел: |
Сеть | Путь пакета сквозь стек протоколов |