现在的位置: 首页 > 综合 > 正文

RTEMS 网络资料的部分翻译

2013年10月19日 ⁄ 综合 ⁄ 共 16619字 ⁄ 字号 评论关闭

应朋友要求,贴出来网络的部分翻译,翻译的不好,本来只是给自己使用的。实在拗不过朋友的请求,就贴出来了,望大家原宥。

 

%1.概述
任务和mbuf消息队列在一个简单的RTEMS网络程序中的原理如图/ref{network}所示:

 

每个网络接口的发送任务通常被阻塞,等待数据包到达发送队列。
一旦数据包到达,发送任务可能会被阻塞,等待来自发送中断处理程序的事件。
发送中断处理程序发送一个RTEMS事件给发送任务,表示传输硬件资源可用。

每个网络接口的接收任务通常被阻塞,等待来自接收中断处理程序的事件。
当这个事件收到后,接收任务读取数据包并将其转发到网络协议栈里供其他网络任务以进行后续处理。

网络任务处理传入的数据包,并处理一些定时操作,如TCP超时和生存时间(aging time),清除路由表项目。

'网络代码'包含程序可能运行在用户应用程序的上下文上,网络接口的接受任务或网络任务。
一个网络信号量可确保网络代码操纵网络数据结构时的一致性。

%2.1 Introduction
本章的目的是为编写的程序RTEMS的网络设备驱动程序。
该示例代码取自68360的网络设备驱动程序。
此驱动程序的源代码位于RTEMS源代码包的c/src/lib/libbsp/m68k/gen68360/network目录中。
手中有这个驱动程序的副本时,阅读以下章节将有显着的帮助。
%2.2 Learn about the network device
在开始写网络驱动程序前需要将网络设备变成完全与编程者眼中熟悉的设备。
以下列出了一些在撰写一个网络驱动程序前必须了解的细节。

  •  该设备是否使用DMA传送数据包到设备和内存,或者处理器必须复制数据包到设备和内存?
  •  如果设备使用DMA,是否能从多个分布在独立缓冲区内的数据帧形成一个单一的输出数据包?
  •  如果设备使用DMA,是否能够连续传出多个数据包,还是每个传出数据包都需要由驱动干预?
  •  是否设备自动将短帧填充到最低的64个字节,或由驱动提供填充?
  •  当检测到碰撞时设备是否会自动重新重传?
  •  如果设备使用DMA,它可以缓冲多个数据包到内存,或是接收任务必须在每一个包到达时重新启动传输?
  •  数据包过短,过长,或收到的CRC错误怎么处理?设备自动接收或是驱动程序必须介入?
  •  如何设置设备的以太网地址?如何对设备编程以接受或拒绝广播和多播数据包?

 设备产生什么样的中断?它为每一个到达的数据包产生中断,或仅为没有错误的接收数据包产生中断?它是否为
每个发送数据包产生中断,或只是在发送队列是空的时候产生中断?
在发送时检测到错误会发生什么?

此外,一些控制器在具体的板级配置下会产生特殊的问题。
例如,声波以太网控制器具有一个特别的可配置的数据总线接口。
它甚至可以被配置成16和32个数据位的总线。
这种类型的信息应从板子的供应商那里获取。

%2.3 Understand the network scheduling conventions
当为驱动程序编写发送和接收任务时,应注意遵循以下网络调度的约定。
所有与网络相关的任务共享各种数据结构和资源。
只有当他们持有的网络信号(rtems_bsdnet_semaphore),才能确保这些任务执行的数据结构的一致性。
发送和接收任务必须遵守此协议。
要非常小心,以避免和其他网络任务抱死(deadly embraces)。
系统提供了一些例程,使网络驱动程序代码编写更容易符合网络任务调度的约定。

 void rtems_bsdnet_semaphore_release(void):
这个函数释放网络信号量。网络驱动程序任务在任何阻塞RTEMS请求之前必须立即调用该函数;

 void rtems_bsdnet_semaphore_obtain(void):
此函数获取网络信号量。如果一个网络驱动任务已释放
网络信号量以允许其他被阻塞的网络相关任务执行,那么这个函数必须立即被调用以重新获取信号量以从阻塞的RTEMS请求中返回;

 rtems_bsdnet_event_receive(rtems_event_set, rtems_option, rtems_interval, rtems_event_set *):
网络驱动任务要等待事件时,应调用此功能。这个函数将释放网络信号量,调用rtems_event_receive等待指定的单个或多个事件,
并重新获取信号量。返回值是由rtems_event_receive返回的值。

%Network Driver Makefile
网络驱动程序被认为是BSD网络包的一部分,因此编译时要使用了适当的选项。
可以通过添加-D__INSIDE_RTEMS_BSD_TCPIP_STACK__到命令行实现。
如果驱动程序在RTEMS源码树中或是使用RTEMS应用程序的Makefile进行编译,
那么加入以下代码行实现:

    DEFINES += - D__INSIDE_RTEMS_BSD_TCPIP_STACK__

这是等同于以下列表中的定义。在RTEMS BSD网络协议栈的早期版本要求所有这些都必须被定义。

    -D_COMPILING_BSD_KERNEL_ -DKERNEL -DINET -DNFS /
    -DDIAGNOSTIC -DBOOTP_COMPAT

定义这些宏告诉网络头文件网络驱动程序以扩展协议栈可见性的方式编译。
这与简单地使用网络协议栈的应用程序形成鲜明地对比。
应用程序不需要这个水平的能见度,并应坚持应用水平API的可移植性。

网络协议栈是内部逻辑的直接结果(BSD 由自己的代码全部撰写),这意味着网络驱动程序使用
BSD的内存分配例程,例如,有三个参数的malloc。例如超声设备驱动程序(c/src/lib/libchip/network/sonic.c)是一个典型的例子。
正因为如此,网络驱动程序不应该包括<stdlib.h>。这样做将导致malloc()定义的冲突。

%2.5 Write the Driver Attach Function
驱动连接功能可用于配置驱动程序和连接协议栈和驱动程序。

驱动连接函数需要一个指向一个rtems_bsdnet_ifconfig的结构体作为其唯一的参数。
设置这个驱动的参数基于这个结构内的值。
如果配置结构中的条目是零,连接函数选择适当的默认值作为参数。

驱动应设置设备相关结构内的ifnet结构中的几个域,设备相关的数据结构是由驱动提供和维护的:

  •  ifp-> if_softc:指向设备相关的数据。在设备相关的数据结构内第一项数据结构必须是一个arpcom结构;
  •  ifp->if_name:该设备的名称。网络协议栈使用此字符串和设备号用于设备名称查找。该设备名称应获得了在配置结构的名称条目;
  •  ifp->if_unit:设备编号。网络协议栈使用这个号码和设备名用于设备名称查找。例如,如果ifp->if_name是'scc'并且ifp->if_unit是'1',完整的设备的名称将是'SCC1'。该单位的数量应从配置结构中的'name'获取;
  •  ifp->if_mtu:该设备的最大传输单元。对于以太网设备这个值应该总是为1500;
  •  ifp->if_flags:设备标志。以太网设备应设置标志为 IFF_BROADCAST  IFF_SIMPLEX',表明该设备可以传输包到多个目的地,不在同一时间接收和发送;
  •  ifp->if_snd.ifq_maxlen:等待发送到该驱动程序里的数据包队列的最大长度。这通常是设置为ifqmaxlen;
  •  ifp->if_init:该驱动程序初始化函数的地址;
  •  ifp->if_start:该驱动程序启动函数的地址;
  •  ifp->if_ioctl:该驱动程序ioctl函数的地址;
  •  ifp->if_output:输出的函数的地址。以太网设备应设置该值为ether_output。

RTEMS提供了一个函数来解析配置结构中的驱动程序名称,将其变为设备名称和单元号。

    int rtems_bsdnet_parse_driver_name (
        const struct rtems_bsdnet_ifconfig *config,
        char **namep);

该函数有两个参数,一个指向配置结构的指针和一个指向一个字符的指针。
函数分析配置名称条目,为该驱动程序的名称分配内存,将驱动程序的名称放置在这个内存中,设置第二个参数指向名称并返回单元号。
发生错误时,总打印一个消息并返回-1。

一旦连接函数完成上述条目,通过调用if_attach函数它必须连接驱动程序的数据结构到设备列表中。
以太网设备应调用ether_ifattach。
这两个函数需要一个设备的ifnet结构指针作为他们唯一参数。

在连接函数应该返回一个非零值,表明该驱动程序已成功配置和连接。

%2.6 Write the Driver Start Function.
%2.6编写驱动程序启动功能。
在网络协议栈每次要启动发送时应调用这个函数。
每当网络协议栈添加一个数据包到一个设备的发送队列时,当IFF_OACTIVE位
在设备的if_flags位未设置才调用启动。

对于许多设备这个函数只需要设置在if_flags中的IFF_OACTIVE位,
并发送一个事件给发送任务,表明一个包在驱动程序的发送队列中。
%2.7编写驱动程序的初始化函数。
%2.7 Write the Driver Initialization Function.
这个函数应初始化设备,连接中断处理程序,并启动驱动程序的发送和接收任务。

    rtems_id rtems_bsdnet_newproc (char *name,
        int stacksize,
        void(*entry)(void *),
        void *arg);

函数rtems_bsdnet_newproc应用于启动驱动程序的任务。

请注意,网络协议栈可能会不止一次调用驱动程序的初始化函数。
确认接收和发送任务的多个版本不会被意外启动。

%2.8编写驱动程序发送任务
%2.8 Write the Driver Transmit Task
这个任务是从驱动程序的发送队列中移除数据包并发送到该设备中。
该任务应等待一个从驱动程序中的启动函数中发送的事件,表明有数据包等待发送。
当发送任务耗尽了驱动中的发送队列,任务应将if_flags中的IFF_OACTIVE位清除直到有另一个输出数据包用于缓冲。

%2.9编写驱动程序接收任务
%2.9 Write the Driver Receive Task
这项任务应被阻塞直到有数据包到达设备。
如果设备将一个数据包输送到以太网协议栈内,以太网接口函数ether_input应该被调用。
ether_input的参数是一个指向接口数据结构的指针,一个指向以太网头的指针和一个指向包含数据的mbuf的指针。

%2.10写驱动程序的中断处理程序
%2.10 Write the Driver Interrupt Handler
一个典型的中断处理程序将只需要在中断发生时做硬件需要的操作并发送一个RTEMS事件以唤醒驱动接收或发送任务。
网络接口的中断处理程序一定不要调用任何其他网络函数。

%2.11 Write the Driver IOCTL Function
这个函数处理ioctl的定位在这个设备上的请求。ioctl必须处理以下命令:

 SIOCGIFADDR、SIOCSIFADDR:如果这个设备是一个以太网接口,这些命令需要传递到ether_ioctl中;
 SIOCSIFFLAGS:这个命令通常用于启动或停止设备,依赖于接口if_flags中的IFF_UP和IFF_RUNNING位,
IFF_RUNING停止设备;IFF_UP启动设备; IFF_UPIFF_RUNNING'停止然后启动设备;0不做任何事情。

%2.12 Write the Driver Statistic-Printing Function
%This function should print the values of any statistic/diagnostic counters the network driver may use.
这个函数应打印网络设备驱动的任何统计、诊断数值。
这个驱动的ioctl函数应调用统计打印函数,当ioctl命令是SIO_RTEMS_SHOW_STATS。
%The driver ioctl function should call the statistic-printing function when the ioctl command is SIO_RTEMS_SHOW_STATS.

/section{应用程序中使用网络}
%3.1 Makefile changes
%3.1.1 Including the required managers
这个FreeBSD网络代码在应用程序中需要RTEMS的几个管理器:io管理器、event管理器、semaphore管理器。

%3.1.2 Increasing the size of the heap
网络任务会申请大量的内存。对于大多数应用程序,堆至少应为256 KB。
设置堆的额外内存可以通过如下的方式调整CFLGAS_LD的定义:

    CFLAGS_LD += -Wl,--defsym -Wl,HeapSize=0x80000

这为堆多设置了512 KB的内存。

%3.2系统配置
%3.2 System Configuration
网络任务申请一些RTEMS的对象。应用程序配置表必须统计这些对象。
下面列出了要求。

 TASK(任务):一个网络任务再加上每个设备的网络任务接收和发送任务;
 SEMAPHORES(信号量):一个网络信号加上系统日志二值信号量,如果应用程序中使用了openlog/syslog;
 EVENT(事件):网络协议栈使用了RTEMS_EVENT_24和RTEMS_EVENT_25。这没有对应用程序的配置没有影响,
但调用网络函数的应用任务不应该为了其它目的使用这些事件。

%3.3初始化
%3.3 Initalization
%3.3.1附加的包含文件
%3.3.1 Additional include files
声明网络配置网络结构并调用
初始化函数的源文件必须包含:

    #include <rtems/rtems_bsdnet.h>

%3.3.2网络配置
%3.3.2 Network Configuration
指定网络的配置通过声明和初始化rtems_bsdnet_config结构实现。

    struct rtems_bsdnet_config {
        /*
         *这个字段指向 ifconfig 链表的头节点
         */
        struct rtems_bsdnet_ifconfig *ifconfig;
        /*
         * 这个字段应该是 rtems_bsdnet_do_dhcp, 如果使用
         * dhcp 配置整个网络系统,如果为 NULL,则不使用
         * dhcp(手工配置)
         */
        void (*bootp)(void);
        /*
         * 这个字段可以被初始化为 0,在这个情况下将使用
         * 默认的优先级别
         */
        rtems_task_priority network_task_priority; /* 100 */
        unsigned long mbuf_bytecount;           /* 64 kbytes */
        unsigned long mbuf_cluster_bytecount;   /* 128 kbytes */
        char *hostname;         /* BOOTP */
        char *domainname;       /* BOOTP */
        char *gateway;          /* BOOTP */
        char *log_host;         /* BOOTP */
        char *name_server[3];   /* BOOTP */
        char *ntp_server[3];    /* BOOTP */
        unsigned long sb_efficiency; /* 2 */
        /* UDP TX: 9216 bytes */
        unsigned long udp_tx_buf_size;
        /* UDP RX: 40 * (1024 + sizeof(struct sockaddr_in)) */
        unsigned long udp_rx_buf_size;
        /* TCP TX: 16 * 1024 bytes */
        unsigned long tcp_tx_buf_size;
        /* TCP TX: 16 * 1024 bytes */
        unsigned long tcp_rx_buf_size;
    };

下面会详细描述这个结构体中的每一个字段。
如果应用程序中使用了BOOTP / DHCP来获得网络配置信息,
并且如果你满意下列描述的默认值,你只需要提供这个结构体的前两个字段。

  struct rtems_bsdnet_ifconfig *ifconfig':
指向第一个网络设备的配置结构的指针。这个结构体会在后续的部分进行介绍。
必须为这个字段提供一个值,因为它没有默认值;

  void (*BOOTP)(void)':此字段应设置为 rtems_bsdnet_do_bootp'或
rtems_bsdnet_do_dhcp',如果应用程序将使用 BOOTP/DHCP'来获得网络配置信息。
如果应用程序不使用 BOOTP/DHCP',它应该被设置为NULL;

  int network_task_priority':网络和网络设备的接收和发射任务将运行的优先级别。
如果为这个字段指定一个0值,任务将运行在优先级100;

  unsigned long buf_bytecount':从堆中分配作为mbuf使用的字节数。如果为该字段指定0值,将申请64 KB;

  unsigned long mbuf_cluster_bytecount':从堆中分配作为 mbuf'的群集使用的字节数。如果为该字段指定0值,将申请128 KB;

  char *hostname':该系统的主机名。如果这样,或下列任何条目为NULL,它的值可以从一个 BOOTP/DHCP'服务器获得;

  char *domainname':该系统隶属互联网域名的名称;

  char *gateway':网络网关机器的IP地址,用‘.十进制数’(129.128.4.1)的形式指定;

  char *log_host':syslog消息发送到的机器的IP地址;

  char *name_server[3]':多达三个主机的IP地址,作为因特网域名服务器;

  char *ntp_server[3]':多达三个主机的IP地址,作为网络时间协议(NTP)服务器;

  unsigned long sb_efficiency':这是五个涉及到每个socket的缓冲区内存消耗量的第一个配置参数。
TCP/IP协议栈为每个打开的套接字(socket)保留一些缓冲区(例如mbuf)。
TCP/IP协议栈对每个TCP和UDP套接字关联的发送和接收缓冲区有不同的限制。
通过调节这些参数,应用程序开发人员可以平衡内存的消耗和性能。
默认参数偏向性能多于内存消耗。见http://www.rtems.org/ml/rtems-users/2004/february/msg00200.html,可以得到更多的信息。
但注意,在RTEMS 4.8以后的版本, sb_efficiency'的缺省值由8变成了2。
用户还应该了解 SO_SNDBUF'和 SO_RCVBUF'的IO控制操作。
这些操作可以用来为特定的套接字指定发送和接收缓冲区的大小。
没有一个标准的IO控制去改变 sb_efficiency'参数。 sb_efficiency'参数是一个缓冲区因子用于实现TCP/IP协议栈。
缺省值为2表示使用双倍的缓冲区。当为每个套接字申请内存时,这个数字会乘以每个套接字的缓冲区大小;

  unsigned long udp_tx_buf_size':此配置参数指定用于UDP套接字发送缓冲区的最大内存用量。
默认大小为9216字节,对应的最大数据报文的大小;

  unsigned long udp_rx_buf_size':此配置参数指定用于UDP套接字接收缓冲区的最大内存用量。默认长度是(按字节计算):
40 * (1024 + sizeof(struct sockaddr_in))';

  unsigned long tcp_tx_buf_size':此配置参数指定用于TCP套接字传输缓冲区的最大内存用量。默认大小为16 KB;

  unsigned long tcp_rx_buf_size':此配置参数指定用于TCP套接字接收缓冲区的最大内存用量。默认大小为16 KB。

此外,在下列领域rtems_bsdnet_ifconfig也值得注意。

  int port':外部以太网可以访问I/O端口号(如0x240);
  int irno':外部以太网控制器的中断号;
  int bpar':外部以太网控制器上共享内存的地址。

%3.3.3网络设备的配置
%3.3.3 Network device configuration
用户通过声明和初始化一个rtems_bsdnet_ifconfig结构体变量来指定每个网络设备。

下面会详细介绍结构体中的每一个字段。
一个使用单一网络接口的应用程序,会从一个 BOOTP/DHCP'服务器获取网络配置信息,
并且所有驱动程序的参数使用缺省值,只需要初始化结构体项的前两个字段。

    struct rtems_bsdnet_ifconfig {
        /*
         * These three entries must be supplied for each interface.
         */
        char        *name;

        /*
         * This function now handles attaching and detaching an interface.
         * The parameter attaching indicates the operation being invoked.
         * For older attach functions which do not have the extra parameter
         * it will be ignored.
         */
        int        (*attach)(struct rtems_bsdnet_ifconfig *conf, int attaching);

        /*
         * Link to next interface
         */
        struct rtems_bsdnet_ifconfig *next;

        /*
         * The following entries may be obtained
         * from BOOTP or explicitily supplied.
         */
        char        *ip_address;
        char        *ip_netmask;
        void        *hardware_address;

        /*
         * The driver assigns defaults values to the following
         * entries if they are not explicitly supplied.
         */
        int        ignore_broadcast;
        int        mtu;
        int        rbuf_count;
        int        xbuf_count;

        /*
         * For external ethernet controller board the following
         * parameters are needed
         */
        unsigned int    port;   /* port of the board */
        unsigned int    irno;   /* irq of the board */
        unsigned int    bpar;   /* memory of the board */

      /*
       * Driver control block pointer. Typcially this points to the driver's
       * controlling structure. You set this when you have the structure allocated
       * externally to the driver.
       */
      void *drv_ctrl;

    };

  char *name':网络设备的全名。此名称由驱动的名称和单元号组成(例如“SCC1”)。 bsp.h'文件中
通常定义了 RTEMS_BSP_NETWORK_DRIVER_NAME'作为主(或唯一的)网络驱动程序的名称;

  int (*attach)(struct rtems_bsdnet_ifconfig *conf)':该驱动程序的连接函数的地址。
网络初始化函数调用这个函数来配置驱动程序并连接到网络协议栈。
bsp.h'文件中通常定义了 RTEMS_BSP_NETWORK_DRIVER_ATTACH'作为主(或唯一的)网络驱动程序的函数的名称;

  struct rtems_bsdnet_ifconfig *next':指向下一个网络设备的配置结构的指针,
如果本结构是最后一个网络接口的配置结构,该字段为NULL;

  char* ip_address':该设备的IP地址,用‘.十进制数’的形式指定(如129.128.4.2),如果该设备的配置信息
正从BOOTP/DHCP服务器获取,该字段的值为NULL;

  char* ip_netmask':该设备的IP地址掩码,用‘.十进制数’的形式指定(如255.255.255.0),如果该设备的配置信息
正从BOOTP/DHCP服务器获取,该字段的值为 NULL';

  void* hardware_address':该设备的硬件地址,如果驱动程序使用一些其他方式获取硬件地址,该字段值为 NULL'(通常是从设备或
引导序列的ROM中读取);

  int ignore_broadcast':如果该设备接收广播数据包,该字段的值为0;如果该设备是不接收广播数据包,该字段的值为非0;

  int mtu':该设备的最大传输单元(Maximum Transmission Unit, MTU),该字段为0时驱动会选择一个默认值(通常以太网设备为1500);

  int rbuf_count':设备接收时使用的缓冲区数量,该字段为0时该驱动程序选择默认值;

  xbuf_count':设备发送时使用的缓冲区数量,该字段为0时该驱动程序选择默认值。请记住,某些网络设备发送一个单个的缓冲区时可能使用4个或更多的传输描述符。

一个完整的网络配置可以像下面的例子这样简单。
这个配置使用一个网络接口,从 BOOTP/DHCP'服务器获取网络配置信息,并使用所有驱动程序的默认值参数。

    static struct rtems_bsdnet_ifconfig netdriver_config = {
        RTEMS_BSP_NETWORK_DRIVER_NAME,
        RTEMS_BSP_NETWORK_DRIVER_ATTACH
    };
    struct rtems_bsdnet_config rtems_bsdnet_config = {
        &netdriver_config,
        rtems_bsdnet_do_dhcp,
    };

%3.3.4网络初始化
%3.3.4 Network initialization
网络任务必须在任何网络I/O操作可以执行前先启动。
这是通过调用函数 rtems_bsdnet_initialize_networt()'完成的。
这个函数原型在文件 rtems/rtems_bsdnet.h'中。函数返回0表示成功,
-1表示错误并且在 errno'中存储着错误代码。
部分初始化的影响是不可能被撤销的,虽然如此,该函数可被调用一次,无论返回代码是什么。
因此,如果失败的情况可得到纠正,系统必须复位以允许网络再次初始化的尝试。

%3.4应用程序编程接口
%3.4 Application Programming Interface
RTEMS的网络包提供了几乎全部的BSD网络服务。
网络函数工作行为与BSD下对应的函数类似,除了以下:

 同一时间,一个给定的套接字只可以被一个任务读取或写入;
 select函数只用于与套接字相关的文件描述符;
 您必须在调用任何syslog函数之前调用 openlog';
 一些网络的函数不是线程安全的。例如,下面的函数返回一个指针指向一个静态的缓冲区,
只保持到下一个调用有效:
[] gethostbyaddr'
[] gethostbyname'
[] inet_ntoa'(虽然 inet_ntop'是线程安全的);
 RTEMS网络包收集统计信息;
 新增的一个机制用于窃听每个接口并监控每一个数据包接收和传输;
 新增的 SO_SNDWAKEUP'和 SO_RCVWAKEUP'套接字选项。

%新的一些功能进行了更详细的在下面的章节。

%3.4.1网络统计
%3.4.1 Network Statistics
有一些函数可以打印网络协议栈收集的统计数据。
这些函数在 rtems/rtems_bsdnet.h'中定义。

  rtems_bsdnet_show_if_stats':显示网络接口收集的统计数据;

  rtems_bsdnet_show_ip_stats':显示IP数据包的统计数据;

  rtems_bsdnet_show_icmp_stats':显示ICMP包的统计数据;

  rtems_bsdnet_show_tcp_stats':显示TCP报文统计数据;

  rtems_bsdnet_show_udp_stats':显示UDP数据包统计数据;

  rtems_bsdnet_show_mbuf_stats':显示mbuf的统计数据;

  rtems_bsdnet_show_inet_routes':显示路由表。

%3.4.2借助接入接口
%3.4.2 Tapping Into an Interface
RTEMS向BSD网络中增加两个新的 ioctls'代码:SIOCSIFTAP和SIOCGIFTAP。
这些用来设置和获取一个窃听函数。监听函数将在每个以太网接口收到数据包时调用。

这些功能调用起来像接口的其它 ioctls'一样,如SIOCSIFADDR。
当使用SIOCSIFTAP设置窃听函数,设置ifreq结构体中的ifr_tap字段指向窃听函数。

当使用SIOCGIFTAP检索窃听函数时,当前的在ifr_tap字段中的窃听函数被返回。
为了停止窃听数据包,调用SIOCSIFTAP将ifr_tap字段设置成0。

窃听函数的原型是这样的:

    int tap (struct ifnet *, struct ether_header *, struct mbuf *);

如果包被完全处理,窃听函数应该返回1,这种情况下调用者简单的丢弃mbuf。
如果包应该被传递到网络的更高层,窃听函数应该返回0。

窃听函数被调用时网络信号量应锁定。它不能调用与其自身处于相同级别的网络函数。
它调用其他非网络的RTEMS函数是安全的。

%3.4.3套接字选项
%3.4.3 Socket Options
RTEMS为setsockopt和getsockopt增加了两个新的SOL_SOCKET级别的选项:
SO_SNDWAKEUP和SO_RCVWAKEUP。
对于这个选项,它们的值应指向一个sockwakeup的结构。
该sockwakeup结构具有以下字段:

    void (*sw_pfn) (struct socket *, caddr_t);
    caddr_t sw_arg;

这些选项用于设置一个回调函数,例如在有数据在套接字(SO_RCVWAKEUP)中可用时并且有空间可以接受
数据写入到套接字中(SO_SNDWAKEUP)时被调用。

如果调用setsockopt并使用SO_RCVWAKEUP选项,并且sw_pfn字段不为零,
这时当有数据可从套接字中读取,sw_pfn字段所指向的函数将被调用。
一个指向套接字的结构的指针将作为第一个参数传递给函数。sw_arg字段为SO_RCVWAKEUP调用时的第二个传递到函数的参数所修改。

如果调用setsockopt并使用SO_SNDWAKEUP选项,并且sw_pfn字段不为零,
这时当有空间可以接受的数据写入套接字时,sw_pfn字段所指向的函数将被调用。
传递给该函数的参数将被视为带有SO_SNDWAKEUP。

当函数被调用时,网络信号量将被锁定,回调函数将运行在的网络任务的上下文中。
该函数必须小心,不要调用任何网络函数。
调用RTEMS函数是没有问题的,例如,发送一个RTEMS事件。

这些回调函数的目的是当大量的套接字需要处理时允许更有效的选择调用。

回调被调用的统一标准是select函数标记“就绪”的套接字。
在Stevens 的 Unix Network Programming,第153-154页,
“Under what Conditions Is a Descriptor Ready?”一节中,你将发现
你会发现最后的条件的列表为可读可写,也决定着函数被调用。

当接收到的字节数等于或超过该套接字接收缓冲区的“低水位线”(缺省为1字节),你得到一个可读的回调。
如果有100个字节在接收缓冲区内,你只读了1个字节,你不会立即得到另外一个回调。
然而,当你读其余的99字节或至少有1到达后,你会得到另一个回调。
使用非阻塞套接字,你应该读取数据直到它产生错误EWOULDBLOCK,
然后让可读回调函数告诉你什么时候有更多的数据到达。(条件1.a.)

对于发送,当套接字连接后并且发送缓冲区的自由空间到达或高于“低
水位线”(默认4096字节),你会收到一个写回调。
如果没有写任何数据,你不会持续得到回调。
使用非阻塞函数写套接字,你应该调用写操作直到它返回实际写的数据量比请求的数据量少,
或它产生错误EWOULDBLOCK错误(表示缓冲区满,不能再被写入)。
当发生这种情况时可以尝试再次写入,但往往最好去做其他事情,
让写回调函数告诉你何时有空间可用来再次发送数据。
你只能得到一个可写回调,当发送缓冲区的自由空间高于“低
水位线”时,而不是每次你写数据到一个还未写满的发送缓冲区内。(条件2.a.)

其余的条件Stevens也都列举的相关的事实,当连接、断开和错误发生,而不仅是接收或发送数据时套接字变为可读
和/或可写的条件 。
例如,当一个服务器“监听”的套接字变为可读则表示一个客户端已连接,并且接受调用不会被阻塞,而不是接收网络数据。(条件1.c.)

%3.4.4 Adding an IP Alias
%The following code snippet adds an IP alias:
下面的代码为系统增加一个别名IP地址。

    void addAlias(const char *pName, const char *pAddr, const char *pMask)
    {
        struct ifaliasreq aliasreq;
        struct sockaddr_in *in;

        /* initialize alias request */
        memset(&aliasreq, 0, sizeof(aliasreq));
        sprintf(aliasreq.ifra_name, pName);

        /* initialize alias address */
        in = (struct sockaddr_in *)&aliasreq.ifra_addr;
        in->sin_family = AF_INET;
        in->sin_len = sizeof(aliasreq.ifra_addr);
        in->sin_addr.s_addr = inet_addr(pAddr);

        /* initialize alias mask */
        in = (struct sockaddr_in *)&aliasreq.ifra_mask;
        in->sin_family = AF_INET;
        in->sin_len = sizeof(aliasreq.ifra_mask);
        in->sin_addr.s_addr = inet_addr(pMask);

        /* call to setup the alias */
        rtems_bsdnet_ifconfig(pName, SIOCAIFADDR, &aliasreq);
    }

%3.4.5 Adding a Default Route
%The function provided in this section is functionally equivalent to the command route add
%default gw yyy.yyy.yyy.yyy:
这个小节提供的函数等于在命令 route add default gw yyy.yyy.yyy.yyy'。

%3.4.6使用的NTP时间同步
%3.4.6 Time Synchronization Using NTP

    int rtems_bsdnet_synchronize_ntp(int interval,
        rtems_task_priority priority);

如果参数interval为0,函数将~RTEMS的时间日期时钟与在rtems_bsdnet_ntpserve数组中的第一NTP服务器同步并返回。
优先级参数priority被忽略。

如果间隔参数的值大于0,函数按指定的优先级别(priority)启动一个RTEMS任务,并且按照‘间隔’的秒数不断的轮询NTP服务器。
注意:此模式的操作尚未实现。

一旦成功的同步了RTEMS的时间日期时钟,函数返回0。
如果发生错误打,则印一条消息,函数返回-1并且在errno里存放错误代码。
通讯没有超时,如果NTP服务器没有响应,函数将一直等下去。

%4测试驱动程序
%4.1初步设置
%4 Testing the Driver
%4.1 Preliminary Setup
用于测试的驱动程序的网络至少应包括:

 在具体的硬件上运行驱动程序。如果能带调试器来控制目标机器的运作,会使得测试更加容易;
 以太网络分析仪或带有以太网抓包软件(如ethersnoop或tcpdump)的工作站;
 工作站(一台PC机)。

在早期的调试中,应该考虑单独的对目标板,工作站和抓包软件组建一个小网络。
它的优势在于:

 减少了通讯的包数量,便于抓包程序处理和分析目标处理在驱动工作以后的动作;
 任何严重的错误只会影响您的小型网络,而不是整个建筑物或校园网。可以避免任何不必要的问题;
 测试数据包比较容易重复地产生;
 性能测量不影响网络上的其他系统。

%4.2调试输出
%4.2 Debug Output
网络中有很多的调试输出可以启用,以帮助追查网络协议栈的行为。下面列出全部的调试输出:

 mbuf的活动:
在网络协议栈代码中的sys/mbuf.h文件里已经注释掉了对printf的调用。
取消这些注释,当mbuf分配和释放的时候会产生输出信息。这是非常有用的查找内存泄漏的工具;

 发送和接收队列:
在网络协议栈代码中的net/if.h文件里已经注释掉了对printf的调用。
取消这些注释,当从发送或接收数据包队列中插入或移除一个数据包时会产生输出。
这些队列可以看作设备驱动程序和网络协议栈之间的边界。
如果网络协议栈要发送而插入数据包到发送队列,设备驱动程序不出列,那么将指示这个问题在设备驱动程序的发送端。
相反,如果设备驱动程序因为它接收数据包而让其包入队列(通过调用ether_input),但没有数据包被网络协议栈移出队列。
这种情况很可能是网络服务任务没有正确启动。

 TCP状态转换:万一有人会想查看TCP状态转换,可在opt_tcpdebug.h文件中定义TCPDEBUG宏。
这会使tcp_trace()例程被网络协议栈调用,并且状态转换会记录到tcp_debug数据结构里。
如果文件netinet/tcp_debug.c中的tcpconsdebug变量设置成1,则状态转换也将被打印到控制台。

抱歉!评论已关闭.