uip源码分析(2)

2019-07-27 10:17

memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);

这里四个memset,重复的源和目的以太网地址一起设置了,四个memset对应图片中的1,10,2,8项.但是:对1和10两项,都是源以太网地址,但置的值是不同的,分别为0xff*6和0x00*6.为什么会这样呢?因为他们的用处不一样,见:【相关资料】ARP分组格式(帧格式,报文格式) 6+6– 以太网的源地址和目的地址,目的地址为全1的为广播地址

注意这里说,目的地址为全为1的广播地址.什么意思?当你发送一个ARP请求是,你是想知道一个IP对应的以太网地址(即MAC地址),但是你现在不知道目的主机的以太网地址,你问谁啊?不知道问谁,这种情况下,只能是广播一下了,0xff*6就是广播地址.

从图片中可以看到,ARP包是分成两部分的,前6+6+2叫做\以太网首部\它的意义就是\分组是从谁(源地址)发给谁(目的地址)的什么类型(帧类型,请求和应答为0x0806)\第二部分则是内容.

来看这个例子:

请求帧如下(为了清晰在每行的前面加了字节计数,每行16个字节): 以太网首部(14字节)

0000: ff ff ff ff ff ff 00 05 5d 61 58 a8 08 06 ARP帧(28字节)

0000: 00 01 0010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 37 0020: 00 00 00 00 00 00 c0 a8 00 02 填充位(18字节)

0020: 00 77 31 d2 50 10 0030: fd 78 41 d3 00 00 00 00 00 00 00 00

以太网首部:

目的主机采用广播地址,源主机的MAC地址是00:05:5d:61:58:a8,上层协议类型0x0806表示ARP。 ARP帧:

硬件类型0x0001表示以太网, 协议类型0x0800表示IP协议, 硬件地址(MAC地址)长度为6, 协议地址(IP地址)长度为4,

op为0x0001表示请求目的主机的MAC地址, 源主机MAC地址为00:05:5d:61:58:a8,源主机IP地址为c0 a8 00 37(192.168.0.55), 目的主机MAC地址全0待填写,目的主机IP地址为c0 a8 00 02(192.168.0.2)。 由于以太网规定最小数据长度为46字节,ARP帧长度只有28字节,因此有18字节填充位,填充位的内容没有定义,与具体实现相关。

uIP的ARP协议代码分析之二 ARP应答

如果读懂了上面的文章,这里的理解就相对容易了.

ARP应答部分代码为uip_arp.c中的void uip_arp_arpin(void)函数. 这个函数是在设备接收到ARP包时,由驱动程序调用的.

如果收到是ARP包是一个对本地主机上次发送的ARP请求的应答,那么就从包中取得自己想要的主机的MAC地址,加入自己的ARP缓存表中.

如果收到是一个ARP请求,那就把自己的MAC地址打包成一个ARP应答,发送给请求的主机. 看代码uip_arp.c的254行:

1. /*-----------------------------------------------------------------------------------*/ 2. /**

3. * ARP processing for incoming ARP packets. 4. *对传入的ARP包的处理.

5. * This function should be called by the device driver when an ARP 6. * packet has been received. The function will act differently 7. * depending on the ARP packet type: if it is a reply for a request 8. * that we previously sent out, the ARP cache will be filled in with 9. * the values from the ARP reply. If the incoming ARP packet is an ARP 10. * request for our IP address, an ARP reply packet is created and put 11. * into the uip_buf[] buffer.

12. *此函数在收到ARP包时由设备驱动调用,函数行为会因包类型而有不同.如果收到的是一个对前先发送

的请求的应答

13. *则根据应答的值填充缓存.如果传入的包是对我们的IP的请求,则创建一个ARP应答,并放入uip_buf[]

中.

14. * When the function returns, the value of the global variable uip_len 15. * indicates whether the device driver should send out a packet or 16. * not. If uip_len is zero, no packet should be sent. If uip_len is 17. * non-zero, it contains the length of the outbound packet that is 18. * present in the uip_buf[] buffer.

19. *函数返回时,全局变量uip_len的值指明了设备驱动要不要发送包.若uip_len为0,则不需发送,若

uip_len不是0,

20. * 则其值是uip_buf[]中包含的要传出的包的大小.

21. * This function expects an ARP packet with a prepended Ethernet 22. * header in the uip_buf[] buffer, and the length of the packet in the

23. * global variable uip_len.此函数预期中的uip_buf中有一个带以太网头的ARP包.其长度存为

uip_len中. 24. */

25. /*-----------------------------------------------------------------------------------*/ 26. void

27. uip_arp_arpin(void) 28. { 29.

30. if(uip_len < sizeof(struct arp_hdr)) { 31. uip_len = 0; 32. return; 33. }

34. uip_len = 0; 35.

36. switch(BUF->opcode) { 37. case HTONS(ARP_REQUEST):

38. /* ARP request. If it asked for our address, we send out a

39. reply. 如果是一个ARP请求,则发送应答.*/

40. if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {

41. /* First, we register the one who made the request in our ARP 42. table, since it is likely that we will do more communication

43. with this host in the future.首先,我们将发送请求的主机注册到ARP缓存表中,因为我们很可能要

跟它要有更多的交流 */

44. uip_arp_update(BUF->sipaddr, &BUF->shwaddr); 45.

46. /* The reply opcode is 2. 应答的操作码为2*/ 47. BUF->opcode = HTONS(2); 48.

49. memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); 50. memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); 51. memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); 52. memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); 53.

54. BUF->dipaddr[0] = BUF->sipaddr[0]; 55. BUF->dipaddr[1] = BUF->sipaddr[1]; 56. BUF->sipaddr[0] = uip_hostaddr[0]; 57. BUF->sipaddr[1] = uip_hostaddr[1]; 58.

59. BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); 60. uip_len = sizeof(struct arp_hdr); 61. } 62. break;

63. case HTONS(ARP_REPLY):

64. /* ARP reply. We insert or update the ARP table if it was meant

65. for us. 如果收到的是一个ARP应答,而且也是我们所要的应答的话,就插件并更新ARP缓存表*/ 66. if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { 67. uip_arp_update(BUF->sipaddr, &BUF->shwaddr); 68. } 69. break; 70. } 71. 72. return; 73. }

复制代码

这里有一件事是很有意思的,就是说如果某个主机请求得到我们的MAC的地址,我们先把它的MAC地址加入到自己的表中.就好比社交网络中,别人请求加我们为好友,如果我们接收的话,也自动加对方为好友一样.既然对方找上我们了,肯定是要做进一步的交流,互加MAC地址也很自然的.

有了上一篇文章,这里似乎不必做过多的解释了.但还是说一下吧,看看我们怎么做应答的. 如果收到了一个请求,我们要做应答:

1. /* The reply opcode is 2. */ 2. BUF->opcode = HTONS(2); 3.

4. memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); 5. memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); 6. memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); 7. memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); 8.

9. BUF->dipaddr[0] = BUF->sipaddr[0]; 10. BUF->dipaddr[1] = BUF->sipaddr[1]; 11. BUF->sipaddr[0] = uip_hostaddr[0]; 12. BUF->sipaddr[1] = uip_hostaddr[1]; 13.

14. BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); 15. uip_len = sizeof(struct arp_hdr);

复制代码

由于请求和应答包很多地方是相同的,如上文中的绿色部分.我们只需将收到的请求稍加修改就可以发送回去了. 首先,要改一下MAC地址,四个地方.然后要将目标主机IP设为设为请求包的源主机IP,目的主机IP设为我们的IP.就可以了.

另外说下对ARP缓存表的设置:

1. 这个函数是集插入,更新一体的,有两个参数,IP地址,MAC地址. 2. static void

3. uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr) 4. {

5. register struct arp_entry *tabptr;

6. /* Walk through the ARP mapping table and try to find an entry to 7. update. If none is found, the IP -> MAC address mapping is

8. inserted in the ARP table. 遍历ARP映射表,看看有没有需要更新的表项,如果没有,就将新的表项

插入.*/

9. for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { 10.

11. tabptr = &arp_table[i];

12. /* Only check those entries that are actually in use. 所谓更新就是传入参数IP在表中己经存

在了,这时不需要新建表项,而是要修改己存表项.只查使用中的表项,如果有些表项IP是0,那么就不是使用中的*/

13. if(tabptr->ipaddr[0] != 0 && 14. tabptr->ipaddr[1] != 0) { 15.

16. /* Check if the source IP address of the incoming packet matches 17. the IP address in this ARP table entry. 看看传入的IP有没有匹配项.*/ 18. if(ipaddr[0] == tabptr->ipaddr[0] && 19. ipaddr[1] == tabptr->ipaddr[1]) {

20.

21. /* An old entry found, update this and return. 如果有己存的匹配项,修改该项的MAC地址和更

新时间.*/

22. memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); 23. tabptr->time = arptime; 24. 25. return; 26. } 27. } 28. } 29.

30. /* If we get here, no existing ARP table entry was found, so we 31. create one. 如果运行到这里,说明没有己存的表项,则创建一个.*/ 32.

33. /* First, we try to find an unused entry in the ARP table. 先看看有没有空表项可用.*/ 34. for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { 35. tabptr = &arp_table[i]; 36. if(tabptr->ipaddr[0] == 0 && 37. tabptr->ipaddr[1] == 0) { 38. break; 39. } 40. } 41.

42. /* If no unused entry is found, we try to find the oldest entry and 43. throw it away. 如果没空表项,就找到一个最旧的表项,扔掉它,换成我们的.*/ 44. if(i == UIP_ARPTAB_SIZE) { 45. tmpage = 0; 46. c = 0;

47. for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { 48. tabptr = &arp_table[i];

49. if(arptime - tabptr->time > tmpage) { 50. tmpage = arptime - tabptr->time; 51. c = i; 52. } 53. } 54. i = c;

55. tabptr = &arp_table[i]; 56. }

57. /* Now, i is the ARP table entry which we will fill with the new 58. information. 现在i就是我们最终得到的表项,我们把新的信息插入到这里.*/ 59. memcpy(tabptr->ipaddr, ipaddr, 4);

60. memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); 61. tabptr->time = arptime;

复制代码


uip源码分析(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:公开课 价值与价值观 教案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: