240 likes | 361 Views
網路程式. 目前提供的嵌入式 UDP/IP 程式. 當有封包暫存於網卡時, 8051 向網卡取出一個封包置於 8051 內部 SRAM 後,釋放此封包佔用網卡空間,才開始處理此封包。 目前此版提供的功能,主要是令本機端處於被動模式。 提供 ARP Reply ,不提供 ARP Request 。. 主程式架構. Main() { var_init(); NICInit(); while(1) { while (HavePacketRecev()) {
E N D
目前提供的嵌入式UDP/IP程式 • 當有封包暫存於網卡時,8051向網卡取出一個封包置於8051內部SRAM後,釋放此封包佔用網卡空間,才開始處理此封包。 • 目前此版提供的功能,主要是令本機端處於被動模式。 • 提供ARP Reply,不提供ARP Request。
主程式架構 Main() { var_init(); NICInit(); while(1) { while (HavePacketRecev()) { if (RecvPacket(E_recv,512)) // packet < 512 bytes { Ni_in(); } } } }
void main() { xdata char daaa[100]; int j=0; InitSerial(); var_init(); delay(1000); NICInit(); for (i=0;i<100;i++) { daaa[i]=my_IP[j]; j++; if (j>3) { j=0; } } while(1) { delay(1000); delay(1000); delay(1000); delay(1000); delay(1000); P11=~P11; SendPacket(daaa,100); while (HavePacketRecev()) { if(RecvPacket(E_recv,512)) // packet < 512 bytes { Ni_in(); } } } }
void var_init(void); • 設定傳送封包時本地MAC Address • 當有封包欲傳送時,若需要Source MAC Address會取自此陣列(unsigned char my_MAC[6];) • 設定傳送封包時本地IP Address • 當有封包欲傳送時,若需要Source IP address會取自此陣列(unsigned char my_IP[6];) • 設定next_page=0x46 • 當欲檢查網卡是否收到封包時,將讀取網卡內部CURR暫存器內容並與此變數比較 • 使用者也可把其它需初始化的變數放於此含函數內一起初始化
Var_init() : 設定MAC/IP Address void var_init() { next_page=0x46; my_MAC[0]=0x11; my_MAC[1]=0x80; my_MAC[2]=0xAD; my_MAC[3]=0x84; my_MAC[4]=0xF8; my_MAC[5]=0x44; my_IP[0]=140; my_IP[1]=125; my_IP[2]=33; my_IP[3]=206; memcpy(&E_send[6],my_MAC,6); }
void NICInit(void) • 初始化網卡內部暫存器 • CR、DCR、RBCR0、RBCR1、TPSR、TCR、PSTART、BNRY、PSTOP、RCR、ISR、IMR、CURR、PAR0-5 • Ex: 規劃TPSR=0x40、PSTART=0x40、PSTOP=0x60、BNRY=0x5F、CURR=0x40
char HavePacketRecev(void) • 檢查網卡內部是否有封包 • 判斷next_page是否等於網卡內部CURR。是則代表無封包,不等則代表有封包 • 回傳 • 無封包回傳0,有封包回傳非1
char HavePacketRecev(void) { unsigned char curr; fEthernet_Write(CR,0x62); curr=fEthernet_Read(CURR); fEthernet_Write(CR,0x22); if (curr==next_page) return 0; else return 1; }
unsigned int RecvPacket(unsigned char *buf_packet, int limit) • unsigned char *buf_packet • 提供一個空間給收封包函數放資料的地方 • int limit • 告訴函數最多不超過Limit指定的封包大小 • 回傳 • 告知填入幾Bytes資料於buf_packet陣列中。若網卡內封包長度大於Limit規定,則回傳0,並將此封包丟棄
void SendPacket(unsigned char *buf_packet, unsigned int packetlength) • unsigned char *buf_packet • 告知函數欲傳送至Ethernet的資料起始位置 • unsigned int packetlength • 資料量長度 • 回傳 • 無
void Ni_in(void) • 解析經由RecvPacket( )函數所收的網卡封包 • Ni_in( )做demux功能,根據所收封包格式, 呼叫相對應函數進行進一步處理。 • 若為ARP協定則呼叫ARP_in( ), • 若為IP協定則呼叫IP_in( )。 • 非以上兩種協定之封包時,將丟棄此封包。
void Ni_in() { if ( E_recv[12]==0x08 ) // Ethernet Frame type 0x08 { switch (E_recv[13]) // Ethernet Frame type 0x00 IP , 0x06 ARP { case 0x00: if (!is_broadcast_MAC(E_recv)) IP_in(); break; case 0x06: if (is_broadcast_MAC(E_recv)) ARP_in(); break; } } }
void ARP_in(void); • 檢查所收封包的payload • 若為ARP協定之ARP Request,則產生ARP Reply格式資料,並置於E_send[ ]陣列中 • 呼叫SendPacket( )函數將資料組成Ethernet封包格式送至Ethernet。 • 此版本之程式不會主動發出ARP Request格式封包,故收到ARP Reply封包時,不予以理會。
void ARP_in() { ARP *arp,*arp2; arp=(ARP *) &E_recv[14]; arp2=(ARP *) &E_send[14]; if (arp->op==0x0001) // ARP request { if ( !memcmp(arp->DIP,my_IP,4) ) // is my IP, ARP reply { memcpy(E_send,arp->SHA,6); // Target MAC memcpy(&E_send[6],my_MAC,6); // Source MAC memcpy(&E_send[12],&E_recv[12],8); // Frame type... arp2->op=0x0002; // ARP reply code memcpy(arp2->SHA,my_MAC,6); memcpy(arp2->DIP,arp->SIP,4); memcpy(arp2->DHA,arp->SHA,6); memcpy(arp2->SIP,my_IP,4); SendPacket(E_send,60); } } }
void IP_in(void) • 檢查IP協定表頭,若所帶之資料為ICMP協定格式資料,則呼叫ICMP_in( )處理。若為UDP協定格式資料,則呼叫UDP_in( )。 • 目前只能處理ICMP與UDP協定,若非此兩種協定則不處理。 • 目前版本之IP_in( )函數內並不作CheckSum運算。雖失去IP協定之CheckSum用意(可靠性),以加快處理IP層處理。
void IP_in() { IP_header *ip; ip=(IP_header *) &E_recv[14]; if ( !memcmp(my_IP,ip->ip_dst,4) ) // is my IP, My IP packet { switch (ip->ip_proto) { case 0x01: // ICMP code ICMP_in(); break; case 0x11: // UDP code UDP_in(); break; } } }
void ICMP_in(void) • 若為ICMP協定中之ECHO Request,則產生ECHO Reply格式資料放置於E_send[ ]陣列中,並呼叫IP_out( )函數將ICMP ECHO Reply封包資料送出。 • 若非ICMP之ECHO Request封包,則不處理 • 實作此協定為了檢查之用,當系統Power-On後,於電腦端使用Ping程式檢查是否可與本系統做基本網路通訊之測試。
void ICMP_in() { IP_header *ip,*ip2; unsigned int *sum; if (E_recv[34]==0x08) // is ECHO request, must ECHO reply { ip=(IP_header *) &E_recv[14]; ip2=(IP_header *) &E_send[14]; sum=(unsigned int *)&(ip2->ip_data[2]); memcpy(E_send,&E_recv[6],6); // Target_MAC ip2->ip_proto=0x01; // ICMP packet ip2->ip_data[0]=0x00; // ECHO reply ip2->ip_data[1]=0x00; // Code 00 ip2->ip_data[2]=0x00; // ICMP checksum ip2->ip_data[3]=0x00; memcpy(&ip2->ip_data[4],&ip->ip_data[4],(ip->ip_len)-24); //ID & seq NO. & data *sum=cksum( (unsigned short *)&(ip2->ip_data),((ip->ip_len)-20)>>1 ); IP_out(&E_recv[26],0x40,ip->ip_len); // Dest IP out } }
void IP_out(void *dip,unsigned char ttl,int size) • 添加IP-Head於E_send[ ]陣列中,呼叫SendPacket將資料組成Ethernet封包格式送至Ethernet。 • void *dip • 目的地IP Address • unsigned char ttl • 設定IP-Head之TTL • int size • IP-Head加上IP-Data總長度 • 回傳 • 無
void IP_out(void *dip,unsigned char ttl,int size) { static int id=1; IP_header *ip; ip=(IP_header *) &E_send[14]; memcpy(ip->ip_dst,dip,4); // Target IP address memcpy(ip->ip_src,my_IP,4); // My IP address memcpy(&E_send[6],my_MAC,6); // Source MAC E_send[12]=0x08; // Ethernet Type = 08 00 ,IP E_send[13]=0x00; // Ethernet Type ip->ip_verlen=0x45; // Version 4, Header length 20 byte (5*4) ip->ip_tos=0x00; // Type of Service ip->ip_ttl=ttl; // TTL ip->ip_fragoff=0x0000; // non-fragement ip->ip_id=id++; // IP identify, a seq NO. ip->ip_len=size; // IP length ip->ip_cksum=0x0000; ip->ip_cksum=cksum((unsigned short *) &E_send[14],20>>1); size=size+14; if (size<60) size=60; SendPacket(E_send,size); }
void UDP_in(void) • 當IP協定之上層協定為UDP時,將會呼叫此函數。而此函數之功能由使用者自行設計。
void UDP_in() { UDP *udp,*udp2; udp=(UDP *) &E_recv[34]; if (udp->d_port==1024) // Dest port is 1024, ack & save data { udp2=(UDP *) &E_send[34]; udp2->s_port=1024; udp2->d_port=udp->s_port; udp2->udp_len=0x000c; // UDP packet length udp2->checksum=0x0000; udp2->udp_data[0]=0x00; // ACK is 0x00 udp2->udp_data[1]=udp->udp_data[1]; // seq No. udp2->udp_data[2]=0xff; // ACK format udp2->udp_data[3]=0xff; // ACK format udp2->checksum=udp_chksum( (unsigned short *)udp2,12>>1); memcpy(E_send,&E_recv[6],6); // Target_MAC E_send[23]=0x11; // UDP protocol code IP_out(&E_recv[26],0x40,32); // IP + UDP + Data, 20+8+4 } }