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

网卡基本工作原理

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 control

typedef 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 1522

u32 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值