XINU
arp.c
Go to the documentation of this file.
1 /* arp.c - arp_init, arp_resolve, arp_in, arp_alloc, arp_ntoh, arp_hton */
2 
3 #include <xinu.h>
4 
5 struct arpentry arpcache[ARP_SIZ]; /* ARP cache */
6 
7 /*------------------------------------------------------------------------
8  * arp_init - Initialize ARP cache for an Ethernet interface
9  *------------------------------------------------------------------------
10  */
11 void arp_init(void)
12 {
13  int32 i; /* ARP cache index */
14 
15  for (i=1; i<ARP_SIZ; i++) { /* Initialize cache to empty */
17  }
18 }
19 
20 /*------------------------------------------------------------------------
21  * arp_resolve - Use ARP to resolve an IP address to an Ethernet address
22  *------------------------------------------------------------------------
23  */
25  uint32 nxthop, /* Next-hop address to resolve */
26  byte mac[ETH_ADDR_LEN] /* Array into which Ethernet */
27  ) /* address should be placed */
28 {
29  intmask mask; /* Saved interrupt mask */
30  struct arppacket apkt; /* Local packet buffer */
31  int32 i; /* Index into arpcache */
32  int32 slot; /* ARP table slot to use */
33  struct arpentry *arptr; /* Ptr to ARP cache entry */
34  int32 msg; /* Message returned by recvtime */
35 
36  /* Use MAC broadcast address for IP limited broadcast */
37 
38  if (nxthop == IP_BCAST) {
39  memcpy(mac, NetData.ethbcast, ETH_ADDR_LEN);
40  return OK;
41  }
42 
43  /* Use MAC broadcast address for IP network broadcast */
44 
45  if (nxthop == NetData.ipbcast) {
46  memcpy(mac, NetData.ethbcast, ETH_ADDR_LEN);
47  return OK;
48  }
49 
50  /* Ensure only one process uses ARP at a time */
51 
52  mask = disable();
53 
54  /* See if next hop address is already present in ARP cache */
55 
56  for (i=0; i<ARP_SIZ; i++) {
57  arptr = &arpcache[i];
58  if (arptr->arstate == AR_FREE) {
59  continue;
60  }
61  if (arptr->arpaddr == nxthop) { /* Adddress is in cache */
62  break;
63  }
64  }
65 
66  if (i < ARP_SIZ) { /* Entry was found */
67 
68  /* If entry is resolved - handle and return */
69 
70  if (arptr->arstate == AR_RESOLVED) {
71  memcpy(mac, arptr->arhaddr, ARP_HALEN);
72  restore(mask);
73  return OK;
74  }
75 
76  /* Entry is already pending - return error because */
77  /* only one process can be waiting at a time */
78 
79  if (arptr->arstate == AR_PENDING) {
80  restore(mask);
81  return SYSERR;
82  }
83  }
84 
85  /* IP address not in cache - allocate a new cache entry and */
86  /* send an ARP request to obtain the answer */
87 
88  slot = arp_alloc();
89  if (slot == SYSERR) {
90  restore(mask);
91  return SYSERR;
92  }
93 
94  arptr = &arpcache[slot];
95  arptr->arstate = AR_PENDING;
96  arptr->arpaddr = nxthop;
97  arptr->arpid = currpid;
98 
99  /* Hand-craft an ARP Request packet */
100 
101  memcpy(apkt.arp_ethdst, NetData.ethbcast, ETH_ADDR_LEN);
102  memcpy(apkt.arp_ethsrc, NetData.ethucast, ETH_ADDR_LEN);
103  apkt.arp_ethtype = ETH_ARP; /* Packet type is ARP */
104  apkt.arp_htype = ARP_HTYPE; /* Hardware type is Ethernet */
105  apkt.arp_ptype = ARP_PTYPE; /* Protocol type is IP */
106  apkt.arp_hlen = 0xff & ARP_HALEN; /* Ethernet MAC size in bytes */
107  apkt.arp_plen = 0xff & ARP_PALEN; /* IP address size in bytes */
108  apkt.arp_op = 0xffff & ARP_OP_REQ;/* ARP type is Request */
110  apkt.arp_sndpa = NetData.ipucast; /* IP address of interface */
111  memset(apkt.arp_tarha, '\0', ARP_HALEN); /* Target HA is unknown*/
112  apkt.arp_tarpa = nxthop; /* Target protocol address */
113 
114  /* Convert ARP packet from host to net byte order */
115 
116  arp_hton(&apkt);
117 
118  /* Convert Ethernet header from host to net byte order */
119 
120  eth_hton((struct netpacket *)&apkt);
121 
122  /* Send the packet ARP_RETRY times and await response */
123 
124  msg = recvclr();
125  for (i=0; i<ARP_RETRY; i++) {
126  write(ETHER0, (char *)&apkt, sizeof(struct arppacket));
127  msg = recvtime(ARP_TIMEOUT);
128  if (msg == TIMEOUT) {
129  continue;
130  } else if (msg == SYSERR) {
131  restore(mask);
132  return SYSERR;
133  } else { /* entry is resolved */
134  break;
135  }
136  }
137 
138  /* If no response, return TIMEOUT */
139 
140  if (msg == TIMEOUT) {
141  arptr->arstate = AR_FREE; /* Invalidate cache entry */
142  restore(mask);
143  return TIMEOUT;
144  }
145 
146  /* Return hardware address */
147 
148  memcpy(mac, arptr->arhaddr, ARP_HALEN);
149  restore(mask);
150  return OK;
151 }
152 
153 
154 /*------------------------------------------------------------------------
155  * arp_in - Handle an incoming ARP packet
156  *------------------------------------------------------------------------
157  */
158 void arp_in (
159  struct arppacket *pktptr /* Ptr to incoming packet */
160  )
161 {
162  intmask mask; /* Saved interrupt mask */
163  struct arppacket apkt; /* Local packet buffer */
164  int32 slot; /* Slot in cache */
165  struct arpentry *arptr; /* Ptr to ARP cache entry */
166  bool8 found; /* Is the sender's address in */
167  /* the cache? */
168 
169  /* Convert packet from network order to host order */
170 
171  arp_ntoh(pktptr);
172 
173  /* Verify ARP is for IPv4 and Ethernet */
174 
175  if ( (pktptr->arp_htype != ARP_HTYPE) ||
176  (pktptr->arp_ptype != ARP_PTYPE) ) {
177  freebuf((char *)pktptr);
178  return;
179  }
180 
181  /* Ensure only one process uses ARP at a time */
182 
183  mask = disable();
184 
185  /* Search cache for sender's IP address */
186 
187  found = FALSE;
188 
189  for (slot=0; slot < ARP_SIZ; slot++) {
190  arptr = &arpcache[slot];
191 
192  /* Skip table entries that are unused */
193 
194  if (arptr->arstate == AR_FREE) {
195  continue;
196  }
197 
198  /* If sender's address matches, we've found it */
199 
200  if (arptr->arpaddr == pktptr->arp_sndpa) {
201  found = TRUE;
202  break;
203  }
204  }
205 
206  if (found) {
207 
208  /* Update sender's hardware address */
209 
210  memcpy(arptr->arhaddr, pktptr->arp_sndha, ARP_HALEN);
211 
212  /* If a process was waiting, inform the process */
213 
214  if (arptr->arstate == AR_PENDING) {
215  /* Mark resolved and notify waiting process */
216  arptr->arstate = AR_RESOLVED;
217  send(arptr->arpid, OK);
218  }
219  }
220 
221  /* For an ARP reply, processing is complete */
222 
223  if (pktptr->arp_op == ARP_OP_RPLY) {
224  freebuf((char *)pktptr);
225  restore(mask);
226  return;
227  }
228 
229  /* The following is for an ARP request packet: if the local */
230  /* machine is not the target or the local IP address is not */
231  /* yet known, ignore the request (i.e., processing is complete)*/
232 
233  if ((!NetData.ipvalid) ||
234  (pktptr->arp_tarpa != NetData.ipucast)) {
235  freebuf((char *)pktptr);
236  restore(mask);
237  return;
238  }
239 
240  /* Request has been sent to the local machine's address. So, */
241  /* add sender's info to cache, if not already present */
242 
243  if (!found) {
244  slot = arp_alloc();
245  if (slot == SYSERR) { /* Cache is full */
246  kprintf("ARP cache overflow on interface\n");
247  freebuf((char *)pktptr);
248  restore(mask);
249  return;
250  }
251  arptr = &arpcache[slot];
252  arptr->arpaddr = pktptr->arp_sndpa;
253  memcpy(arptr->arhaddr, pktptr->arp_sndha, ARP_HALEN);
254  arptr->arstate = AR_RESOLVED;
255  }
256 
257  /* Hand-craft an ARP reply packet and send back to requester */
258 
259  memcpy(apkt.arp_ethdst, pktptr->arp_sndha, ARP_HALEN);
261  apkt.arp_ethtype= ETH_ARP; /* Frame carries ARP */
262  apkt.arp_htype = ARP_HTYPE; /* Hardware is Ethernet */
263  apkt.arp_ptype = ARP_PTYPE; /* Protocol is IP */
264  apkt.arp_hlen = ARP_HALEN; /* Ethernet address size*/
265  apkt.arp_plen = ARP_PALEN; /* IP address size */
266  apkt.arp_op = ARP_OP_RPLY; /* Type is Reply */
267 
268  /* Insert local Ethernet and IP address in sender fields */
269 
271  apkt.arp_sndpa = NetData.ipucast;
272 
273  /* Copy target Ethernet and IP addresses from request packet */
274 
275  memcpy(apkt.arp_tarha, pktptr->arp_sndha, ARP_HALEN);
276  apkt.arp_tarpa = pktptr->arp_sndpa;
277 
278  /* Convert ARP packet from host to network byte order */
279 
280  arp_hton(&apkt);
281 
282  /* Convert the Ethernet header to network byte order */
283 
284  eth_hton((struct netpacket *)&apkt);
285 
286  /* Send the reply */
287 
288  write(ETHER0, (char *)&apkt, sizeof(struct arppacket));
289  freebuf((char *)pktptr);
290  restore(mask);
291  return;
292 }
293 
294 /*------------------------------------------------------------------------
295  * arp_alloc - Find a free slot or kick out an entry to create one
296  *------------------------------------------------------------------------
297  */
299 {
300  int32 slot; /* Slot in ARP cache */
301 
302  /* Search for a free slot */
303 
304  for (slot=0; slot < ARP_SIZ; slot++) {
305  if (arpcache[slot].arstate == AR_FREE) {
306  memset((char *)&arpcache[slot],
307  NULLCH, sizeof(struct arpentry));
308  return slot;
309  }
310  }
311 
312  /* Search for a resolved entry */
313 
314  for (slot=0; slot < ARP_SIZ; slot++) {
315  if (arpcache[slot].arstate == AR_RESOLVED) {
316  memset((char *)&arpcache[slot],
317  NULLCH, sizeof(struct arpentry));
318  return slot;
319  }
320  }
321 
322  /* At this point, all slots are pending (should not happen) */
323 
324  kprintf("ARP cache size exceeded\n");
325 
326  return SYSERR;
327 }
328 
329 /*------------------------------------------------------------------------
330  * arp_ntoh - Convert ARP packet fields from net to host byte order
331  *------------------------------------------------------------------------
332  */
333 void arp_ntoh(
334  struct arppacket *pktptr
335  )
336 {
337  pktptr->arp_htype = ntohs(pktptr->arp_htype);
338  pktptr->arp_ptype = ntohs(pktptr->arp_ptype);
339  pktptr->arp_op = ntohs(pktptr->arp_op);
340  pktptr->arp_sndpa = ntohl(pktptr->arp_sndpa);
341  pktptr->arp_tarpa = ntohl(pktptr->arp_tarpa);
342 }
343 
344 /*------------------------------------------------------------------------
345  * arp_hton - Convert ARP packet fields from host to net byte order
346  *------------------------------------------------------------------------
347  */
348 void arp_hton(
349  struct arppacket *pktptr
350  )
351 {
352  pktptr->arp_htype = htons(pktptr->arp_htype);
353  pktptr->arp_ptype = htons(pktptr->arp_ptype);
354  pktptr->arp_op = htons(pktptr->arp_op);
355  pktptr->arp_sndpa = htonl(pktptr->arp_sndpa);
356  pktptr->arp_tarpa = htonl(pktptr->arp_tarpa);
357 }
syscall kprintf(char *fmt,...)
ポーリングI/Oを使用して、フォーマットされた文字列をコンソールに出力する。
Definition: kprintf.c:98
#define AR_FREE
ARPキャッシュエントリ状態:スロットが未使用
Definition: arp.h:27
void eth_hton(struct netpacket *)
Definition: net.c:127
#define ARP_PALEN
IPアドレスサイズ
Definition: arp.h:10
uint32 ipucast
Definition: net.h:55
pid32 currpid
現在実行中のプロセス。
Definition: initialize.c:32
unsigned char byte
符号なし8ビット値(unsigned char)
Definition: kernel.h:7
#define ARP_SIZ
キャシュ中のエントリ数
Definition: arp.h:20
void arp_in(struct arppacket *pktptr)
Definition: arp.c:158
byte arp_ethdst[ETH_ADDR_LEN]
Ethernet転送先のMACアドレス
Definition: arp.h:42
void arp_ntoh(struct arppacket *pktptr)
Definition: arp.c:333
void restore(intmask)
byte arp_plen
ARPプロトコルアドレス長さ
Definition: arp.h:54
#define ARP_PTYPE
IPプロトコルタイプ
Definition: arp.h:14
#define IP_BCAST
IPローカルブロードキャストアドレス。
Definition: ip.h:7
struct network NetData
Definition: net.c:6
#define ARP_RETRY
ARPリクエストのリトライ回数
Definition: arp.h:22
全てのシステムヘッダファイルをインクルードする。
#define SYSERR
処理が失敗した場合
Definition: kernel.h:79
void arp_hton(struct arppacket *pktptr)
Definition: arp.c:348
struct arpentry arpcache[ARP_SIZ]
ARPキャッシュエントリテーブル
Definition: arp.c:5
status arp_resolve(uint32 nxthop, byte mac[ETH_ADDR_LEN])
Definition: arp.c:24
byte arp_hlen
ARPハードウェアアドレス長さ
Definition: arp.h:52
void arp_init(void)
Definition: arp.c:11
#define ARP_OP_RPLY
リプライオペコード
Definition: arp.h:18
uint16 arp_ptype
ARPプロトコルタイプ
Definition: arp.h:50
#define OK
処理が成功した場合
Definition: kernel.h:77
syscall send(pid32, umsg32)
プロセスにメッセージを送信し、受信側が待機状態の場合はREADY状態にする。
Definition: send.c:21
byte bool8
Boolean値
Definition: kernel.h:36
#define TIMEOUT
システムコールがタイムアウトした場合
Definition: kernel.h:83
int32 status
ステータスを意味する返り値の型(OK/SYSERR)
Definition: kernel.h:57
#define ARP_TIMEOUT
[ms]毎のリトライタイマ
Definition: arp.h:24
int32 arstate
エントリの状態
Definition: arp.h:75
#define ARP_HTYPE
Ethernetハードウェアタイプ
Definition: arp.h:12
byte arp_sndha[ARP_HALEN]
ARP送信者のEthernetアドレス
Definition: arp.h:58
#define ntohl(x)
Definition: prototypes.h:623
byte ethucast[ETH_ADDR_LEN]
Definition: net.h:64
syscall write(did32, char *, uint32)
Definition: write.c:9
int32 arp_alloc()
Definition: arp.c:298
uint32 arpaddr
エントリのIPアドレス
Definition: arp.h:77
#define FALSE
Boolean False(0)
Definition: kernel.h:63
byte arp_tarha[ARP_HALEN]
ARPターゲットのEthernetアドレス
Definition: arp.h:62
#define TRUE
Boolean True(1)
Definition: kernel.h:65
umsg32 recvclr(void)
受信メッセージをクリアし、待機している場合はメッセージを返す。
Definition: recvclr.c:14
IP&Ethernet用のARPパケットフォーマット
Definition: arp.h:39
#define ARP_HALEN
EthernetのMACアドレスサイズ
Definition: arp.h:8
uint16 arp_ethtype
Ethernetタイプ領域
Definition: arp.h:46
ARPキャッシュエントリ
Definition: arp.h:72
uint32 intmask
保存された割り込みマスク
Definition: kernel.h:38
#define ETH_ARP
Definition: net.h:9
int int32
符号あり32ビット整数(int)
Definition: kernel.h:11
void * memset(void *, const int, int32)
指定のByteブロックに対して、同じ値をNバイト分書き込む。
Definition: memset.c:13
#define ntohs(x)
Definition: prototypes.h:622
byte arhaddr[ARP_HALEN]
エントリのEthernetアドレス
Definition: arp.h:81
uint32 ipbcast
Definition: net.h:56
byte ethbcast[ETH_ADDR_LEN]
Definition: net.h:65
#define ARP_OP_REQ
リクエストオペコード
Definition: arp.h:16
byte arp_ethsrc[ETH_ADDR_LEN]
Ethernet送信元のMACアドレス
Definition: arp.h:44
Definition: net.h:16
#define AR_RESOLVED
ARPキャッシュエントリ状態:エントリが正常
Definition: arp.h:31
syscall freebuf(char *)
バッファプールから取得したバッファを解放する。
Definition: freebuf.c:19
#define ETH_ADDR_LEN
Definition: ether.h:10
uint32 arp_tarpa
ARPターゲットのIPアドレス
Definition: arp.h:64
pid32 arpid
待機中プロセスか-1
Definition: arp.h:79
#define htonl(x)
Definition: prototypes.h:620
umsg32 recvtime(int32)
Definition: recvtime.c:17
unsigned int uint32
符号なし32ビット整数(unsigned int)
Definition: kernel.h:15
#define htons(x)
Definition: prototypes.h:619
#define ETHER0
Definition: conf.h:34
uint16 arp_htype
ARPハードウェアタイプ
Definition: arp.h:48
uint32 arp_sndpa
ARP送信者のIPアドレス
Definition: arp.h:60
#define NULLCH
NULL文字(NULL終端)
Definition: kernel.h:70
void * memcpy(void *, const void *, int32)
メモリAの領域(source)からメモリBの領域(Destination)にN Byteコピーする。
Definition: memcpy.c:13
uint16 arp_op
ARPオペレーション
Definition: arp.h:56
bool8 ipvalid
Definition: net.h:63
intmask disable(void)
割り込み禁止(intr.Sに定義がある)
#define AR_PENDING
ARPキャッシュエントリ状態:解決中
Definition: arp.h:29