uip协议分析

IP协议多用于嵌入式产品。
     结合如CP2200芯片的网卡芯片,组成嵌入式网卡,硬件提供能力,UIP提供的是策略。
     由上往下逐步封装用户的数据,如:
     应用层----------传输层--------网络层------数据链路层-----物理层
     应用数据---TCP封装头部---IP封装头部-----mac封装+尾部-----发送 
    任何的事物需要经过一定的初始阶段,在UIP协议里面通过uip_init()来初始化。
    在uip_init()函数里面主要工作是:
     1. 将uip_state结构体全部清零。
     2. 初始化用于TCP链接的uip_conn结构体,将连接状态置为close。
     3. 设置用于TCP链接的端口lastport = 4096; 应该是最大的端口号,待查证。
     4. 如果定义了UDP,同样进行初始化。
  1. void uip_init(void) {
  2.     // clean statistics
  3.     char* ptr= (char*) &uip_stat;
  4.     for (int i = 0; i<sizeof (uip_stat); i++) {
  5.         ptr[i] = 0;   
  6.     }

  7.     for (= 0; c < UIP_LISTENPORTS; ++c) {
  8.         uip_listenports[c] = 0;
  9.     }
  10.     for (= 0; c < UIP_CONNS; ++c) {
  11.         uip_conns[c].tcpstateflags = UIP_CLOSED;
  12.     }
  13.     lastport = 4096;

  14. #if UIP_UDP
  15.     for (= 0; c < UIP_UDP_CONNS; ++c) {
  16.         uip_udp_conns[c].lport = 0;
  17.     }
  18. #endif /* UIP_UDP */


  19.     /* IPv4 initialization. */
  20. #if UIP_FIXEDADDR == 0
  21.     /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
  22. #endif /* UIP_FIXEDADDR */

  23. }
   同样,我在ourdev.cn上下载了,一份总结,一点一点上传,感谢ourdev.cn。
   uip_arp_init(); arp协议的初始化,其中进行的是构造arp协议的缓存。
   在配置UIP协议的时候要主要配置超时。
   // 摘自uip协议包main.c
  1. struct timer periodic_timer, arp_timer;
  2. timer_set(&periodic_timer, CLOCK_SECOND / 2);
  3. timer_set(&arp_timer, CLOCK_SECOND * 10);
   还要进行的配置是,比如配置主机地址,ip地址,还有掩码,以太网mac地址等信息,或者配置dhcp。
   这些配置完成之后,进入协议的主循环,接受,和发送等等的过程了。
   要应用到实际的使用中,还需要结合硬件,比如CP2200芯片,使用过程中,需要有接收,和发送函
   数,这个需要自己实现,循环的流程如下:
  
  1. while(1)
  2.  {
  3.     uip_len = tapdev_read();  // 接收的函数
  4.     if(uip_len > 0)
  5.     {
  6.       if(BUF->type == htons(UIP_ETHTYPE_IP))
  7.       {
  8.           uip_arp_ipin();
  9.           uip_input();  // 这个是实际的从上往下封装包的函数
  10.          /* If the above function invocation resulted in data that
  11.           should be sent out on the network, the global variable
  12.            uip_len is set to a value > 0. */
  13.           if(uip_len > 0)
  14.           {
  15.               uip_arp_out();
  16.               tapdev_send(); // 发送的实际函数 
  17.           }
  18.       } 
  19.       else if(BUF->type == htons(UIP_ETHTYPE_ARP))
  20.       {
  21.           uip_arp_arpin();
  22.           /* If the above function invocation resulted in data that
  23.           should be sent out on the network, the global variable
  24.           uip_len is set to a value > 0. */
  25.           if(uip_len > 0) 
  26.           {
  27.            tapdev_send();
  28.           }
  29.       }

  30.     } 
  31.     else if(timer_expired(&periodic_timer))
  32.      {
  33.          timer_reset(&periodic_timer);
  34.          for(= 0; i < UIP_CONNS; i++)
  35.          {
  36.              uip_periodic(i);
  37.              /* If the above function invocation resulted in data that
  38.              should be sent out on the network, the global variable
  39.              uip_len is set to a value > 0. */
  40.              if(uip_len > 0)
  41.              {
  42.                  uip_arp_out();
  43.                  tapdev_send();
  44.              }
  45.         }

  46. #if UIP_UDP
  47.       for(= 0; i < UIP_UDP_CONNS; i++)
  48.        {
  49.            uip_udp_periodic(i);
  50.            /* If the above function invocation resulted in data that
  51.             should be sent out on the network, the global variable
  52.              uip_len is set to a value > 0. */
  53.            if(uip_len > 0)
  54.             {
  55.                 uip_arp_out();
  56.                 tapdev_send();
  57.            }
  58.       }
  59. #endif /* UIP_UDP */

  60.       /* Call the ARP timer function every 10 seconds. */
  61.       if(timer_expired(&arp_timer))
  62.        {
  63.            timer_reset(&arp_timer);
  64.            uip_arp_timer();
  65.       }
  66.     }
  67.   }
1. 网卡如何与uIP协议交互(包括arp, icmp等)
   在我看来,CP2200提供了读取网络数据的能力,而UIP提供的是一种如何封装网路数据的策略。对用户数
据不断封装,最后交给CP2200发送,在UIP协议中有一个uip_buf缓冲用来接收和发送数据。

(转自:维库电子开发网>子通列表 > 协议栈)

   ARP请求和应答
在UIP协议中定义了一个ARP的struct。维护了一张
缓存表。
  1. struct arp_entry {
  2. u16_t ipaddr[2];  // 保存的是IP地址
  3. struct uip_eth_addr ethaddr; // 保存的是mac地址
  4. u8_t time;       // 缓存更新时间
  5. };
     ARP请求发送函数:void uip_arp_out(void)
* 为传出的IP包添加以太网头并看是否需要发送ARP请求. 
* 此函数应该在发送IP包时调用,它会检查IP包的目的IP地址,看看以太网应该使用什么目的MAC地址.
* 如果目的IP地址是在局域网中(由IP地址与子网掩码的与逻辑决定),函数就会从ARP缓存表中查找有
* 无对应项.若有,就取对应的MAC地址,加上以太网头,并返回,否则uip_buf[]中的数据包会被替换成一个
* 目的IP在址的ARP请求.原来的IP包会被简单的仍掉,此函数假设高层协议(如TCP)会最终重传扔掉的包.
* 如果目标IP地址并非一个局域网IP,则会使用默认路由的IP地址.
* uip_len.函数返回时,uip_buf[]中已经有了一个包,其长度由uip_len指定.
  1. void uip_arp_out(void)
  2. {
  3.   struct arp_entry *tabptr=0;
  4.   // 在ARP表中找到目的IP地址,构成以太网头.如果目的IP地址不在局域网中,则使用默认路由的IP.
  5.   // 如果ARP表中找不到,则将原来的IP包替换成一个ARP请求.  
  6.   // 首先检查目标是不是广播
  7.   if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr))
  8.   {
  9.     memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
  10.   } 
  11.   else 
  12.   {
  13.         /* 检查目标地址是否在局域网内 */
  14.         if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask))
  15.         {
  16.               /* 目的地址不在局域网内,所以保用默认路由器的地址来确在MAC地址 */
  17.               uip_ipaddr_copy(ipaddr, uip_draddr);
  18.         } 
  19.         else 
  20.         {
  21.             /* 否则,使用目标IP地址 */
  22.           uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);
  23.         }
  24.         //这里遍历表,对比目的IP与ARP缓存表中的IP.
  25.         for(= 0; i < UIP_ARPTAB_SIZE; ++i)
  26.         {
  27.              tabptr = &arp_table[i];
  28.              if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr))
  29.              {
  30.                  break;
  31.              }
  32.          }
  33.          
  34.          if(== UIP_ARPTAB_SIZE)
  35.          {
  36.             /* 如果遍历到头没找到,将原IP包替换为ARP请求并返回 */
  37.               memset(BUF->ethhdr.dest.addr, 0xff, 6);  // 以太网目的地址
  38.               memset(BUF->dhwaddr.addr, 0x00, 6);      // 目的以太网地址
  39.               memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);  //
  40.               memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);  // 源以太网地址
  41.     
  42.               uip_ipaddr_copy(BUF->dipaddr, ipaddr);  // 目的IP地址
  43.               uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);  // 源IP地址
  44.               BUF->opcode = HTONS(ARP_REQUEST);  // ARP 请求
  45.               BUF->hwtype = HTONS(ARP_HWTYPE_ETH);  // 硬件类型 值为1
  46.               BUF->protocol = HTONS(UIP_ETHTYPE_IP); // 协议类型 值为0x8000表示IP地址
  47.               BUF->hwlen = 6;  
  48.               BUF->protolen = 4
  49.               BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);  

  50.               uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
  51.               uip_len = sizeof(struct arp_hdr);
  52.               return;
  53.           }

  54.         // 如果是在局域网中,且在ARP缓存中找到了(如果没找到进行不到这一步,在上面就返回了),则构建以太网头
  55.          memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
  56.   }
  57.   memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
  58.   IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
  59.   uip_len += sizeof(struct uip_eth_hdr);
  60. }
网卡如何与UIP协议交互(包括arp, icmp等)  接上文
    接下来看看UIP如何处理ARP应答的情况,在主循环中一段代码:
  1. else if(BUF->type == htons(UIP_ETHTYPE_ARP)) 
  2. {   
  3.     uip_arp_arpin();  // 处理ARP应答
  4.     /* If the above function invocation resulted in data that
  5.        should be sent out on the network, the global variable
  6.        uip_len is set to a value > 0. */
  7.    // 如果上面的函数返回的结果需要发送到网络上,那么uip_len就必须设置 > 0
  8.     if(uip_len > 0) 
  9.     {
  10.         network_device_send(); // 回应ARP包
  11.     }
  12. }

在uip_arp_arpin()函数中主要是处理ARP应答。
    这个函数是在设备接收到ARP包时,由驱动程序调用的.如果收到是ARP包是一个对本地主机上次发送的ARP请求的应答,那么就从包中取得自己想要的主机的MAC地址,加入自己的ARP缓存表中.如果收到是一个ARP请求,那就把自己的MAC地址打包成一个ARP应答,发送给请求的主机.看代码uip_arp.c的254行:
  1. void uip_arp_arpin(void)
  2. {
  3.   if(uip_len < sizeof(struct arp_hdr))
  4.   {
  5.     uip_len = 0;
  6.     return;
  7.   }
  8.   uip_len = 0;
  9.   
  10.   switch(BUF->opcode)  // 操作码
  11.   {
  12.       case HTONS(ARP_REQUEST):
  13.       // 如果是一个ARP请求,则发送应答
  14.       if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr))
  15.       {
  16.           // 首先,我们将发送请求的主机注册到ARP缓存表中,因为我们很
  17.           // 可能要跟它要有更多的交流
  18.           uip_arp_update(BUF->sipaddr, &BUF->shwaddr);  
  19.       
  20.           // 回应的操作码是 2.
  21.           BUF->opcode = HTONS(2);
  22.           // 将收到的ARP包的发送端以太网地址,变为目的以太网地址
  23.           memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
  24.           // 将自己的以太网地址,赋值给ARP包的发送端以太网地址
  25.           memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
  26.           // 对应以太网源地址
  27.           memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
  28.           // 对应以太网目的地址
  29.           memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
  30.       
  31.           BUF->dipaddr[0] = BUF->sipaddr[0];
  32.           BUF->dipaddr[1] = BUF->sipaddr[1];
  33.           BUF->sipaddr[0] = uip_hostaddr[0];
  34.           BUF->sipaddr[1] = uip_hostaddr[1];

  35.           BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
  36.           uip_len = sizeof(struct arp_hdr);
  37.      }
  38.      break;
  39.     // 如果收到的是一个ARP应答,而且也是我们所要的应答的话,就插件
  40.     // 并更新ARP缓存表
  41.     case HTONS(ARP_REPLY):  
  42.     if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr))
  43.     {
  44.       uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
  45.     }
  46.     break;
  47.   }

  48.   return;
  49. }
还有一个是ARP周期处理函数,在主循环中代码如下:
// 每10秒运行一次
if(timer_expired(&arp_timer)) 
{
    timer_reset(&arp_timer); 

    uip_arp_timer();
}
具体的代码:
  1. void uip_arp_timer(void)
  2. {
  3.   struct arp_entry *tabptr;
  4.   ++arptime;    // 这个是个全局变量,结合uip_arp_update来更新缓存表
  5.   for(= 0; i < UIP_ARPTAB_SIZE; ++i)
  6.   {
  7.     tabptr = &arp_table[i];
  8.     // 把超过20分钟都没有更新的项扔掉
  9.     if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
  10.        arptime - tabptr->time >= UIP_ARP_MAXAGE)
  11.     {
  12.       memset(tabptr->ipaddr, 0, 4);
  13.     }
  14.   }
  15. }
下面说说网卡如何与UIP协议交互中的ICMP情况,首先必须知道什么叫ICMP,在百科上的介绍是:
   ----------------------------------ICMP------------------------------------------------------
 
   ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
    ICMP协议是一种面向无连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。   
    它是TCP/IP协议族的一个子协议,属于网络层协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。当遇到IP数据无法访问目标、IP路由器无法按当前的传输速率转发数据包等情况时,会自动发送ICMP消息。
    ICMP 提供一致易懂的出错报告信息。发送的出错报文返回到发送原数据的设备,因为只有发送设备才是出错报文的逻辑接受者。发送设备随后可根据ICMP报文确定发生错误的类型,并确定如何才能更好地重发失败的数据包。但是ICMP唯一的功能是报告问题而不是纠正错误,纠正错误的任务由发送方完成。
  我们在网络中经常会使用到ICMP协议,比如我们经常使用的用于检查网络通不通的Ping命令(Linux和Windows中均有),这个“Ping”的过程实际上就是ICMP协议工作的过程。还有其他的网络命令如跟踪路由的Tracert命令也是基于ICMP协议的。
-------------------------------------ICMP---------------------------------------------------- 
  
    实现ICMP网络控制报文协议时,只实现echo(回响)服务。uIP在生成回响报文时并不重新分配存储器空间,而是直接修改echo请求报文来生成回响报文。将ICMP类型字段从“echo”类型改变成 “echo reply”类型,重新计算校验和修改校验和字段。
  1. #define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
    主要的处理过程在uip_process()函数中,UIP同样将收到的ICMP的数据包放到uip_buf中。
  写到这里本来不想再写下去了,不过还是有些没明白的地方。比如,我只看到了设备接收对方发过来的数据包,但是,UIP如何将数据包发送出去?还有那个uip_process()函数好长,很多没弄明白,今天继续翻看了另外一些代码,发现一个宏UIP_APPCALL。
    都是自己的疏忽,在uip文档里面搜索UIP_APPCALL就提到了,不同的事件调用不懂的函数,UIP_APPCALL被定义成一个宏,当要用到应用层序的时候,就将UIP_APPCALL定义成相应的函数,比如:
    example1_app应用函数: 
  1. void example1_app(void)
  2.  {
  3.      if(uip_newdata() || uip_rexmit())
  4.      {
  5.          uip_send("ok\n", 3);
  6.      }
  7. }
    UIP_APPCALL宏
  1. #define UIP_APPCALL example2_app
    显然,就是将example1_app定义成UIP_APPCALL宏来使用,这样在uip_process()就可以直接使用UIP_APPCALL了。
    自己定义的example1_app函数中使用UIP应用层函数,就能在网络上交换数据了。

 总算一点一点看完了UIP协议,期间各大网站,各位coder的代码翻了好几个,在此感谢。
    首先,应清楚UIP协议在代码中扮演的是什么角色,我觉得流水线一样,将应用层的数据,通过流水线不断包装。
    TCP---IP---MAC--->发送。
    uip_buf就是实际的原料了。在UIP协议就使用了一个缓冲区。其实是char类型的数组,然后各种strut将它转换成自己的结构,如:
  1.     #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
  2.     #define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
  3.     #define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
     所有的数据都保存在uip_buf数组中。通过uip_process函数来封装。
    uip_len是uip_buf接收到的数据的长度。
    具体的发送到网络上的函数需要根据自己的平台具体实现,整体的循环不需要改动多少。



  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值