contiki 中数据包的接收与发送流程
2015-09-09 21:10
267 查看
--------------------------------------- 数据包接收流程 ----------------------------------------------------------------------
以ESB为例:CPU为msp430,
射频芯片为Tr1001。相关代码在/platform/esb
以及 /cpu/msp430 ,/core/net中
[align=left]在contiki-conf.h中首先对各层的协议栈进行了定义。[/align]
[align=left]如下:[/align]
[align=left]#define NETSTACK_CONF_RADIO tr1001_driver[/align]
[align=left]#define NETSTACK_CONF_NETWORK uip_driver[/align]
[align=left]#define NETSTACK_CONF_MAC nullmac_driver[/align]
[align=left]#define NETSTACK_CONF_RDC nullrdc_driver[/align]
[align=left][/align]
[align=left]一、 收包流程[/align]
[align=left]下面我们从主函数Contiki-esb-main.c开始,先说数据的接收流程。[/align]
[align=left]首先,定义一块网卡:[/align]
[align=left]static struct uip_fw_netif tr1001if =[/align]
[align=left] {UIP_FW_NETIF(0,0,0,0, 0,0,0,0, uip_driver_send)};[/align]
[align=left]其中uip_driver_send就是这块网卡的发包函数。[/align]
[align=left]在主函数中会进行协议栈的初始化,另外开启几个关于收发数据的进程。[/align]
[align=left]int main(void)[/align]
[align=left]{[/align]
[align=left] msp430_cpu_init();[/align]
[align=left] process_start(&etimer_process, NULL);[/align]
[align=left] netstack_init();[/align]
[align=left] init_uip_net();[/align]
[align=left] autostart_start(autostart_processes);[/align]
[align=left] watchdog_start();[/align]
[align=left] while(1) {[/align]
[align=left] int r;[/align]
[align=left] do {[/align]
[align=left] /* Reset watchdog. */[/align]
[align=left] watchdog_periodic();[/align]
[align=left] r = process_run();[/align]
[align=left] } while(r > 0);[/align]
[align=left] return 0;[/align]
[align=left]}[/align]
其中,init_uip_net()
中启动了两个进程如下:
[align=left]static void init_uip_net(void)[/align]
[align=left]{[/align]
[align=left] process_start(&tcpip_process, NULL);[/align]
[align=left] process_start(&uip_fw_process, NULL);[/align]
[align=left]}[/align]
[align=left]这两个进程我们在以后会用到。[/align]
[align=left][/align]
[align=left]netstack_init()如下:[/align]
[align=left]void netstack_init(void)[/align]
[align=left]{[/align]
[align=left] NETSTACK_RADIO.init();[/align]
[align=left] NETSTACK_RDC.init();[/align]
[align=left] NETSTACK_MAC.init();[/align]
[align=left] NETSTACK_NETWORK.init();[/align]
[align=left]}[/align]
[align=left]即,netstack_init会对各层驱动均进行初始化。[/align]
[align=left]下面,主要说Radio层的驱动初始化:[/align]
[align=left]Int tr1001_init(void)[/align]
[align=left]{[/align]
[align=left] PT_INIT(&rxhandler_pt);[/align]
[align=left] process_start(&tr1001_process, NULL);[/align]
[align=left] return 1;[/align]
[align=left]}[/align]
该初始化过程中启动了 tr1001_process,
如下:
[align=left]PROCESS_THREAD(tr1001_process, ev, data)[/align]
[align=left]{[/align]
[align=left] PROCESS_BEGIN();[/align]
[align=left] while(1) {[/align]
[align=left] PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);[/align]
[align=left] packetbuf_clear();[/align]
len = tr1001_read(packetbuf_dataptr(), PACKETBUF_SIZE); //
读取数据
[align=left] if(len > 0) {[/align]
[align=left] packetbuf_set_datalen(len);[/align]
NETSTACK_RDC.input(); //
向上提交
[align=left] }[/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]当该进程收到事件ev == PROCESS_EVENT_POLL时,就会从射频芯片读数据。[/align]
我们知道,射频芯片每收到一个frame,都会向cpu
发送一个中断,进而CPU将收到的数据读走。下面,看这个PROCESS_EVENT_POLL事件的产生过程。
[align=left]中断注册函数如下:[/align]
[align=left]interrupt (UART0RX_VECTOR)[/align]
[align=left] tr1001_rxhandler(void)[/align]
[align=left]{[/align]
[align=left] ENERGEST_ON(ENERGEST_TYPE_IRQ);[/align]
[align=left] tr1001_default_rxhandler_pt(RXBUF0);[/align]
[align=left] if(tr1001_rxstate == RXSTATE_FULL) {[/align]
[align=left] LPM4_EXIT;[/align]
[align=left] }[/align]
[align=left] ENERGEST_OFF(ENERGEST_TYPE_IRQ);[/align]
[align=left]}[/align]
[align=left][/align]
[align=left]Char tr1001_default_rxhandler_pt(unsigned char incoming_byte))[/align]
[align=left]{[/align]
[align=left] static unsigned char rxtmp, tmppos;[/align]
[align=left] if(rxcrctmp == rxcrc) {[/align]
[align=left] /* A full packet has been received and the CRC checks out. We'll[/align]
[align=left] request the driver to take care of the incoming data. */[/align]
[align=left] RIMESTATS_ADD(llrx);[/align]
[align=left] process_poll(&tr1001_process);[/align]
[align=left] PT_END(&rxhandler_pt);[/align]
[align=left]}[/align]
到这里,radio层的收包过程就结束了。通过 NETSTACK_RDC.input()
将数据提交到rdc层。
进入函数:nullrdc_driver.input(),
即core\net\mac 下的 nullrdc.c
中的packet_input。
[align=left]static void packet_input(void)[/align]
[align=left]{[/align]
[align=left] NETSTACK_MAC.input();[/align]
[align=left]}[/align]
提交给mac层继续处理。进入函数nullmac_driver.input(),即core\net\mac
下的 nullmac.c 中的packet_input。
[align=left]static void packet_input(void)[/align]
[align=left]{[/align]
[align=left] NETSTACK_NETWORK.input();[/align]
[align=left]}[/align]
提交给网络层进行处理。进入函数uip_driver.input(),
即platform/esb/net/uip_dirver.c
中的 input函数。
[align=left][/align]
[align=left]static void input(void)[/align]
[align=left]{[/align]
[align=left] if(packetbuf_datalen() > 0 && packetbuf_datalen() <= UIP_BUFSIZE - UIP_LLH_LEN) {[/align]
[align=left] memcpy(&uip_buf[UIP_LLH_LEN], packetbuf_dataptr(), packetbuf_datalen());[/align]
[align=left] uip_len = hc_inflate(&uip_buf[UIP_LLH_LEN], packetbuf_datalen());[/align]
[align=left] tcpip_input();[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]Void tcpip_input(void)[/align]
[align=left]{[/align]
[align=left] process_post_synch(&tcpip_process, PACKET_INPUT, NULL);[/align]
[align=left]}[/align]
Tcpip_input 向进程tcpip_process
传递消息PACKET_INPUT。(下面三个函数均位于/core/net/tcpip.c)
[align=left]PROCESS_THREAD(tcpip_process, ev, data)[/align]
[align=left]{[/align]
[align=left] PROCESS_BEGIN();[/align]
[align=left] tcpip_event = process_alloc_event();[/align]
[align=left] while(1) {[/align]
[align=left] PROCESS_YIELD();[/align]
[align=left] eventhandler(ev, data);[/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]/*---------------------------------------------------------------------------*/[/align]
[align=left]static void[/align]
[align=left]eventhandler(process_event_t ev, process_data_t data)[/align]
[align=left]{[/align]
[align=left] switch(ev) {[/align]
[align=left] case PROCESS_EVENT_EXITED: …[/align]
[align=left] case PROCESS_EVENT_TIMER: ….[/align]
[align=left] case TCP_POLL: …[/align]
[align=left] case UDP_POLL: ...[/align]
[align=left] case PACKET_INPUT:[/align]
[align=left] packet_input();[/align]
[align=left] break;[/align]
[align=left] };[/align]
[align=left]}[/align]
[align=left]static void[/align]
[align=left]packet_input(void)[/align]
[align=left]{[/align]
[align=left] if(uip_len > 0) {[/align]
[align=left] tcpip_is_forwarding = 1;[/align]
[align=left] if(uip_fw_forward() == UIP_FW_LOCAL) { // 这里执行路由和转发[/align]
[align=left] tcpip_is_forwarding = 0;[/align]
[align=left] check_for_tcp_syn();[/align]
[align=left] uip_input();[/align]
[align=left] if(uip_len > 0) {[/align]
[align=left] tcpip_output();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] tcpip_is_forwarding = 0;[/align]
[align=left] }[/align]
[align=left]}[/align]
到uip_input,至此数据成功的转交到UIP协议栈进行处理。在uip_porcess
中会把数据包分发到不同的应用程序中。
[align=left]Uip_process中会对网络层以及传输层的包头进行分析,并提交给应用程序。[/align]
[align=left]至此,数据的接收流程结束。[/align]
------------------------------- 数据包发送过程 ----------------------------------------------------------
二、
发包流程
下面讨论发送数据包的流程。发数据包的过程相对复杂。用到了回调机制。其过程可以分为:产生完整的数据包
和 发送数据包
两部分。下面分别说明。
以doc/example-program.c
为例
[align=left]PROCESS_THREAD(example_program_process, ev, data)[/align]
[align=left]{[/align]
[align=left] static struct uip_udp_conn *c; [/align]
[align=left] PROCESS_BEGIN();[/align]
c = udp_broadcast_new(UIP_HTONS(4321), NULL); ------建立一个udp连接
[align=left] while(1) {[/align]
etimer_set(&timer, CLOCK_SECOND); ---
设置定时器
[align=left] PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); -----等待定时器到时[/align]
tcpip_poll_udp(c);
[align=left] PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);[/align]
[align=left] uip_send("Hello", 5); - [/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]该函数执行的事情是:周期性的广播发送hello。[/align]
下面从tcpip_poll_udp(c)
开始
[align=left]Void tcpip_poll_udp(struct uip_udp_conn *conn)[/align]
[align=left]{[/align]
process_post(&tcpip_process, UDP_POLL, conn); //
给tcpip_process 传递消息 UDP_POLL
[align=left]}[/align]
前面在收包时,我们已经看到过tcpip_process。当tcpip_process
收到消息后,进行的处理如下:
[align=left]static void eventhandler(process_event_t ev, process_data_t data) // core/net/tcpip.c[/align]
[align=left]{[/align]
[align=left] switch(ev) {[/align]
[align=left] case PROCESS_EVENT_EXITED:[/align]
[align=left] case PROCESS_EVENT_TIMER:[/align]
[align=left] case TCP_POLL:[/align]
[align=left] case UDP_POLL:[/align]
[align=left] if(data != NULL) {[/align]
uip_udp_periodic_conn(data); //
产生数据
[align=left] if(uip_len > 0) {[/align]
tcpip_output(); //
发送
[align=left] }[/align]
[align=left] }[/align]
[align=left] break;[/align]
[align=left] };[/align]
[align=left]}[/align]
其中uip_udp_periodic_conn
用于产生数据包,tcpip_output 用于发送。
[align=left]先看uip_udp_periodic_conn:[/align]
[align=left]#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \[/align]
[align=left]uip_process(UIP_UDP_TIMER); } while(0)[/align]
[align=left][/align]
转到uip_process()。
这是uip的核心处理函数。收数据包时已经看到过此函数。
[align=left][/align]
[align=left]void uip_process(u8_t flag)[/align]
[align=left] if(flag == UIP_UDP_TIMER) {[/align]
[align=left] if(uip_udp_conn->lport != 0) {[/align]
[align=left] uip_conn = NULL;[/align]
[align=left] uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];[/align]
[align=left] uip_len = uip_slen = 0;[/align]
[align=left] uip_flags = UIP_POLL;[/align]
UIP_UDP_APPCALL(); /* 产生应用层数据 */
[align=left] goto udp_send;[/align]
[align=left] } else {[/align]
[align=left] goto drop;[/align]
[align=left]}[/align]
[align=left]udp_send:[/align]
[align=left]/* 填充udp的包头*/[/align]
[align=left]goto ip_send_nolen;[/align]
[align=left]ip_send_nolen:[/align]
[align=left]/* 填充ip层包头 , 校验和等*/[/align]
[align=left]Return;[/align]
[align=left] }[/align]
下面看 UIP_UDP_APPCALL
是如何产生数据的:
[align=left]#define UIP_UDP_APPCALL tcpip_uipcall[/align]
[align=left][/align]
[align=left]Void tcpip_uipcall(void)[/align]
[align=left]{[/align]
[align=left] register uip_udp_appstate_t *ts;[/align]
[align=left] ts = &uip_udp_conn->appstate;[/align]
[align=left] if(ts->p != NULL) {[/align]
[align=left] process_post_synch(ts->p, tcpip_event, ts->state);[/align]
[align=left] }[/align]
[align=left]}[/align]
通过process_post_synch(ts->p, tcpip_event, ts->state)
调回到udp连接相关联的进程,即我们最初的进程:example_program_process,向这个进程发送消息: tcpip_event
[align=left]这是我们最初的进程,[/align]
[align=left]PROCESS_THREAD(example_program_process, ev, data)[/align]
[align=left]{[/align]
[align=left] static struct uip_udp_conn *c; [/align]
[align=left] PROCESS_BEGIN();[/align]
c = udp_broadcast_new(UIP_HTONS(4321), NULL); ------建立一个udp连接
[align=left] while(1) {[/align]
etimer_set(&timer, CLOCK_SECOND); ---
设置定时器
[align=left] PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); -----等待定时器到时[/align]
tcpip_poll_udp(c);
PROCESS_WAIT_EVENT_UNTIL(ev ==
tcpip_event);
[align=left] uip_send("Hello", 5); - [/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
这时,example_program_process
将继续执行,调用 uip_send()。
[align=left]Void uip_send(const void *data, int len)[/align]
[align=left]{[/align]
[align=left] memcpy(uip_sappdata, (data), uip_slen);[/align]
[align=left]}[/align]
Uip_send 执行的功能就是把应用层的数据拷贝到
数据包的对应位置,然后返回。
[align=left]至此,网络层的数据包就已经完全生成了。[/align]
下面看发包函数tcpip_output
(/core/net/tcpip.c)
[align=left]u8_t tcpip_output(void)[/align]
[align=left]{[/align]
[align=left] if(outputfunc != NULL) {[/align]
[align=left] return outputfunc();[/align]
[align=left] }[/align]
[align=left] UIP_LOG("tcpip_output: Use tcpip_set_outputfunc() to set an output function");[/align]
[align=left] return 0;[/align]
[align=left]}[/align]
[align=left]下面转到outputfunc()。在main函数中启动了进程 uip_fw_procss。[/align]
[align=left]PROCESS_THREAD(uip_fw_process, ev, data) // /core/net/uip_fw_drv.c[/align]
[align=left]{[/align]
[align=left] PROCESS_BEGIN();[/align]
[align=left] tcpip_set_outputfunc(uip_fw_output);[/align]
[align=left] PROCESS_WAIT_UNTIL(ev == PROCESS_EVENT_EXIT);[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]即outputfunc = uip_fw_output。[/align]
[align=left]下面进入 uip_fw_output。[/align]
[align=left]u8_t uip_fw_output(void)[/align]
[align=left]{[/align]
[align=left] struct uip_fw_netif *netif;[/align]
[align=left] if(uip_len == 0) {[/align]
[align=left] return UIP_FW_ZEROLEN;[/align]
[align=left] } [/align]
[align=left] netif = find_netif();[/align]
[align=left] if(netif == NULL) {[/align]
[align=left] return UIP_FW_NOROUTE;[/align]
[align=left] }[/align]
[align=left] return netif->output();[/align]
[align=left]}[/align]
该函数中先调用find_netif()
通过查路由表找到合适的网卡,然后调用该网卡的output函数。
[align=left]前面提到的,我们的网卡在最开始就定义过:[/align]
[align=left]static struct uip_fw_netif tr1001if =[/align]
[align=left] {UIP_FW_NETIF(0,0,0,0, 0,0,0,0, uip_driver_send)};[/align]
所以,假设找到的网卡就是tr1001if,那么接下来就要调用uip_driver_send
函数。
[align=left][/align]
[align=left]uint8_t uip_driver_send(void)[/align]
[align=left]{[/align]
[align=left] uip_len = hc_compress(&uip_buf[UIP_LLH_LEN], uip_len);[/align]
[align=left] packetbuf_copyfrom(&uip_buf[UIP_LLH_LEN], uip_len);[/align]
[align=left] NETSTACK_MAC.send(NULL, NULL);[/align]
[align=left]}[/align]
进入nullmac
的发送函数
[align=left]static void send_packet(mac_callback_t sent, void *ptr)[/align]
[align=left]{[/align]
[align=left] NETSTACK_RDC.send(sent, ptr);[/align]
[align=left]}[/align]
[align=left]进入nullrdc的发送函数[/align]
[align=left]static void send_packet(mac_callback_t sent, void *ptr)[/align]
[align=left]{[/align]
[align=left] int ret;[/align]
[align=left] packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);[/align]
[align=left] switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {[/align]
[align=left] case RADIO_TX_OK:[/align]
[align=left] ret = MAC_TX_OK;[/align]
[align=left] break;[/align]
[align=left] case RADIO_TX_COLLISION:[/align]
[align=left] ret = MAC_TX_COLLISION;[/align]
[align=left] break;[/align]
[align=left] default:[/align]
[align=left] ret = MAC_TX_ERR;[/align]
[align=left] break;[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] mac_call_sent_callback(sent, ptr, ret, 1);[/align]
[align=left]}[/align]
[align=left]进入tr1001_driver的发送函数[/align]
[align=left]Int tr1001_send(const void *packet, unsigned short len)[/align]
[align=left]{[/align]
[align=left]….(复杂,需要认真研究)[/align]
[align=left]}[/align]
[align=left]至此,数据的发送过程结束。 [/align]
[align=left](问题:MAC层头部是在哪里填充的?)[/align]
以ESB为例:CPU为msp430,
射频芯片为Tr1001。相关代码在/platform/esb
以及 /cpu/msp430 ,/core/net中
[align=left]在contiki-conf.h中首先对各层的协议栈进行了定义。[/align]
[align=left]如下:[/align]
[align=left]#define NETSTACK_CONF_RADIO tr1001_driver[/align]
[align=left]#define NETSTACK_CONF_NETWORK uip_driver[/align]
[align=left]#define NETSTACK_CONF_MAC nullmac_driver[/align]
[align=left]#define NETSTACK_CONF_RDC nullrdc_driver[/align]
[align=left][/align]
[align=left]一、 收包流程[/align]
[align=left]下面我们从主函数Contiki-esb-main.c开始,先说数据的接收流程。[/align]
[align=left]首先,定义一块网卡:[/align]
[align=left]static struct uip_fw_netif tr1001if =[/align]
[align=left] {UIP_FW_NETIF(0,0,0,0, 0,0,0,0, uip_driver_send)};[/align]
[align=left]其中uip_driver_send就是这块网卡的发包函数。[/align]
[align=left]在主函数中会进行协议栈的初始化,另外开启几个关于收发数据的进程。[/align]
[align=left]int main(void)[/align]
[align=left]{[/align]
[align=left] msp430_cpu_init();[/align]
[align=left] process_start(&etimer_process, NULL);[/align]
[align=left] netstack_init();[/align]
[align=left] init_uip_net();[/align]
[align=left] autostart_start(autostart_processes);[/align]
[align=left] watchdog_start();[/align]
[align=left] while(1) {[/align]
[align=left] int r;[/align]
[align=left] do {[/align]
[align=left] /* Reset watchdog. */[/align]
[align=left] watchdog_periodic();[/align]
[align=left] r = process_run();[/align]
[align=left] } while(r > 0);[/align]
[align=left] return 0;[/align]
[align=left]}[/align]
其中,init_uip_net()
中启动了两个进程如下:
[align=left]static void init_uip_net(void)[/align]
[align=left]{[/align]
[align=left] process_start(&tcpip_process, NULL);[/align]
[align=left] process_start(&uip_fw_process, NULL);[/align]
[align=left]}[/align]
[align=left]这两个进程我们在以后会用到。[/align]
[align=left][/align]
[align=left]netstack_init()如下:[/align]
[align=left]void netstack_init(void)[/align]
[align=left]{[/align]
[align=left] NETSTACK_RADIO.init();[/align]
[align=left] NETSTACK_RDC.init();[/align]
[align=left] NETSTACK_MAC.init();[/align]
[align=left] NETSTACK_NETWORK.init();[/align]
[align=left]}[/align]
[align=left]即,netstack_init会对各层驱动均进行初始化。[/align]
[align=left]下面,主要说Radio层的驱动初始化:[/align]
[align=left]Int tr1001_init(void)[/align]
[align=left]{[/align]
[align=left] PT_INIT(&rxhandler_pt);[/align]
[align=left] process_start(&tr1001_process, NULL);[/align]
[align=left] return 1;[/align]
[align=left]}[/align]
该初始化过程中启动了 tr1001_process,
如下:
[align=left]PROCESS_THREAD(tr1001_process, ev, data)[/align]
[align=left]{[/align]
[align=left] PROCESS_BEGIN();[/align]
[align=left] while(1) {[/align]
[align=left] PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);[/align]
[align=left] packetbuf_clear();[/align]
len = tr1001_read(packetbuf_dataptr(), PACKETBUF_SIZE); //
读取数据
[align=left] if(len > 0) {[/align]
[align=left] packetbuf_set_datalen(len);[/align]
NETSTACK_RDC.input(); //
向上提交
[align=left] }[/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]当该进程收到事件ev == PROCESS_EVENT_POLL时,就会从射频芯片读数据。[/align]
我们知道,射频芯片每收到一个frame,都会向cpu
发送一个中断,进而CPU将收到的数据读走。下面,看这个PROCESS_EVENT_POLL事件的产生过程。
[align=left]中断注册函数如下:[/align]
[align=left]interrupt (UART0RX_VECTOR)[/align]
[align=left] tr1001_rxhandler(void)[/align]
[align=left]{[/align]
[align=left] ENERGEST_ON(ENERGEST_TYPE_IRQ);[/align]
[align=left] tr1001_default_rxhandler_pt(RXBUF0);[/align]
[align=left] if(tr1001_rxstate == RXSTATE_FULL) {[/align]
[align=left] LPM4_EXIT;[/align]
[align=left] }[/align]
[align=left] ENERGEST_OFF(ENERGEST_TYPE_IRQ);[/align]
[align=left]}[/align]
[align=left][/align]
[align=left]Char tr1001_default_rxhandler_pt(unsigned char incoming_byte))[/align]
[align=left]{[/align]
[align=left] static unsigned char rxtmp, tmppos;[/align]
[align=left] if(rxcrctmp == rxcrc) {[/align]
[align=left] /* A full packet has been received and the CRC checks out. We'll[/align]
[align=left] request the driver to take care of the incoming data. */[/align]
[align=left] RIMESTATS_ADD(llrx);[/align]
[align=left] process_poll(&tr1001_process);[/align]
[align=left] PT_END(&rxhandler_pt);[/align]
[align=left]}[/align]
到这里,radio层的收包过程就结束了。通过 NETSTACK_RDC.input()
将数据提交到rdc层。
进入函数:nullrdc_driver.input(),
即core\net\mac 下的 nullrdc.c
中的packet_input。
[align=left]static void packet_input(void)[/align]
[align=left]{[/align]
[align=left] NETSTACK_MAC.input();[/align]
[align=left]}[/align]
提交给mac层继续处理。进入函数nullmac_driver.input(),即core\net\mac
下的 nullmac.c 中的packet_input。
[align=left]static void packet_input(void)[/align]
[align=left]{[/align]
[align=left] NETSTACK_NETWORK.input();[/align]
[align=left]}[/align]
提交给网络层进行处理。进入函数uip_driver.input(),
即platform/esb/net/uip_dirver.c
中的 input函数。
[align=left][/align]
[align=left]static void input(void)[/align]
[align=left]{[/align]
[align=left] if(packetbuf_datalen() > 0 && packetbuf_datalen() <= UIP_BUFSIZE - UIP_LLH_LEN) {[/align]
[align=left] memcpy(&uip_buf[UIP_LLH_LEN], packetbuf_dataptr(), packetbuf_datalen());[/align]
[align=left] uip_len = hc_inflate(&uip_buf[UIP_LLH_LEN], packetbuf_datalen());[/align]
[align=left] tcpip_input();[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]Void tcpip_input(void)[/align]
[align=left]{[/align]
[align=left] process_post_synch(&tcpip_process, PACKET_INPUT, NULL);[/align]
[align=left]}[/align]
Tcpip_input 向进程tcpip_process
传递消息PACKET_INPUT。(下面三个函数均位于/core/net/tcpip.c)
[align=left]PROCESS_THREAD(tcpip_process, ev, data)[/align]
[align=left]{[/align]
[align=left] PROCESS_BEGIN();[/align]
[align=left] tcpip_event = process_alloc_event();[/align]
[align=left] while(1) {[/align]
[align=left] PROCESS_YIELD();[/align]
[align=left] eventhandler(ev, data);[/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]/*---------------------------------------------------------------------------*/[/align]
[align=left]static void[/align]
[align=left]eventhandler(process_event_t ev, process_data_t data)[/align]
[align=left]{[/align]
[align=left] switch(ev) {[/align]
[align=left] case PROCESS_EVENT_EXITED: …[/align]
[align=left] case PROCESS_EVENT_TIMER: ….[/align]
[align=left] case TCP_POLL: …[/align]
[align=left] case UDP_POLL: ...[/align]
[align=left] case PACKET_INPUT:[/align]
[align=left] packet_input();[/align]
[align=left] break;[/align]
[align=left] };[/align]
[align=left]}[/align]
[align=left]static void[/align]
[align=left]packet_input(void)[/align]
[align=left]{[/align]
[align=left] if(uip_len > 0) {[/align]
[align=left] tcpip_is_forwarding = 1;[/align]
[align=left] if(uip_fw_forward() == UIP_FW_LOCAL) { // 这里执行路由和转发[/align]
[align=left] tcpip_is_forwarding = 0;[/align]
[align=left] check_for_tcp_syn();[/align]
[align=left] uip_input();[/align]
[align=left] if(uip_len > 0) {[/align]
[align=left] tcpip_output();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] tcpip_is_forwarding = 0;[/align]
[align=left] }[/align]
[align=left]}[/align]
到uip_input,至此数据成功的转交到UIP协议栈进行处理。在uip_porcess
中会把数据包分发到不同的应用程序中。
[align=left]Uip_process中会对网络层以及传输层的包头进行分析,并提交给应用程序。[/align]
[align=left]至此,数据的接收流程结束。[/align]
------------------------------- 数据包发送过程 ----------------------------------------------------------
二、
发包流程
下面讨论发送数据包的流程。发数据包的过程相对复杂。用到了回调机制。其过程可以分为:产生完整的数据包
和 发送数据包
两部分。下面分别说明。
以doc/example-program.c
为例
[align=left]PROCESS_THREAD(example_program_process, ev, data)[/align]
[align=left]{[/align]
[align=left] static struct uip_udp_conn *c; [/align]
[align=left] PROCESS_BEGIN();[/align]
c = udp_broadcast_new(UIP_HTONS(4321), NULL); ------建立一个udp连接
[align=left] while(1) {[/align]
etimer_set(&timer, CLOCK_SECOND); ---
设置定时器
[align=left] PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); -----等待定时器到时[/align]
tcpip_poll_udp(c);
[align=left] PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);[/align]
[align=left] uip_send("Hello", 5); - [/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]该函数执行的事情是:周期性的广播发送hello。[/align]
下面从tcpip_poll_udp(c)
开始
[align=left]Void tcpip_poll_udp(struct uip_udp_conn *conn)[/align]
[align=left]{[/align]
process_post(&tcpip_process, UDP_POLL, conn); //
给tcpip_process 传递消息 UDP_POLL
[align=left]}[/align]
前面在收包时,我们已经看到过tcpip_process。当tcpip_process
收到消息后,进行的处理如下:
[align=left]static void eventhandler(process_event_t ev, process_data_t data) // core/net/tcpip.c[/align]
[align=left]{[/align]
[align=left] switch(ev) {[/align]
[align=left] case PROCESS_EVENT_EXITED:[/align]
[align=left] case PROCESS_EVENT_TIMER:[/align]
[align=left] case TCP_POLL:[/align]
[align=left] case UDP_POLL:[/align]
[align=left] if(data != NULL) {[/align]
uip_udp_periodic_conn(data); //
产生数据
[align=left] if(uip_len > 0) {[/align]
tcpip_output(); //
发送
[align=left] }[/align]
[align=left] }[/align]
[align=left] break;[/align]
[align=left] };[/align]
[align=left]}[/align]
其中uip_udp_periodic_conn
用于产生数据包,tcpip_output 用于发送。
[align=left]先看uip_udp_periodic_conn:[/align]
[align=left]#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \[/align]
[align=left]uip_process(UIP_UDP_TIMER); } while(0)[/align]
[align=left][/align]
转到uip_process()。
这是uip的核心处理函数。收数据包时已经看到过此函数。
[align=left][/align]
[align=left]void uip_process(u8_t flag)[/align]
[align=left] if(flag == UIP_UDP_TIMER) {[/align]
[align=left] if(uip_udp_conn->lport != 0) {[/align]
[align=left] uip_conn = NULL;[/align]
[align=left] uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];[/align]
[align=left] uip_len = uip_slen = 0;[/align]
[align=left] uip_flags = UIP_POLL;[/align]
UIP_UDP_APPCALL(); /* 产生应用层数据 */
[align=left] goto udp_send;[/align]
[align=left] } else {[/align]
[align=left] goto drop;[/align]
[align=left]}[/align]
[align=left]udp_send:[/align]
[align=left]/* 填充udp的包头*/[/align]
[align=left]goto ip_send_nolen;[/align]
[align=left]ip_send_nolen:[/align]
[align=left]/* 填充ip层包头 , 校验和等*/[/align]
[align=left]Return;[/align]
[align=left] }[/align]
下面看 UIP_UDP_APPCALL
是如何产生数据的:
[align=left]#define UIP_UDP_APPCALL tcpip_uipcall[/align]
[align=left][/align]
[align=left]Void tcpip_uipcall(void)[/align]
[align=left]{[/align]
[align=left] register uip_udp_appstate_t *ts;[/align]
[align=left] ts = &uip_udp_conn->appstate;[/align]
[align=left] if(ts->p != NULL) {[/align]
[align=left] process_post_synch(ts->p, tcpip_event, ts->state);[/align]
[align=left] }[/align]
[align=left]}[/align]
通过process_post_synch(ts->p, tcpip_event, ts->state)
调回到udp连接相关联的进程,即我们最初的进程:example_program_process,向这个进程发送消息: tcpip_event
[align=left]这是我们最初的进程,[/align]
[align=left]PROCESS_THREAD(example_program_process, ev, data)[/align]
[align=left]{[/align]
[align=left] static struct uip_udp_conn *c; [/align]
[align=left] PROCESS_BEGIN();[/align]
c = udp_broadcast_new(UIP_HTONS(4321), NULL); ------建立一个udp连接
[align=left] while(1) {[/align]
etimer_set(&timer, CLOCK_SECOND); ---
设置定时器
[align=left] PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); -----等待定时器到时[/align]
tcpip_poll_udp(c);
PROCESS_WAIT_EVENT_UNTIL(ev ==
tcpip_event);
[align=left] uip_send("Hello", 5); - [/align]
[align=left] }[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
这时,example_program_process
将继续执行,调用 uip_send()。
[align=left]Void uip_send(const void *data, int len)[/align]
[align=left]{[/align]
[align=left] memcpy(uip_sappdata, (data), uip_slen);[/align]
[align=left]}[/align]
Uip_send 执行的功能就是把应用层的数据拷贝到
数据包的对应位置,然后返回。
[align=left]至此,网络层的数据包就已经完全生成了。[/align]
下面看发包函数tcpip_output
(/core/net/tcpip.c)
[align=left]u8_t tcpip_output(void)[/align]
[align=left]{[/align]
[align=left] if(outputfunc != NULL) {[/align]
[align=left] return outputfunc();[/align]
[align=left] }[/align]
[align=left] UIP_LOG("tcpip_output: Use tcpip_set_outputfunc() to set an output function");[/align]
[align=left] return 0;[/align]
[align=left]}[/align]
[align=left]下面转到outputfunc()。在main函数中启动了进程 uip_fw_procss。[/align]
[align=left]PROCESS_THREAD(uip_fw_process, ev, data) // /core/net/uip_fw_drv.c[/align]
[align=left]{[/align]
[align=left] PROCESS_BEGIN();[/align]
[align=left] tcpip_set_outputfunc(uip_fw_output);[/align]
[align=left] PROCESS_WAIT_UNTIL(ev == PROCESS_EVENT_EXIT);[/align]
[align=left] PROCESS_END();[/align]
[align=left]}[/align]
[align=left]即outputfunc = uip_fw_output。[/align]
[align=left]下面进入 uip_fw_output。[/align]
[align=left]u8_t uip_fw_output(void)[/align]
[align=left]{[/align]
[align=left] struct uip_fw_netif *netif;[/align]
[align=left] if(uip_len == 0) {[/align]
[align=left] return UIP_FW_ZEROLEN;[/align]
[align=left] } [/align]
[align=left] netif = find_netif();[/align]
[align=left] if(netif == NULL) {[/align]
[align=left] return UIP_FW_NOROUTE;[/align]
[align=left] }[/align]
[align=left] return netif->output();[/align]
[align=left]}[/align]
该函数中先调用find_netif()
通过查路由表找到合适的网卡,然后调用该网卡的output函数。
[align=left]前面提到的,我们的网卡在最开始就定义过:[/align]
[align=left]static struct uip_fw_netif tr1001if =[/align]
[align=left] {UIP_FW_NETIF(0,0,0,0, 0,0,0,0, uip_driver_send)};[/align]
所以,假设找到的网卡就是tr1001if,那么接下来就要调用uip_driver_send
函数。
[align=left][/align]
[align=left]uint8_t uip_driver_send(void)[/align]
[align=left]{[/align]
[align=left] uip_len = hc_compress(&uip_buf[UIP_LLH_LEN], uip_len);[/align]
[align=left] packetbuf_copyfrom(&uip_buf[UIP_LLH_LEN], uip_len);[/align]
[align=left] NETSTACK_MAC.send(NULL, NULL);[/align]
[align=left]}[/align]
进入nullmac
的发送函数
[align=left]static void send_packet(mac_callback_t sent, void *ptr)[/align]
[align=left]{[/align]
[align=left] NETSTACK_RDC.send(sent, ptr);[/align]
[align=left]}[/align]
[align=left]进入nullrdc的发送函数[/align]
[align=left]static void send_packet(mac_callback_t sent, void *ptr)[/align]
[align=left]{[/align]
[align=left] int ret;[/align]
[align=left] packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);[/align]
[align=left] switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {[/align]
[align=left] case RADIO_TX_OK:[/align]
[align=left] ret = MAC_TX_OK;[/align]
[align=left] break;[/align]
[align=left] case RADIO_TX_COLLISION:[/align]
[align=left] ret = MAC_TX_COLLISION;[/align]
[align=left] break;[/align]
[align=left] default:[/align]
[align=left] ret = MAC_TX_ERR;[/align]
[align=left] break;[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] mac_call_sent_callback(sent, ptr, ret, 1);[/align]
[align=left]}[/align]
[align=left]进入tr1001_driver的发送函数[/align]
[align=left]Int tr1001_send(const void *packet, unsigned short len)[/align]
[align=left]{[/align]
[align=left]….(复杂,需要认真研究)[/align]
[align=left]}[/align]
[align=left]至此,数据的发送过程结束。 [/align]
[align=left](问题:MAC层头部是在哪里填充的?)[/align]
相关文章推荐
- JAVA - 垃圾回收算法
- hdu 1000 A + B Problem(Java)
- Eclipse使用--奇淫技巧
- iptables的state模块的4种封包链接状态
- hdu2814(斐波那契,费马小定理,快速幂)
- hdu 5014__Number Sequence
- webview和js的交互
- 0909 谈谈我对操作系统的理解
- leetcode面试准备:Valid Anagram
- POJ 3133 Manhattan Wiring (插头DP,轮廓线,经典)
- Redis学习手册(List数据类型)(转)
- Android 数据存储5种方式
- C++ 数组
- 2016华为机试题目:好友推荐
- 指针的初始化
- 怎么判断一个ResultSet为空 ,有没有内容
- toString的经典实现
- UVa 1343:The Rotation Game(IDA*)
- centos 下面安装lamp
- 系统组件:警告对话框AlertDialog(1)