XINU
icmp.c
Go to the documentation of this file.
1 /* icmp.c - icmp_init, icmp_in, icmp_register, icmp_recv, icmp_send, */
2 /* icmp_release, icmp_cksum, icmp_hton, icmp_ntoh */
3 
4 #include <xinu.h>
5 
6 struct icmpentry icmptab[ICMP_SLOTS]; /* Table of processes using ping*/
7 
8 /*------------------------------------------------------------------------
9  * icmp_init - Initialize icmp table
10  *------------------------------------------------------------------------
11  */
12 void icmp_init(void) {
13 
14  int32 i; /* table index */
15 
16  for(i=0; i<ICMP_SLOTS; i++) {
18  }
19  return;
20 }
21 
22 /*------------------------------------------------------------------------
23  * icmp_in - Handle an incoming icmp packet
24  *------------------------------------------------------------------------
25  */
26 void icmp_in(
27  struct netpacket *pkt /* Pointer to incoming packet */
28  )
29 {
30  intmask mask; /* Saved interrupt mask */
31  int32 slot; /* Slot in ICMP table */
32  struct icmpentry *icmptr; /* Pointer to icmptab entry */
33  struct netpacket *replypkt; /* Pointer to reply packet */
34 
35  mask = disable();
36 
37  /* Discard all ICMP messages except ping */
38 
39  if ( (pkt->net_ictype != ICMP_ECHOREPLY) &&
40  (pkt->net_ictype != ICMP_ECHOREQST) ) {
41  freebuf((char *)pkt);
42  restore(mask);
43  return;
44  }
45 
46  /* Handle Echo Request message */
47 
48  if (pkt->net_ictype == ICMP_ECHOREQST) {
49 
50  /* Send echo reply message */
51 
52  replypkt = icmp_mkpkt(pkt->net_ipsrc,ICMP_ECHOREPLY,
53  pkt->net_icident, pkt->net_icseq,
54  (char *) &pkt->net_icdata,
56  if ((int32)replypkt != SYSERR) {
57  ip_enqueue(replypkt);
58  }
59  freebuf((char *)pkt);
60  restore(mask);
61  return;
62  }
63 
64  /* Handle Echo Reply message: verify that ID is valid */
65 
66  slot = pkt->net_icident;
67  if ( (slot < 0) || (slot >= ICMP_SLOTS) ) {
68  freebuf((char *)pkt);
69  restore(mask);
70  return;
71  }
72 
73  /* Verify that slot in table is in use and IP address */
74  /* in incomming packet matches IP address in table */
75 
76  icmptr = &icmptab[slot];
77  if ( (icmptr->icstate == ICMP_FREE) ||
78  (pkt->net_ipsrc != icmptr->icremip) ) {
79  freebuf((char *)pkt); /* discard packet */
80  restore(mask);
81  return;
82  }
83 
84  /* Add packet to queue */
85 
86  icmptr->iccount++;
87  icmptr->icqueue[icmptr->ictail++] = pkt;
88  if (icmptr->ictail >= ICMP_QSIZ) {
89  icmptr->ictail = 0;
90  }
91  if (icmptr->icstate == ICMP_RECV) {
92  icmptr->icstate = ICMP_USED;
93  send (icmptr->icpid, OK);
94  }
95  restore(mask);
96  return;
97 }
98 
99 /*------------------------------------------------------------------------
100  * icmp_register - Register a remote IP address for ping replies
101  *------------------------------------------------------------------------
102  */
104  uint32 remip /* Remote IP address */
105  )
106 {
107  intmask mask; /* Saved interrupt mask */
108  int32 i; /* Index into icmptab */
109  int32 freeslot; /* Index of slot to use */
110  struct icmpentry *icmptr; /* Pointer to icmptab entry */
111 
112  mask = disable();
113 
114  /* Find a free slot in the table */
115 
116  freeslot = -1;
117  for (i=0; i<ICMP_SLOTS; i++) {
118  icmptr = &icmptab[i];
119  if (icmptr->icstate == ICMP_FREE) {
120  if (freeslot == -1) {
121  freeslot = i;
122  }
123  } else if (icmptr->icremip == remip) {
124  restore(mask);
125  return SYSERR; /* Already registered */
126  }
127  }
128  if (freeslot == -1) { /* No free entries in table */
129 
130  restore(mask);
131  return SYSERR;
132  }
133 
134  /* Fill in table entry */
135 
136  icmptr = &icmptab[freeslot];
137  icmptr->icstate = ICMP_USED;
138  icmptr->icremip = remip;
139  icmptr->iccount = 0;
140  icmptr->ichead = icmptr->ictail = 0;
141  icmptr->icpid = -1;
142  restore(mask);
143  return freeslot;
144 }
145 
146 /*------------------------------------------------------------------------
147  * icmp_recv - Receive an icmp echo reply packet
148  *------------------------------------------------------------------------
149  */
151  int32 icmpid, /* ICMP slot identifier */
152  char *buff, /* Buffer to ICMP data */
153  int32 len, /* Length of buffer */
154  uint32 timeout /* Time to wait in msec */
155  )
156 {
157  intmask mask; /* Saved interrupt mask */
158  struct icmpentry *icmptr; /* Pointer to icmptab entry */
159  umsg32 msg; /* Message from recvtime() */
160  struct netpacket *pkt; /* Pointer to packet being read */
161  int32 datalen; /* Length of ICMP data area */
162  char *icdataptr; /* Pointer to icmp data */
163  int32 i; /* Counter for data copy */
164 
165  /* Verify that the ID is valid */
166 
167  if ( (icmpid < 0) || (icmpid >= ICMP_SLOTS) ) {
168  return SYSERR;
169  }
170 
171  /* Insure only one process touches the table at a time */
172 
173  mask = disable();
174 
175  /* Verify that the ID has been registered and is idle */
176 
177  icmptr = &icmptab[icmpid];
178  if (icmptr->icstate != ICMP_USED) {
179  restore(mask);
180  return SYSERR;
181  }
182 
183  if (icmptr->iccount == 0) { /* No packet is waiting */
184  icmptr->icstate = ICMP_RECV;
185  icmptr->icpid = currpid;
186  msg = recvclr();
187  msg = recvtime(timeout); /* Wait for a reply */
188  icmptr->icstate = ICMP_USED;
189  if (msg == TIMEOUT) {
190  restore(mask);
191  return TIMEOUT;
192  } else if (msg != OK) {
193  restore(mask);
194  return SYSERR;
195  }
196  }
197 
198  /* Packet has arrived -- dequeue it */
199 
200  pkt = icmptr->icqueue[icmptr->ichead++];
201  if (icmptr->ichead >= ICMP_SLOTS) {
202  icmptr->ichead = 0;
203  }
204  icmptr->iccount--;
205 
206  /* Copy data from ICMP message into caller's buffer */
207 
208  datalen = pkt->net_iplen - IP_HDR_LEN - ICMP_HDR_LEN;
209  icdataptr = (char *) &pkt->net_icdata;
210  for (i=0; i<datalen; i++) {
211  if (i >= len) {
212  break;
213  }
214  *buff++ = *icdataptr++;
215  }
216  freebuf((char *)pkt);
217  restore(mask);
218  return i;
219 }
220 
221 /*------------------------------------------------------------------------
222  * icmp_send - Send an icmp packet
223  *------------------------------------------------------------------------
224  */
226  uint32 remip, /* Remote IP address to use */
227  uint16 type, /* ICMP type (req. or reply) */
228  uint16 ident, /* ICMP identifier value */
229  uint16 seq, /* ICMP sequence number */
230  char *buf, /* pointer to data buffer */
231  int32 len /* Length of data in buffer */
232  )
233 {
234  intmask mask; /* Saved interrupt mask */
235  struct netpacket *pkt; /* Packet returned by icmp_mkpkt*/
236  int32 retval; /* Value returned by ip_send */
237 
238  mask = disable();
239 
240  /* Form a packet to send */
241 
242  pkt = icmp_mkpkt(remip, type, ident, seq, buf, len);
243  if ((int32)pkt == SYSERR) {
244  return SYSERR;
245  }
246 
247  /* Send the packet */
248 
249  retval = ip_send(pkt);
250  restore(mask);
251  return retval;
252 }
253 
254 
255 /*------------------------------------------------------------------------
256  * icmp_mkpkt - Make an icmp packet by filling in fields
257  *------------------------------------------------------------------------
258  */
260  uint32 remip, /* Remote IP address to use */
261  uint16 type, /* ICMP type (req. or reply) */
262  uint16 ident, /* ICMP identifier value */
263  uint16 seq, /* ICMP sequence number */
264  char *buf, /* Pointer to data buffer */
265  int32 len /* Length of data in buffer */
266  )
267 {
268  struct netpacket *pkt; /* pointer to packet buffer */
269  static uint32 ipident=32767; /* IP ident field */
270 
271  /* Allocate packet */
272 
273  pkt = (struct netpacket *)getbuf(netbufpool);
274 
275  if ((int32)pkt == SYSERR) {
276  panic("icmp_mkpkt: cannot get a network buffer\n");
277  }
278 
279  /* Create icmp packet in pkt */
280 
282  pkt->net_ethtype = 0x800; /* Type is IP */
283  pkt->net_ipvh = 0x45; /* IP version and hdr length */
284  pkt->net_iptos = 0x00; /* Type of service */
285  pkt->net_iplen= IP_HDR_LEN+ICMP_HDR_LEN+len;/* datagram length */
286  pkt->net_ipid = ipident++; /* Datagram gets next IDENT */
287  pkt->net_ipfrag = 0x0000; /* IP flags & fragment offset */
288  pkt->net_ipttl = 0xff; /* IP time-to-live */
289  pkt->net_ipproto = IP_ICMP; /* Datagram carries icmp */
290  pkt->net_ipcksum = 0x0000; /* Initial checksum */
291  pkt->net_ipsrc = NetData.ipucast; /* IP source address */
292  pkt->net_ipdst = remip; /* IP destination address */
293 
294 
295  pkt->net_ictype = type; /* ICMP type */
296  pkt->net_iccode = 0; /* Code is zero for ping */
297  pkt->net_iccksum = 0x0000; /* Temporarily zero the cksum */
298  pkt->net_icident = ident; /* ICMP identification */
299  pkt->net_icseq = seq; /* ICMP sequence number */
300  memcpy(pkt->net_icdata, buf, len);
301 
302  /* Return packet to caller */
303 
304  return pkt;
305 }
306 
307 
308 /*------------------------------------------------------------------------
309  * icmp_release - Release a previously-registered ICMP icmpid
310  *------------------------------------------------------------------------
311  */
313  int32 icmpid /* Slot in icmptab to release */
314  )
315 {
316  intmask mask; /* Saved interrupt mask */
317  struct icmpentry *icmptr; /* Pointer to icmptab entry */
318  struct netpacket *pkt; /* Pointer to packet */
319 
320  mask = disable();
321 
322  /* Check arg and insure entry in table is in use */
323 
324  if ( (icmpid < 0) || (icmpid >= ICMP_SLOTS) ) {
325  restore(mask);
326  return SYSERR;
327  }
328  icmptr = &icmptab[icmpid];
329  if (icmptr->icstate != ICMP_USED) {
330  restore(mask);
331  return SYSERR;
332  }
333 
334  /* Remove each packet from the queue and free the buffer */
335 
337  while (icmptr->iccount > 0) {
338  pkt = icmptr->icqueue[icmptr->ichead++];
339  if (icmptr->ichead >= ICMP_SLOTS) {
340  icmptr->ichead = 0;
341 
342  }
343  freebuf((char *)pkt);
344  icmptr->iccount--;
345  }
346 
347  /* Mark the entry free */
348 
349  icmptr->icstate = ICMP_FREE;
351  restore(mask);
352  return OK;
353 }
354 
355 /*------------------------------------------------------------------------
356  * icmp_cksum - Compute a checksum for a specified set of data bytes
357  *------------------------------------------------------------------------
358  */
360  char *buf, /* Buffer of items for checksum */
361  int32 buflen /* Size of buffer in bytes */
362  )
363 {
364  int32 scount; /* Number of 16-bit values buf */
365  uint32 cksum; /* Checksum being computed */
366  uint16 *sptr; /* Walks along buffer */
367  uint16 word; /* One 16-bit word */
368 
369  /* Walk along buffer and sum all 16-bit values */
370 
371  scount = buflen >> 1; /* Divide by 2 and round down */
372  sptr = (uint16 *)buf;
373  cksum = 0;
374  for (; scount > 0; scount--) {
375  word = (uint32) *sptr++;
376  cksum += ntohs(word);
377  }
378 
379  /* If buffer lenght is odd, add last byte */
380 
381  if ( (buflen & 0x01) !=0 ) {
382  cksum += 0xFFFF & ((uint32) (*((byte *) sptr) << 8));
383  }
384  cksum += (cksum >> 16);
385  cksum = 0xffff & ~cksum;
386  return (uint16) (0xffff & cksum);
387 }
388 
389 
390 /*------------------------------------------------------------------------
391  * icmp_hton - Convert ICMP ping fields to network byte order
392  *------------------------------------------------------------------------
393  */
394 void icmp_hton (
395  struct netpacket *pktptr
396  )
397 {
398  pktptr->net_iccksum = htons(pktptr->net_iccksum);
399  pktptr->net_icident = htons(pktptr->net_icident);
400  pktptr->net_icseq = htons(pktptr->net_icseq);
401 }
402 
403 
404 /*------------------------------------------------------------------------
405  * icmp_ntoh - Convert ICMP ping fields to host byte order
406  *------------------------------------------------------------------------
407  */
408 void icmp_ntoh (
409  struct netpacket *pktptr
410  )
411 {
412  pktptr->net_iccksum = ntohs(pktptr->net_iccksum);
413  pktptr->net_icident = ntohs(pktptr->net_icident);
414  pktptr->net_icseq = ntohs(pktptr->net_icseq);
415 }
byte net_ictype
Definition: net.h:39
#define ICMP_RECV
Definition: icmp.h:10
uint32 ipucast
Definition: net.h:55
struct netpacket * icmp_mkpkt(uint32 remip, uint16 type, uint16 ident, uint16 seq, char *buf, int32 len)
Definition: icmp.c:259
pid32 currpid
現在実行中のプロセス。
Definition: initialize.c:32
unsigned char byte
符号なし8ビット値(unsigned char)
Definition: kernel.h:7
void icmp_init(void)
Definition: icmp.c:12
uint16 net_ethtype
Definition: net.h:19
void restore(intmask)
struct icmpentry icmptab[ICMP_SLOTS]
Definition: icmp.c:6
uint16 net_iccksum
Definition: net.h:41
struct network NetData
Definition: net.c:6
#define ICMP_ECHOREQST
Definition: icmp.h:17
全てのシステムヘッダファイルをインクルードする。
#define SYSERR
処理が失敗した場合
Definition: kernel.h:79
uint16 net_ipid
Definition: net.h:23
struct netpacket * icqueue[ICMP_QSIZ]
Definition: icmp.h:28
uint32 icremip
Definition: icmp.h:23
uint16 net_ipfrag
Definition: net.h:24
#define IP_HDR_LEN
IPヘッダのバイト数。
Definition: ip.h:20
#define ICMP_SLOTS
Definition: icmp.h:3
#define ICMP_ECHOREPLY
Definition: icmp.h:16
#define OK
処理が成功した場合
Definition: kernel.h:77
syscall send(pid32, umsg32)
プロセスにメッセージを送信し、受信側が待機状態の場合はREADY状態にする。
Definition: send.c:21
byte net_ethsrc[ETH_ADDR_LEN]
Definition: net.h:18
uint16 net_iplen
Definition: net.h:22
#define TIMEOUT
システムコールがタイムアウトした場合
Definition: kernel.h:83
int32 status
ステータスを意味する返り値の型(OK/SYSERR)
Definition: kernel.h:57
byte net_iccode
Definition: net.h:40
byte net_icdata[1500-28]
Definition: net.h:44
#define ICMP_QSIZ
Definition: icmp.h:4
#define IP_ICMP
IP向けのICMPプロトコルタイプ
Definition: ip.h:14
uint32 umsg32
プロセス間で渡されるメッセージ
Definition: kernel.h:32
Definition: icmp.h:21
int32 ictail
Definition: icmp.h:25
status resched_cntl(int32)
再スケジューリングを延期させるか、もしくは許可させるかを制御する。
Definition: resched.c:81
int32 icstate
Definition: icmp.h:22
byte ethucast[ETH_ADDR_LEN]
Definition: net.h:64
uint16 icmp_cksum(char *buf, int32 buflen)
Definition: icmp.c:359
int32 icmp_recv(int32 icmpid, char *buff, int32 len, uint32 timeout)
Definition: icmp.c:150
void icmp_ntoh(struct netpacket *pktptr)
Definition: icmp.c:408
#define ICMP_FREE
Definition: icmp.h:8
uint16 net_icseq
Definition: net.h:43
umsg32 recvclr(void)
受信メッセージをクリアし、待機している場合はメッセージを返す。
Definition: recvclr.c:14
#define DEFER_STOP
遅延リスケジューリングの停止
Definition: resched.h:10
int32 ichead
Definition: icmp.h:24
uint32 intmask
保存された割り込みマスク
Definition: kernel.h:38
#define DEFER_START
遅延リスケジューリングの開始
Definition: resched.h:8
int int32
符号あり32ビット整数(int)
Definition: kernel.h:11
uint16 net_ipcksum
Definition: net.h:27
#define ICMP_USED
Definition: icmp.h:9
int32 iccount
Definition: icmp.h:26
int32 icmp_register(uint32 remip)
Definition: icmp.c:103
bpid32 netbufpool
Definition: net.c:7
unsigned short uint16
符号なし16ビット整数(unsigned short)
Definition: kernel.h:17
#define ntohs(x)
Definition: prototypes.h:622
char * getbuf(bpid32)
事前に確保されたバッファプールからバッファを取得する。
Definition: getbuf.c:19
byte net_iptos
Definition: net.h:21
Definition: net.h:16
byte net_ipvh
Definition: net.h:20
void panic(char *)
Panic状態に陥った旨のメッセージを表示し、全てのプロセスを停止させる。
Definition: panic.c:12
uint32 net_ipsrc
Definition: net.h:28
pid32 icpid
Definition: icmp.h:27
uint32 net_ipdst
Definition: net.h:29
void icmp_hton(struct netpacket *pktptr)
Definition: icmp.c:394
status icmp_release(int32 icmpid)
Definition: icmp.c:312
syscall freebuf(char *)
バッファプールから取得したバッファを解放する。
Definition: freebuf.c:19
status icmp_send(uint32 remip, uint16 type, uint16 ident, uint16 seq, char *buf, int32 len)
Definition: icmp.c:225
#define ICMP_HDR_LEN
Definition: icmp.h:12
uint16 net_icident
Definition: net.h:42
status ip_enqueue(struct netpacket *)
Definition: ip.c:439
status ip_send(struct netpacket *)
Definition: ip.c:103
#define ETH_ADDR_LEN
Definition: ether.h:10
byte net_ipproto
Definition: net.h:26
byte net_ipttl
Definition: net.h:25
umsg32 recvtime(int32)
Definition: recvtime.c:17
unsigned int uint32
符号なし32ビット整数(unsigned int)
Definition: kernel.h:15
#define htons(x)
Definition: prototypes.h:619
void * memcpy(void *, const void *, int32)
メモリAの領域(source)からメモリBの領域(Destination)にN Byteコピーする。
Definition: memcpy.c:13
void icmp_in(struct netpacket *pkt)
Definition: icmp.c:26
intmask disable(void)
割り込み禁止(intr.Sに定義がある)