网卡 搭建新通道 DM9000芯片 ARP协议实现

来源:互联网 发布:网络经过路由器变慢了 编辑:程序博客网 时间:2024/05/21 19:21

网卡基本工作原理

OSI七层模型:
OSI(Open SystemInterconnection),开放式系统互联参考模型 。它把网络协议从逻辑上分为了7层。通过七个层次使不同的系统网络之间实现可靠的通讯。
这里写图片描述

Linux四层模型:
OSI参考模型的过于庞大、复杂招致了许多批评。与此对照,由技术人员自己开发的TCP/IP协议栈获得了更为广泛的应用。
这里写图片描述

DM9000硬件结构:
这里写图片描述

主要由三部分组成 PHY、MAC、MII

这里写图片描述

从上图可见,MAC位于数据链路层,PHY位于物理层,MII位于他们之间。

MAC:
这里写图片描述
MAC主要负责数据帧的构建、数据差错检查、传送控制等。

PHY:
这里写图片描述
PHY是物理接口收发器,属于物理层,当它收到MAC过来的数据时,它会去加上校验码,然后按照物理层的规则进行数据编码,再发送到传输介质上。接收过程则相反。

MII:
这里写图片描述
MII:媒体独立接口, “媒体独立”表明MAC一定情况下,任何类型的PHY设备都可以正常工作。如果更换了PHY,同样可以正常工作。

DM9000编程接口 简介
DM9000有两个编程端口,分别是 Index接口数据接口,在2440开发板上,他们的地址分别为0x20000300和0x20000304,其中‘2’表示片选地址,从内存地址分配图和硬件电路上的管脚可以看出,‘3’是根据数据手册中TXD算出来的,‘4’是需要CMD命令位为1。

DM9000驱动程序设计

头文件:

//dm9000 Ethernet#define DM9000_ID       0x90000A46#define DM9000_PKT_MAX  1536    /* Received packet max size */#define DM9000_PKT_RDY  0x01    /* Packet ready to receive *///although the registers are 16 bit, they are 32-bit aligned.#define DM9000_NCR     0x00#define DM9000_NSR     0x01#define DM9000_TCR     0x02#define DM9000_TSR1    0x03#define DM9000_TSR2    0x04#define DM9000_RCR     0x05#define DM9000_RSR     0x06#define DM9000_ROCR    0x07#define DM9000_BPTR    0x08#define DM9000_FCTR    0x09#define DM9000_FCR     0x0A#define DM9000_EPCR    0x0B#define DM9000_EPAR    0x0C#define DM9000_EPDRL   0x0D#define DM9000_EPDRH   0x0E#define DM9000_WCR     0x0F#define DM9000_PAR     0x10#define DM9000_MAR     0x16#define DM9000_GPCR    0x1e#define DM9000_GPR     0x1f#define DM9000_TRPAL   0x22#define DM9000_TRPAH   0x23#define DM9000_RWPAL   0x24#define DM9000_RWPAH   0x25#define DM9000_VIDL    0x28#define DM9000_VIDH    0x29#define DM9000_PIDL    0x2A#define DM9000_PIDH    0x2B#define DM9000_CHIPR   0x2C#define DM9000_SMCR    0x2F#define DM9000_PHY     0x40 /* PHY address 0x01 */#define DM9000_MRCMDX    0xF0#define DM9000_MRCMD     0xF2#define DM9000_MRRL      0xF4#define DM9000_MRRH      0xF5#define DM9000_MWCMDX    0xF6#define DM9000_MWCMD     0xF8#define DM9000_MWRL      0xFA#define DM9000_MWRH      0xFB#define DM9000_TXPLL     0xFC#define DM9000_TXPLH     0xFD#define DM9000_ISR       0xFE#define DM9000_IMR       0xFF#define NCR_EXT_PHY      (1<<7)#define NCR_WAKEEN       (1<<6)#define NCR_FCOL         (1<<4)#define NCR_FDX          (1<<3)#define NCR_LBK          (3<<1)#define NCR_LBK_INT_MAC  (1<<1)#define NCR_LBK_INT_PHY  (2<<1)#define NCR_RST          (1<<0)#define NSR_SPEED       (1<<7)#define NSR_LINKST      (1<<6)#define NSR_WAKEST      (1<<5)#define NSR_TX2END      (1<<3)#define NSR_TX1END      (1<<2)#define NSR_RXOV        (1<<1)#define TCR_TJDIS       (1<<6)#define TCR_EXCECM      (1<<5)#define TCR_PAD_DIS2    (1<<4)#define TCR_CRC_DIS2    (1<<3)#define TCR_PAD_DIS1    (1<<2)#define TCR_CRC_DIS1    (1<<1)#define TCR_TXREQ       (1<<0)#define TSR_TJTO        (1<<7)#define TSR_LC          (1<<6)#define TSR_NC          (1<<5)#define TSR_LCOL        (1<<4)#define TSR_COL         (1<<3)#define TSR_EC          (1<<2)#define RCR_WTDIS       (1<<6)#define RCR_DIS_LONG    (1<<5)#define RCR_DIS_CRC     (1<<4)#define RCR_ALL         (1<<3)#define RCR_RUNT        (1<<2)#define RCR_PRMSC       (1<<1)#define RCR_RXEN        (1<<0)#define RSR_RF          (1<<7)#define RSR_MF          (1<<6)#define RSR_LCS         (1<<5)#define RSR_RWTO        (1<<4)#define RSR_PLE         (1<<3)#define RSR_AE          (1<<2)#define RSR_CE          (1<<1)#define RSR_FOE         (1<<0)#define EPCR_EPOS_PHY   (1<<3)#define EPCR_EPOS_EE    (0<<3)#define EPCR_ERPRR      (1<<2)#define EPCR_ERPRW      (1<<1)#define EPCR_ERRE       (1<<0)#define FCTR_HWOT(ot)   (( ot & 0xf ) << 4 )#define FCTR_LWOT(ot)   ( ot & 0xf )#define BPTR_BPHW(x)        ((x) << 4)#define BPTR_JPT_200US      (0x07)#define BPTR_JPT_600US      (0x0f)#define IMR_PAR         (1<<7)#define IMR_ROOM        (1<<3)#define IMR_ROM         (1<<2)#define IMR_PTM         (1<<1)#define IMR_PRM         (1<<0)#define ISR_ROOS        (1<<3)#define ISR_ROS         (1<<2)#define ISR_PTS         (1<<1)#define ISR_PRS         (1<<0)#define GPCR_GPIO0_OUT      (1<<0)#define GPR_PHY_PWROFF      (1<<0)

cpp文件:

#include "dm9000.h"#define DM_ADD (*((volatile unsigned short *)0x20000300))#define DM_DAT (*((volatile unsigned short *)0x20000304))#define GPFCON    (*(volatile unsigned *)0x56000050)//Port F control#define EXTINT0   (*(volatile unsigned *)0x56000088)//External interrupt control register 0#define EINTMASK  (*(volatile unsigned *)0x560000a4)//External interrupt mask#define SRCPND    (*(volatile unsigned *)0x4a000000)//Interrupt request status#define INTPND    (*(volatile unsigned *)0x4a000010)//Interrupt request status#define INTMSK    (*(volatile unsigned *)0x4a000008)//Interrupt mask control#define EINTPEND  (*(volatile unsigned *)0x560000a8)//External interrupt pending#define BWSCON    (*(volatile unsigned *)0x48000000)//Bus width & wait status#define BANKCON4  (*(volatile unsigned *)0x48000014)//BANK4 controltypedef unsigned int   u32;typedef unsigned short u16;typedef unsigned char  u8;u8 mac_addr[6] = {9,8,7,6,5,4};u8 buffer[1000];void cs_init(){    BWSCON = BWSCON & (~(0x3<<16));    BWSCON = BWSCON |(0x1<<16);    BANKCON4 = (0x0<<13)|(0x0<<11)|(0x7<<8)|(0x1<<6)|(0x0<<4)|(0x0<<2)|(0x0<<0);}void int_init(){    GPFCON = GPFCON &(~(0x3<<14));    GPFCON = GPFCON |(0x2<<14);    EXTINT0 = EXTINT0 & (~(0x7<<28));    EXTINT0 = EXTINT0 | (0x1<<28);    INTMSK = INTMSK &(~(1<<4));    EINTMASK = EINTMASK & (~(0x1<<7));    SRCPND = (1<<4);    INTPND = (1<<4);}void dm9000_reg_write(u16 reg,u16 data){    DM_ADD = reg;       DM_DAT = data;  }u8 dm9000_reg_read(u16 reg){    DM_ADD = reg;    return DM_DAT;  }void dm9000_reset(){    dm9000_reg_write(DM9000_GPCR, GPCR_GPIO0_OUT);    dm9000_reg_write(DM9000_GPR, 0);        dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));    dm9000_reg_write(DM9000_NCR, 0);    dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));    dm9000_reg_write(DM9000_NCR, 0);}void dm9000_probe(void){    u32 id_val;    id_val = dm9000_reg_read(DM9000_VIDL);    id_val |= dm9000_reg_read(DM9000_VIDH) << 8;    id_val |= dm9000_reg_read(DM9000_PIDL) << 16;    id_val |= dm9000_reg_read(DM9000_PIDH) << 24;    if (id_val == DM9000_ID) {        printf("dm9000 is found !\n");        return ;    } else {        printf("dm9000 is not found !\n");        return ;    }}void dm9000_init(){    u32 i;    /*设置片选*/    cs_init();    /*中断初始化*/    int_init();    /*复位设备*/    dm9000_reset();    /*捕获dm9000*/    dm9000_probe();    /*MAC初始化*/    /* Program operating register, only internal phy supported */    dm9000_reg_write(DM9000_NCR, 0x0);    /* TX Polling clear */    dm9000_reg_write(DM9000_TCR, 0);    /* Less 3Kb, 200us */    dm9000_reg_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);    /* Flow Control : High/Low Water */    dm9000_reg_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));    /* SH FIXME: This looks strange! Flow Control */    dm9000_reg_write(DM9000_FCR, 0x0);    /* Special Mode */    dm9000_reg_write(DM9000_SMCR, 0);    /* clear TX status */    dm9000_reg_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);    /* Clear interrupt status */    dm9000_reg_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);    /*填充MAC地址*/    for (i = 0; i < 6; i++)        dm9000_reg_write(DM9000_PAR+i, mac_addr[i]);    /*激活DM9000*/        dm9000_reg_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);    /* Enable TX/RX interrupt mask */    dm9000_reg_write(DM9000_IMR, IMR_PAR);}void dm9000_tx(u8 *data,u32 length){    u32 i;    /*禁止中断*/    dm9000_reg_write(DM9000_IMR,0x80);    /*写入发送数据的长度*/    dm9000_reg_write(DM9000_TXPLL, length & 0xff);    dm9000_reg_write(DM9000_TXPLH, (length >> 8) & 0xff);    /*写入待发送的数据*/    DM_ADD = DM9000_MWCMD;    for(i=0;i<length;i+=2)    {        DM_DAT = data[i] | (data[i+1]<<8);    }    /*启动发送*/    dm9000_reg_write(DM9000_TCR, TCR_TXREQ);     /*等待发送结束*/    while(1)    {       u8 status;       status = dm9000_reg_read(DM9000_TCR);       if((status&0x01)==0x00)           break;       }    /*清除发送状态*/    dm9000_reg_write(DM9000_NSR,0x2c);    /*恢复中断使能*/    dm9000_reg_write(DM9000_IMR,0x81);}#define PTK_MAX_LEN 1522u32 dm9000_rx(u8 *data){    u8 status,len;    u16 tmp;    u32 i;    /*判断是否产生中断,且清除*/    if(dm9000_reg_read(DM9000_ISR) & 0x01)        dm9000_reg_write(DM9000_ISR,0x01);    else        return 0;    /*空读*/    dm9000_reg_read(DM9000_MRCMDX);    /*读取状态*/    status = dm9000_reg_read(DM9000_MRCMD);    /*读取包长度*/    len = DM_DAT;    /*读取包数据*/    if(len<PTK_MAX_LEN)    {       for(i=0;i<len;i+=2)       {           tmp = DM_DAT;           data[i] = tmp & 0x0ff;           data[i+1] = (tmp>>8)&0x0ff;       }    }}void int_issue(){    u32 i;    i = dm9000_rx(buffer);      SRCPND = (1<<4);    INTPND = (1<<4);    EINTPEND |= 1<<7; }

ARP协议实现

ARP协议介绍:
1、以太网通讯格式

这里写图片描述

在计算机网络中,数据发送的过程,就是一个把数据按照各层协议层层封装的过程。在这个过程中,最终要使用的协议通常是以太网协议(数据链路层协议)。

这里写图片描述

目的MAC地址:接收者的物理地址
源MAC地址:发送者的物理地址
类型:标明高层的数据使用的协议类型
数据:高层的数据
CRC:校验码

2、ARP协议功能

ARP是网络层协议,封装在以太网包中。

在以太网络中,每台计算机的唯一身份标示是MAC地址(物理层的地址),两台计算机要进行通讯,也必须知道对方的MAC地址,但是用户通常只知道对方的IP地址,这个时候,就可以利用ARP(地址解析协议)来向局域网中的所有计算机发送ARP请求包,收到请求包且满足条件的计算机将回复ARP应答包,告知其MAC地址。所以ARP协议是一种利用IP地址或者MAC地址的协议。

3、ARP通讯格式
这里写图片描述

ARP包分为请求包和应答包,通过OP字段来区别。

编程实现ARP:
ARP协议的实现需要借助于DM9000芯片,因此同样需要DM9000的驱动程序。

头文件:

typedef unsigned int   u32;typedef unsigned short u16;typedef unsigned char  u8;typedef struct eth_hdr{    u8 d_mac[6];    u8 s_mac[6];    u16 type;}ETH_HDR;typedef struct arp_hdr{    ETH_HDR ethhdr;    u16 hwtype;    u16 protocol;    u8 hwlen;    u8 protolen;    u16 opcode;    u8 smac[6];    u8 sipaddr[4];    u8 dmac[6];    u8 dipaddr[4];}ARP_HDR;ARP_HDR arpbuf;extern u8 host_mac_addr[6];extern u8 mac_addr[6];extern u8 ip_addr[4];extern u8 host_ip_addr[4];extern u16 packet_len;extern u8 *buffer;

CPP文件:

#include "arp.h"//设置网络字节序#define HON(n) ((((u16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))/*1.发送arp请求包*/void arp_request(){     /*1.构成arp请求包*/     memcpy(arpbuf.ethhdr.d_mac,host_mac_addr,6);//目的mac地址需要全为F     memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);     arpbuf.ethhdr.type = HON(0x0806);     arpbuf.hwtype = HON(1);     arpbuf.protocol = HON(0x0800);     arpbuf.hwlen = 6;     arpbuf.protolen = 4;     arpbuf.opcode = HON(1);     //不需要填目的mac     memcpy(arpbuf.smac,mac_addr,6);     memcpy(arpbuf.sipaddr,ip_addr,4);     memcpy(arpbuf.dipaddr,host_ip_addr,4);     packet_len = 14+28;     /*2.调用dm9000发送函数,发送应答包*/        dm9000_tx(buffer,packet_len);}/*2.解析arp应答包,提取mac*/u8 arp_process(){    u32 i;    if (packet_len<28)        return 0;    memcpy(host_ip_addr,arpbuf.sipaddr,4);    printf("host ip is : ");    for(i=0;i<4;i++)        printf("%03d ",host_ip_addr[i]);    printf("\n\r");    memcpy(host_mac_addr,arpbuf.smac,6);    printf("host mac is : ");    for(i=0;i<6;i++)        printf("%02x ",host_mac_addr[i]);    printf("\n\r");}

注意:必须设置为网络字节序:大端模式

0 0
原创粉丝点击