新闻中心

EEPW首页>嵌入式系统>设计应用> Linux串口上网的程序实现方法

Linux串口上网的程序实现方法

作者: 时间:2011-05-10 来源:网络 收藏
ether_setup()填充一些以太网的缺省设置。dev->hard_header_cache=NULL表示不缓存向本网络接口回复的ARP网络数据包。IFF_NOARP的标志设置表明本网络接口不使用ARP。ARP的主要功能是获得通信对方的网络接口的硬件地址,本文的伪网络接口的物理地址是中设定的伪物理地址,所以我们不需要ARP协议。SET_MODULE_OWNER(dev)这个宏是设置dev结构中owner域(定义为struct module *owner;),使得它指向本模块本身。与字符设备一样,本网络设备也需要定义在其上的操作例程。下面就对ednet_init()中用户定义的设备操作函数做进一步说明。整个伪网络设备操作调用结构如图6所示。

本文引用地址://m.amcfsurvey.com/article/150775.htm

图 6

由图6我们看到,ednet_rx()并不是网络设备的一个操作,而是模块中的一个函数。在实际的网卡驱动中,当网卡确实接收到数据的时候,由网络中断唤醒等待接收数据的用户进程,也就是说,ednet_rx()应该由那个网络中断处理例程调用。我们这里并没有中断,所以字符设备的device_write()可以看成是一个中断例程,也就是说,用户空间往字符写操作的时候,也就调用了网络设备的数据接收内核例程ednet_rx()了。然后ednet_rx()会把原始的数据包发送到TCP/IP上层进行处理,这一切均依赖于内核API 函数netif_rx()。ednet_rx()就需要sk_buff数据结构(linux/skbuff.h>中定义),用来存放从网络接口接收到的原始网络数据,分配后的sk_buff结构将在TCP/IP协议栈上被释放掉。

下面介绍一下网络设备的主要操作例程ednet_open()、ednet_release()、ednet_tx()、ednet_stats ()、ednet_change_mtu()、ednet_header()。网络设备文件操作结构struct net_device(linux/netdevice.h>中有定义)中定义了指向以上函数的函数指针的原形:

ednet_open: int (*open)(struct net_device *dev);

ednet_release: int (*stop)(struct net_device *dev);

ednet_tx: int (*hard_start_xmit) (struct sk_buff *skb,struct net_device *dev);

ednet_stats: struct net_device_stats* (*get_stats)(struct net_device *dev);

ednet_change_mtu:int(*change_mtu)(struct net_device *dev, int new_mtu);

ednet_header: int (*hard_header) (struct sk_buff *skb,

struct net_device *dev,

unsigned short type,

void *daddr,

void *saddr,

unsigned len);

操作int ednet_open(struct net_device *dev)的作用是打开伪网络接口设备,获得其需要的I/O端口、IRQ等,但是本网络接口不需要和实际硬件打交道,所以不需要自动获得或者赋予I/O端口值,也不需要IRQ中断号,唯一需要指定的是其伪硬件地址(这个硬件地址是0ED000,ifconfig可以看到其硬件地址是 00:45:44:30:30:30,struct net_device中的dev_addr域存放网络接口的物理地址。操作ednet_open()必须调用netif_start_queue()内核API开启网络接口接收和发送数据队列。

当接口关闭的时候,int ednet_release(struct net_device *dev)例程被系统调用,在ednet_release()中调用netif_stop_queque()将停止接收和发送队列的工作。

伪网络设备驱动的传送例程int ednet_tx(struct sk_buff *skb, struct net_device *dev)将把要发送的网络数据包写入字符设备ed[ED_TX_DEVICE]。在发送完毕数据包的时候,dev_kfree_skb() Kernel API释放由上层协议栈分配的sk_buff数据块。伪网络接口在进行硬件传输的时候,需要为网络数据包打上时间戳。如果传送数据包的时候超时,将调用超时处理例程ednet_tx_timeout()超时处理例程。例程ednet_tx()调用真正的硬件传送例程ednet_hw_tx()在实际的网卡驱动程序中,就是真正向特定的网络硬件设备写数据的程序。我们看到,我们的硬件就是本文前面描述的字符设备,字符设备的操作例程.kernel_write()在ednet_hw_tx()将被调用。

如果我们希望使用ifconfig看到伪网络接口的统计信息,那么系统就调用 struct net_device_stats *ednet_stats(struct net_device *dev)。我们看到,网络接口的统计信息被放到设备的私有数据指针指向的内存。网络数据信息的统计结构被放在内核结构struct net_device_stats中。

在TCP会话中,也许要协商MTU的大小,int ednet_change_mtu(struct net_device *dev, int new_mtu)可以随时改变MTU的大小。比如在使用FTP协议的时候,在传送数据库的时候,MTU可能被协商为最大,以提高网络传送吞吐量。由于改变了MTU,存放网络数据的字符设备初始化分配的缓存区就要重新被分配,并把已经存放数据的旧的缓存区的内容拷贝到新的缓存区中,所以,当MTU改变大小的时候,那么就要使用kmalloc(new_mtu ,GFP_KERNEL)重新分配缓存区。读者可以根据自己的需要定义新的缓存区大小。kfree()是内核API,负责释放内核空间的内存,它的使用和用户空间的free()系统调用一致,这里就不列举ed_realloc()函数的源程序了。

IP数据包在被网络接口发送前,需要构建其以太网头信息int ednet_header(struct sk_buff *skb,struct net_device *dev,unsigned short type,void *daddr,void *saddr,unsigned int len)例程完成此功能,我们看到网络数据包的以太源、目的地址,都是从发送这个数据包的网络接口设备数据结构struct net_device中得到的。源地址和目的地址信息是从网络设备结构得到的。在编译本程序的时候,如果发现htons()这个函数没有定义,可以这样定义htons()为:#define htons(x) ((x>>8) | (x8)) 。

因为伪网络接口没有使用ARP获得硬件地址,所以我们可以把我们自己定义的伪硬件地址复制到数据包的以太网包头。2.4.x使用设备hard_header()代替设备rebuild_header()。2.x使用的rebuild_header()例程在本文的附加源程序中,这里不再说明。

编写用户空间通信程序

控制的server应用程序完成非常简单的打包和拆包的工作,它没有差错控制,没有重发机制,在实际应用中,需要加上适当的控制协议。server创建的子进程负责从读取数据并把数据传送到receiving device /dev/ed_rec;父进程则负责从sending device /dev/ed_tx 读取需要发送的网络数据包,然后从串口发送出去。子进程和父进程都是用轮询方式读取和写入设备。Server的程序流图如图所示。


图 7

传送的frame按照SLIP定义的格式:数据的两头都是END字符(0300),如图8所示。

图 8

特殊控制字符的定义如下:

#define END 0300

#define ESC 0333

#define ESC_END 0334

#define ESC_ESC 0335

linux操作系统文章专题:linux操作系统详解(linux不再难懂)

linux相关文章:linux教程




评论


相关推荐

技术专区

关闭