XINU
ip.c
Go to the documentation of this file.
1 /* ip.c - ip_in, ip_send, ip_local, ip_out, ipcksum, ip_hton, ip_ntoh, */
2 /* ipout, ip_enqueue */
3 
4 #include <xinu.h>
5 
6 struct iqentry ipoqueue; /* Queue of outgoing packets */
7 
8 /*------------------------------------------------------------------------
9  * ip_in - Handle an IP packet that has arrived over a network
10  *------------------------------------------------------------------------
11  */
12 
13 void ip_in(
14  struct netpacket *pktptr /* Pointer to the packet */
15  )
16 {
17  int32 icmplen; /* Length of ICMP message */
18 
19  /* Verify checksum */
20 
21  if (ipcksum(pktptr) != 0) {
22  kprintf("IP header checksum failed\n\r");
23  freebuf((char *)pktptr);
24  return;
25  }
26 
27  /* Convert IP header fields to host order */
28 
29  ip_ntoh(pktptr);
30 
31  /* Ensure version and length are valid */
32 
33  if (pktptr->net_ipvh != 0x45) {
34  kprintf("IP version failed\n\r");
35  freebuf((char *)pktptr);
36  return;
37  }
38 
39  /* Verify encapsulated prototcol checksums and then convert */
40  /* the encapsulated headers to host byte order */
41 
42  switch (pktptr->net_ipproto) {
43 
44  case IP_UDP:
45  /* Skipping UDP checksum for now */
46  udp_ntoh(pktptr);
47  break;
48 
49  case IP_ICMP:
50  icmplen = pktptr->net_iplen - IP_HDR_LEN;
51  if (icmp_cksum((char *)&pktptr->net_ictype,icmplen) != 0){
52  freebuf((char *)pktptr);
53  return;
54  }
55  icmp_ntoh(pktptr);
56  break;
57 
58  default:
59  break;
60  }
61 
62  /* Deliver 255.255.255.255 to local stack */
63 
64  if (pktptr->net_ipdst == IP_BCAST) {
65  ip_local(pktptr);
66  return;
67  }
68 
69  /* If we do not yet have a valid address, accept UDP packets */
70  /* (to get DHCP replies) and drop others */
71 
72  if (!NetData.ipvalid) {
73  if (pktptr->net_ipproto == IP_UDP) {
74  ip_local(pktptr);
75  return;
76  } else {
77  freebuf((char *)pktptr);
78  return;
79  }
80  }
81 
82  /* If packet is destined for us, accept it; otherwise, drop it */
83 
84  if ( (pktptr->net_ipdst == NetData.ipucast) ||
85  (pktptr->net_ipdst == NetData.ipbcast) ||
86  (pktptr->net_ipdst == IP_BCAST) ) {
87  ip_local(pktptr);
88  return;
89  } else {
90 
91  /* Drop the packet */
92  freebuf((char *)pktptr);
93  return;
94  }
95 }
96 
97 
98 /*------------------------------------------------------------------------
99  * ip_send - Send an outgoing IP datagram from the local stack
100  *------------------------------------------------------------------------
101  */
102 
104  struct netpacket *pktptr /* Pointer to the packet */
105  )
106 {
107  intmask mask; /* Saved interrupt mask */
108  uint32 dest; /* Destination of the datagram */
109  int32 retval; /* Return value from functions */
110  uint32 nxthop; /* Next-hop address */
111 
112  mask = disable();
113 
114  /* Pick up the IP destination address from the packet */
115 
116  dest = pktptr->net_ipdst;
117 
118  /* Loop back to local stack if destination 127.0.0.0/8 */
119 
120  if ((dest&0xff000000) == 0x7f000000) {
121  ip_local(pktptr);
122  restore(mask);
123  return OK;
124  }
125 
126  /* Loop back if the destination matches our IP unicast address */
127 
128  if (dest == NetData.ipucast) {
129  ip_local(pktptr);
130  restore(mask);
131  return OK;
132  }
133 
134  /* Broadcast if destination is 255.255.255.255 */
135 
136  if ( (dest == IP_BCAST) ||
137  (dest == NetData.ipbcast) ) {
139  ETH_ADDR_LEN);
140  retval = ip_out(pktptr);
141  restore(mask);
142  return retval;
143  }
144 
145  /* If destination is on the local network, next hop is the */
146  /* destination; otherwise, next hop is default router */
147 
148 
149  if ( (dest & NetData.ipmask) == NetData.ipprefix) {
150 
151  /* Next hop is the destination itself */
152  nxthop = dest;
153 
154  } else {
155 
156  /* Next hop is default router on the network */
157  nxthop = NetData.iprouter;
158 
159  }
160 
161  if (nxthop == 0) { /* Dest. invalid or no default route */
162  freebuf((char *)pktptr);
163  return SYSERR;
164  }
165 
166  /* Resolve the next-hop address to get a MAC address */
167 
168  retval = arp_resolve(nxthop, pktptr->net_ethdst);
169  if (retval != OK) {
170  freebuf((char *)pktptr);
171  return SYSERR;
172  }
173 
174  /* Send the packet */
175 
176  retval = ip_out(pktptr);
177  restore(mask);
178  return retval;
179 }
180 
181 
182 /*------------------------------------------------------------------------
183  * ip_local - Deliver an IP datagram to the local stack
184  *------------------------------------------------------------------------
185  */
186 void ip_local(
187  struct netpacket *pktptr /* Pointer to the packet */
188  )
189 {
190  /* Use datagram contents to determine how to process */
191 
192  switch (pktptr->net_ipproto) {
193 
194  case IP_UDP:
195  udp_in(pktptr);
196  return;
197 
198  case IP_ICMP:
199  icmp_in(pktptr);
200  return;
201 
202  default:
203  freebuf((char *)pktptr);
204  return;
205  }
206 }
207 
208 
209 /*------------------------------------------------------------------------
210  * ip_out - Transmit an outgoing IP datagram
211  *------------------------------------------------------------------------
212  */
214  struct netpacket *pktptr /* Pointer to the packet */
215  )
216 {
217  uint16 cksum; /* Checksum in host byte order */
218  int32 len; /* Length of ICMP message */
219  int32 pktlen; /* Length of entire packet */
220  int32 retval; /* Value returned by write */
221 
222  /* Compute total packet length */
223 
224  pktlen = pktptr->net_iplen + ETH_HDR_LEN;
225 
226  /* Convert encapsulated protocol to network byte order */
227 
228  switch (pktptr->net_ipproto) {
229 
230  case IP_UDP:
231 
232  pktptr->net_udpcksum = 0;
233  udp_hton(pktptr);
234 
235  /* ...skipping UDP checksum computation */
236 
237  break;
238 
239  case IP_ICMP:
240  icmp_hton(pktptr);
241 
242  /* Compute ICMP checksum */
243 
244  pktptr->net_iccksum = 0;
245  len = pktptr->net_iplen-IP_HDR_LEN;
246  cksum = icmp_cksum((char *)&pktptr->net_ictype,
247  len);
248  pktptr->net_iccksum = 0xffff & htons(cksum);
249  break;
250 
251  default:
252  break;
253  }
254 
255  /* Convert IP fields to network byte order */
256 
257  ip_hton(pktptr);
258 
259  /* Compute IP header checksum */
260 
261  pktptr->net_ipcksum = 0;
262  cksum = ipcksum(pktptr);
263  pktptr->net_ipcksum = 0xffff & htons(cksum);
264 
265  /* Convert Ethernet fields to network byte order */
266 
267  eth_hton(pktptr);
268 
269  /* Send packet over the Ethernet */
270 
271  retval = write(ETHER0, (char*)pktptr, pktlen);
272  freebuf((char *)pktptr);
273 
274  if (retval == SYSERR) {
275  return SYSERR;
276  } else {
277  return OK;
278  }
279 }
280 
281 /*------------------------------------------------------------------------
282  * ipcksum - Compute the IP header checksum for a datagram
283  *------------------------------------------------------------------------
284  */
285 
287  struct netpacket *pkt /* Pointer to the packet */
288  )
289 {
290  uint16 *hptr; /* Ptr to 16-bit header values */
291  int32 i; /* Counts 16-bit values in hdr */
292  uint16 word; /* One 16-bit word */
293  uint32 cksum; /* Computed value of checksum */
294 
295  hptr= (uint16 *) &pkt->net_ipvh;
296 
297  /* Sum 16-bit words in the packet */
298 
299  cksum = 0;
300  for (i=0; i<10; i++) {
301  word = *hptr++;
302  cksum += (uint32) htons(word);
303  }
304 
305  /* Add in carry, and take the ones-complement */
306 
307  cksum += (cksum >> 16);
308  cksum = 0xffff & ~cksum;
309 
310  /* Use all-1s for zero */
311 
312  if (cksum == 0xffff) {
313  cksum = 0;
314  }
315  return (uint16) (0xffff & cksum);
316 }
317 
318 
319 /*------------------------------------------------------------------------
320  * ip_ntoh - Convert IP header fields to host byte order
321  *------------------------------------------------------------------------
322  */
323 void ip_ntoh(
324  struct netpacket *pktptr
325  )
326 {
327  pktptr->net_iplen = ntohs(pktptr->net_iplen);
328  pktptr->net_ipid = ntohs(pktptr->net_ipid);
329  pktptr->net_ipfrag = ntohs(pktptr->net_ipfrag);
330  pktptr->net_ipsrc = ntohl(pktptr->net_ipsrc);
331  pktptr->net_ipdst = ntohl(pktptr->net_ipdst);
332 }
333 
334 /*------------------------------------------------------------------------
335  * ip_hton - Convert IP header fields to network byte order
336  *------------------------------------------------------------------------
337  */
338 void ip_hton(
339  struct netpacket *pktptr
340 
341  )
342 {
343  pktptr->net_iplen = htons(pktptr->net_iplen);
344  pktptr->net_ipid = htons(pktptr->net_ipid);
345  pktptr->net_ipfrag = htons(pktptr->net_ipfrag);
346  pktptr->net_ipsrc = htonl(pktptr->net_ipsrc);
347  pktptr->net_ipdst = htonl(pktptr->net_ipdst);
348 }
349 
350 
351 /*------------------------------------------------------------------------
352  * ipout - Process that transmits IP packets from the IP output queue
353  *------------------------------------------------------------------------
354  */
355 
357 {
358  struct netpacket *pktptr; /* Pointer to next the packet */
359  struct iqentry *ipqptr; /* Pointer to IP output queue */
360  uint32 destip; /* Destination IP address */
361  uint32 nxthop; /* Next hop IP address */
362  int32 retval; /* Value returned by functions */
363 
364  ipqptr = &ipoqueue;
365 
366  while(1) {
367 
368  /* Obtain next packet from the IP output queue */
369 
370  wait(ipqptr->iqsem);
371  pktptr = ipqptr->iqbuf[ipqptr->iqhead++];
372  if (ipqptr->iqhead >= IP_OQSIZ) {
373  ipqptr->iqhead= 0;
374  }
375 
376  /* Fill in the MAC source address */
377 
379 
380  /* Extract destination address from packet */
381 
382  destip = pktptr->net_ipdst;
383 
384 
385  /* Sanity check: packets sent to ipout should *not* */
386  /* contain a broadcast address. */
387 
388  if ((destip == IP_BCAST)||(destip == NetData.ipbcast)) {
389  kprintf("ipout: encountered a broadcast\n");
390  freebuf((char *)pktptr);
391  continue;
392  }
393 
394  /* Check whether destination is the local computer */
395 
396  if (destip == NetData.ipucast) {
397  ip_local(pktptr);
398  continue;
399  }
400 
401  /* Check whether destination is on the local net */
402 
403  if ( (destip & NetData.ipmask) == NetData.ipprefix) {
404 
405  /* Next hop is the destination itself */
406 
407  nxthop = destip;
408  } else {
409 
410  /* Next hop is default router on the network */
411 
412  nxthop = NetData.iprouter;
413  }
414 
415  if (nxthop == 0) { /* Dest. invalid or no default route*/
416  freebuf((char *)pktptr);
417  continue;
418  }
419 
420  /* Use ARP to resolve next-hop address */
421 
422  retval = arp_resolve(nxthop, pktptr->net_ethdst);
423  if (retval != OK) {
424  freebuf((char *)pktptr);
425  continue;
426  }
427 
428  /* Use ipout to Convert byte order and send */
429 
430  ip_out(pktptr);
431  }
432 }
433 
434 
435 /*------------------------------------------------------------------------
436  * ip_enqueue - Deposit an outgoing IP datagram on the IP output queue
437  *------------------------------------------------------------------------
438  */
440  struct netpacket *pktptr /* Pointer to the packet */
441  )
442 {
443  intmask mask; /* Saved interrupt mask */
444  struct iqentry *iptr; /* Ptr. to network output queue */
445 
446  /* Ensure only one process accesses output queue at a time */
447 
448  mask = disable();
449 
450  /* Enqueue packet on network output queue */
451 
452  iptr = &ipoqueue;
453  if (semcount(iptr->iqsem) >= IP_OQSIZ) {
454  kprintf("ipout: output queue overflow\n");
455  freebuf((char *)pktptr);
456  restore(mask);
457  return SYSERR;
458  }
459  iptr->iqbuf[iptr->iqtail++] = pktptr;
460  if (iptr->iqtail >= IP_OQSIZ) {
461  iptr->iqtail = 0;
462  }
463  signal(iptr->iqsem);
464  restore(mask);
465  return OK;
466 }
syscall kprintf(char *fmt,...)
ポーリングI/Oを使用して、フォーマットされた文字列をコンソールに出力する。
Definition: kprintf.c:98
#define IP_UDP
IP向けのUDPプロトコルタイプ
Definition: ip.h:16
syscall semcount(sid32)
セマフォのカウント値を返す。
Definition: semcount.c:18
uint16 net_udpcksum
Definition: net.h:35
void eth_hton(struct netpacket *)
Definition: net.c:127
byte net_ictype
Definition: net.h:39
uint32 ipucast
Definition: net.h:55
uint32 ipmask
Definition: net.h:57
void restore(intmask)
void ip_local(struct netpacket *pktptr)
Definition: ip.c:186
#define IP_OQSIZ
IPアウトプットキューのサイズ
Definition: ip.h:24
uint16 net_iccksum
Definition: net.h:41
sid32 iqsem
パケット(pkts)をカウントするセマフォ
Definition: ip.h:37
#define IP_BCAST
IPローカルブロードキャストアドレス。
Definition: ip.h:7
struct network NetData
Definition: net.c:6
void ip_ntoh(struct netpacket *pktptr)
Definition: ip.c:323
全てのシステムヘッダファイルをインクルードする。
#define SYSERR
処理が失敗した場合
Definition: kernel.h:79
byte net_ethdst[ETH_ADDR_LEN]
Definition: net.h:17
uint16 net_ipid
Definition: net.h:23
struct netpacket * iqbuf[IP_OQSIZ]
循環パケットキュー
Definition: ip.h:39
void icmp_ntoh(struct netpacket *)
Definition: icmp.c:408
uint16 net_ipfrag
Definition: net.h:24
#define IP_HDR_LEN
IPヘッダのバイト数。
Definition: ip.h:20
void ip_hton(struct netpacket *pktptr)
Definition: ip.c:338
#define OK
処理が成功した場合
Definition: kernel.h:77
struct iqentry ipoqueue
ネットワーク送信キュー
Definition: ip.c:6
byte net_ethsrc[ETH_ADDR_LEN]
Definition: net.h:18
int32 iqhead
次に送信するパケットのインデックス
Definition: ip.h:33
uint16 net_iplen
Definition: net.h:22
int32 status
ステータスを意味する返り値の型(OK/SYSERR)
Definition: kernel.h:57
void ip_in(struct netpacket *pktptr)
Definition: ip.c:13
#define IP_ICMP
IP向けのICMPプロトコルタイプ
Definition: ip.h:14
uint16 icmp_cksum(char *, int32)
Definition: icmp.c:359
void udp_ntoh(struct netpacket *)
Definition: udp.c:553
#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
uint16 ipcksum(struct netpacket *pkt)
Definition: ip.c:286
void icmp_in(struct netpacket *)
Definition: icmp.c:26
status ip_enqueue(struct netpacket *pktptr)
Definition: ip.c:439
uint32 iprouter
Definition: net.h:59
status ip_out(struct netpacket *pktptr)
Definition: ip.c:213
uint32 intmask
保存された割り込みマスク
Definition: kernel.h:38
int int32
符号あり32ビット整数(int)
Definition: kernel.h:11
uint16 net_ipcksum
Definition: net.h:27
status ip_send(struct netpacket *pktptr)
Definition: ip.c:103
unsigned short uint16
符号なし16ビット整数(unsigned short)
Definition: kernel.h:17
#define ntohs(x)
Definition: prototypes.h:622
uint32 ipprefix
Definition: net.h:58
uint32 ipbcast
Definition: net.h:56
void udp_hton(struct netpacket *)
Definition: udp.c:567
#define ETH_HDR_LEN
Definition: ether.h:22
byte ethbcast[ETH_ADDR_LEN]
Definition: net.h:65
ipout(IP送信)プロセスを待機している送信用IPパケットのキュー
Definition: ip.h:30
Definition: net.h:16
byte net_ipvh
Definition: net.h:20
uint32 net_ipsrc
Definition: net.h:28
uint32 net_ipdst
Definition: net.h:29
syscall freebuf(char *)
バッファプールから取得したバッファを解放する。
Definition: freebuf.c:19
status arp_resolve(uint32, byte[])
#define ETH_ADDR_LEN
Definition: ether.h:10
byte net_ipproto
Definition: net.h:26
syscall wait(sid32)
Definition: wait.c:9
syscall signal(sid32)
セマフォにシグナルを送り、待機プロセスがある場合は解除する。
Definition: signal.c:18
int32 iqtail
次の空きスロットのインデックス。
Definition: ip.h:35
void udp_in(struct netpacket *)
Definition: udp.c:29
#define htonl(x)
Definition: prototypes.h:620
unsigned int uint32
符号なし32ビット整数(unsigned int)
Definition: kernel.h:15
#define htons(x)
Definition: prototypes.h:619
#define ETHER0
Definition: conf.h:34
void icmp_hton(struct netpacket *)
Definition: icmp.c:394
void * memcpy(void *, const void *, int32)
メモリAの領域(source)からメモリBの領域(Destination)にN Byteコピーする。
Definition: memcpy.c:13
process ipout(void)
Definition: ip.c:356
bool8 ipvalid
Definition: net.h:63
intmask disable(void)
割り込み禁止(intr.Sに定義がある)
int32 process
プロセスの最上位レベル関数 返り値の型
Definition: kernel.h:53