地址转换协议ARP
地址轉(zhuǎn)換協(xié)議ARP
在以太網(wǎng)協(xié)議中規(guī)定,同一局域網(wǎng)中的一臺(tái)主機(jī)要和另一臺(tái)主機(jī)進(jìn)行直接通信,必須要知道目標(biāo)主機(jī)的MAC地址。而在TCP/IP協(xié)議中,網(wǎng)絡(luò)層和傳輸層只關(guān)心目標(biāo)主機(jī)的IP地址。這就導(dǎo)致在以太網(wǎng)中使用IP協(xié)議時(shí),數(shù)據(jù)鏈路層的以太網(wǎng)協(xié)議接到上層IP協(xié)議提供的數(shù)據(jù)中,只包含目的主機(jī)的IP地址。于是需要一種方法,根據(jù)目的主機(jī)的IP地址,獲得其MAC地址。這就是ARP協(xié)議要做的事情。
所謂地址解析(address resolution)就是主機(jī)在發(fā)送幀前將目標(biāo)IP地址轉(zhuǎn)換成目標(biāo)MAC地址的過程。
理論結(jié)構(gòu)
ARP軟件可分為三部分:
- 輸出模塊
- 將高層協(xié)議地址與相應(yīng)的物理地址進(jìn)行綁定,返回給網(wǎng)絡(luò)接口程序
- 輸入模塊
- 處理來(lái)自網(wǎng)絡(luò)的ARP分組,并通過增加新的綁定來(lái)修改ARP高速緩存的內(nèi)容
- 高速緩存管理程序
- 實(shí)現(xiàn)高速緩存替換策略;檢測(cè)高速緩存中的所有表項(xiàng),刪除已達(dá)到規(guī)定時(shí)限的表項(xiàng)
輸出模塊
該模塊主要是要接收IP數(shù)組請(qǐng)求,然后查找物理地址,返回。
主要步驟為:
1. 睡眠,直到IP軟件收到IP分組。
2. 檢查高速緩存表,尋找對(duì)應(yīng)于這個(gè)IP分組的項(xiàng)目。
3. if ( 找到 ){
? if ( 狀態(tài)為 RESOLVED ){
? 提取硬件物理地址;
?將分組連同硬件物理地址一起發(fā)送到數(shù)據(jù)鏈路層;
? ? ? ? ? ? ? ? ? ?return;
?}
?else if ( 狀態(tài)為 PENDING ){
將分組放入相應(yīng)的隊(duì)列;
? ? ? ? ? ? ? ? ?return;
}
?}
?else{
?創(chuàng)建一個(gè)隊(duì)列;
?將分組加入到隊(duì)列中;
?創(chuàng)建一個(gè)高速緩存項(xiàng)目,狀態(tài)設(shè)置為 PENDING ,ATTEMPTS 為 1;
?發(fā)送ARP請(qǐng)求;
?}
ARP高速緩存隊(duì)列
它是用數(shù)組來(lái)存儲(chǔ)的。
extern struct arpentry arptable[ARP_TSIZE]搜索ARP高速緩存
/* arpfind.c - arpfind */ #include <conf.h> #include <kernel.h> #include <network.h> /*------------------------------------------------------------------------ * arpfind - find an ARP entry given a protocol address and interface *------------------------------------------------------------------------ */ struct arpentry * arpfind(u_char *pra, u_short prtype, struct netif *pni) { struct arpentry *pae; /* 定義ARP緩存結(jié)構(gòu)體指針 */int i; for (i=0; i<ARP_TSIZE; ++i) { /* 遍歷ARP高速緩存 */pae = &arptable[i]; /* 高速緩存數(shù)組 */if (pae->ae_state == AS_FREE) /* 緩存為空閑接找下一個(gè) */continue; if (pae->ae_prtype == prtype && /* 協(xié)議類型相同 */pae->ae_pni == pni && /* 接口和協(xié)議地址相同 */BLKEQU(pae->ae_pra, pra, pae->ae_prlen)) /* BLKEQU的定義 #define BLKEQU(b1, b2, len) (!memcmp((b1), (b2), len))*/return pae; } return 0; }ARP請(qǐng)求分組的廣播
/* arpsend.c - arpsend */#include <conf.h> #include <kernel.h> #include <network.h>/*------------------------------------------------------------------------* arpsend - broadcast an ARP request* N.B. Assumes interrupts disabled*------------------------------------------------------------------------*/ int arpsend(pae) struct arpentry *pae; //指向高速緩存的表項(xiàng) {struct netif *pni = pae->ae_pni;struct ep *pep;struct arp *parp;int arplen;pep = (struct ep *) getbuf(Net.netpool); //生成ARP請(qǐng)求分組if ((int)pep == SYSERR)return SYSERR;blkcopy(pep->ep_dst, pni->ni_hwb.ha_addr, pae->ae_hwlen);pep->ep_type = EPT_ARP;pep->ep_order = EPO_NET;parp = (struct arp *) pep->ep_data;parp->ar_hwtype = hs2net(pae->ae_hwtype);parp->ar_prtype = hs2net(pae->ae_prtype);parp->ar_hwlen = pae->ae_hwlen;parp->ar_prlen = pae->ae_prlen;parp->ar_op = hs2net(AR_REQUEST);blkcopy(SHA(parp), pni->ni_hwa.ha_addr, pae->ae_hwlen);blkcopy(SPA(parp), &pni->ni_ip, pae->ae_prlen);bzero(THA(parp), pae->ae_hwlen);blkcopy(TPA(parp), pae->ae_pra, pae->ae_prlen);arplen = ARP_HLEN + 2*(parp->ar_hwlen + parp->ar_prlen);write(pni->ni_dev, pep, EP_HLEN+arplen); //發(fā)送請(qǐng)求分組return OK; }輸入模塊
? ?從一個(gè)隊(duì)列中拿走一個(gè)分組,并連同解析出的物理地址一起發(fā)送給數(shù)據(jù)報(bào)鏈路層傳輸。
主要步驟為
1. 睡眠,直到ARP分組到達(dá)(請(qǐng)求或回答)。
2. 檢查高速緩存表,尋找對(duì)應(yīng)這個(gè)ARP分組的項(xiàng)目。
3. if ( 找到 ){
if ( 狀態(tài)是 RESOLVED ){
更新項(xiàng)目;
return;
}
else if ( 狀態(tài)是 PENDING ){
更新項(xiàng)目;
? ? ? ? ? ? ? ? ?如果隊(duì)列非空的話,將一個(gè)分組從隊(duì)列中取出,將它與硬件地址一起發(fā)送給數(shù)據(jù)鏈路層;
return;
{
?}
?else{
創(chuàng)建一個(gè)項(xiàng)目;
將此項(xiàng)目添加到表中;
return;
?}
4. ?如果分組是一個(gè)請(qǐng)求, 發(fā)送ARP回答。
向表中增加已轉(zhuǎn)換的表項(xiàng)
/* arpadd.c - arpadd */#include <conf.h> #include <kernel.h> #include <network.h>struct arpentry *arpalloc(void);/*------------------------------------------------------------------------* arpadd - Add a RESOLVED entry to the ARP cache* N.B. Assumes interrupts disabled*------------------------------------------------------------------------*/ struct arpentry * arpadd(struct netif *pni, struct arp *parp) {struct arpentry *pae;pae = arpalloc(); //在高速緩存中分配一個(gè)表項(xiàng)/* 利用ARP分組信息填寫表項(xiàng) */pae->ae_hwtype = parp->ar_hwtype;pae->ae_prtype = parp->ar_prtype;pae->ae_hwlen = parp->ar_hwlen;pae->ae_prlen = parp->ar_prlen;pae->ae_pni = pni;pae->ae_queue = EMPTY;memcpy(pae->ae_hwa, SHA(parp), parp->ar_hwlen);memcpy(pae->ae_pra, SPA(parp), parp->ar_prlen);/* 初始化 */pae->ae_ttl = ARP_TIMEOUT;pae->ae_state = AS_RESOLVED;return pae; }發(fā)送等待發(fā)送的分組
/* arpqsend.c - arpqsend */#include <conf.h> #include <kernel.h> #include <network.h>int netwrite(struct netif *, struct ep *, unsigned);/*------------------------------------------------------------------------* arpqsend - write packets queued waiting for an ARP resolution*------------------------------------------------------------------------*/ void arpqsend(struct arpentry *pae) {struct ep *pep;struct netif *pni;if (pae->ae_queue == EMPTY)return;pni = pae->ae_pni;/* 遍歷等待發(fā)送的分組隊(duì)列,調(diào)用netwrite逐個(gè)放入網(wǎng)絡(luò)輸出隊(duì)列中 */while (pep = (struct ep *)deq(pae->ae_queue)) netwrite(pni, pep, pep->ep_len);freeq(pae->ae_queue); //隊(duì)列為空后,釋放自身pae->ae_queue = EMPTY; }高速緩存管理
? 高速緩存是用來(lái)存儲(chǔ)IP地址與物理地址的。如果一個(gè)IP進(jìn)行需要發(fā)送一個(gè)數(shù)據(jù)報(bào),但其目的地址不在ARP高速緩存中,就會(huì)創(chuàng)建一個(gè)新的表項(xiàng),然后廣播相應(yīng)的請(qǐng)求分組,并等待分組置入隊(duì)列中。
主要步驟:
1. 睡眠,周期性的喚醒。
2. 遍歷高速緩存的每一個(gè)項(xiàng)目:
if ( 狀態(tài)為FREE )
? ? ? ? ? ?continue;
? ? ? if ( 狀態(tài)為PENDING ){
嘗試次數(shù)+1;
if ( 嘗試次數(shù)達(dá)到最大次數(shù) ){
該項(xiàng)目狀態(tài)->FREE;
? ? ?? 撤銷相應(yīng)的隊(duì)列;
}
else {
發(fā)送ARP請(qǐng)求;
}
continue;
}
? else if( 狀態(tài)為RESOLVED ){
將超時(shí)字段的值減去已經(jīng)過去的時(shí)間;
若結(jié)果小于0,狀態(tài)->FREE,撤銷相應(yīng)隊(duì)列。
}
?替換策略
/* arpalloc.c - arpalloc */ #include <conf.h> #include <kernel.h> #include <proc.h> #include <network.h> void arpdq(struct arpentry *); /*------------------------------------------------------------------------ * arpalloc - allocate an entry in the ARP table * N.B. Assumes interrupts DISABLED *------------------------------------------------------------------------ */ struct arpentry *arpalloc() { static int aenext = 0; //靜態(tài)變量,保證循環(huán) struct arpentry *pae; int i; for (i=0; i<ARP_TSIZE; ++i) { //遍歷表if (arptable[aenext].ae_state == AS_FREE) break; aenext = (aenext + 1) % ARP_TSIZE; //循環(huán)替換} pae = & arptable[aenext]; aenext = (aenext + 1) % ARP_TSIZE; if (pae->ae_state == AS_PENDING && pae->ae_queue >= 0) arpdq(pae); pae->ae_state = AS_PENDING; return pae; }?
?
總結(jié)
- 上一篇: vc 国际化的资源文件处理
- 下一篇: 几行简单代码实现DIV层上显示Toolt