/** * Give up an echo reply queue, and flush any loitering packets. */ static int echoQueueDealloc(int echoent) { irqmask im; struct packet *pkt = NULL; struct icmpEchoQueue *eq = NULL; if ((echoent < 0) || (echoent >= NPINGQUEUE)) { return SYSERR; } eq = &echotab[echoent]; im = disable(); eq->tid = BADTID; while (eq->tail != eq->head) { pkt = eq->pkts[eq->tail]; ICMP_TRACE("Discarding ping packet from closed queue %d", echoent); netFreebuf(pkt); eq->tail = (eq->tail + 1) % NPINGHOLD; } restore(im); return OK; }
/** * Send an ICMP Echo (Ping) Request. * @param dst destination address * @param id ping stream identifier * @param seq sequence number * @return OK if packet was sent, otherwise SYSERR */ syscall icmpEchoRequest(struct netaddr *dst, ushort id, ushort seq) { struct packet *pkt = NULL; struct icmpEcho *echo = NULL; int result = OK; irqmask im; ICMP_TRACE("echo request(%d, %d)", id, seq); pkt = netGetbuf(); if (SYSERR == (int)pkt) { ICMP_TRACE("Failed to acquire packet buffer"); return SYSERR; } pkt->len = sizeof(struct icmpEcho); pkt->curr -= pkt->len; echo = (struct icmpEcho *)pkt->curr; echo->id = hs2net(id); echo->seq = hs2net(seq); /* Our optional data payload includes room for the departure */ /* and arrival timestamps, in seconds, milliseconds, and */ /* clock cycles. */ im = disable(); echo->timecyc = hl2net(clkcount()); echo->timetic = hl2net(clkticks); echo->timesec = hl2net(clktime); restore(im); echo->arrivcyc = 0; echo->arrivtic = 0; echo->arrivsec = 0; ICMP_TRACE("Sending Echo Request id = %d, seq = %d, time = %d.%d", net2hs(echo->id), net2hs(echo->seq), net2hl(echo->timesec), net2hl(echo->timetic)); result = icmpSend(pkt, ICMP_ECHO, 0, sizeof(struct icmpEcho), dst); netFreebuf(pkt); return result; }
/** * @ingroup icmp * * Compose ICMP Time Exceeded message. * @param unreached packet that could not be sent * @param code ICMP destination unreachable code number * @return OK if packet was sent, otherwise SYSERR */ syscall icmpTimeExceeded(struct packet *unreached, int code) { struct packet *pkt = NULL; struct ipv4Pkt *ip = NULL; struct netaddr dst; int result = OK; int ihl = 0; ICMP_TRACE("Time exceeded (%d)", code); pkt = netGetbuf(); if (SYSERR == (int)pkt) { ICMP_TRACE("Failed to acquire packet buffer"); return SYSERR; } ip = (struct ipv4Pkt *)unreached->nethdr; dst.type = NETADDR_IPv4; dst.len = IPv4_ADDR_LEN; /* Send error message back to original source. */ memcpy(dst.addr, ip->src, dst.len); ihl = (ip->ver_ihl & IPv4_IHL) * 4; /* Message will contain at least ICMP_DEF_DATALEN */ /* of packet in question, as per RFC 792. */ pkt->len = ihl + ICMP_DEF_DATALEN; pkt->curr -= pkt->len; memcpy(pkt->curr, ip, ihl + ICMP_DEF_DATALEN); /* First four octets of payload are unused. */ pkt->curr -= 4; pkt->len += 4; *((ulong *)pkt->curr) = 0; result = icmpSend(pkt, ICMP_TIMEEXCD, code, pkt->len, &dst); netFreebuf(pkt); return result; }
/** * @ingroup icmp * * Processes an incoming ICMP packet. * @param pkt pointer to the incoming packet * return OK if packet was processed succesfully, otherwise SYSERR */ syscall icmpRecv(struct packet *pkt) { struct icmpPkt *icmp; struct icmpEcho *echo; int id; /* Error check pointers */ if (NULL == pkt) { return SYSERR; } icmp = (struct icmpPkt *)pkt->curr; switch (icmp->type) { case ICMP_ECHOREPLY: ICMP_TRACE("Received Echo Reply"); echo = (struct icmpEcho *)icmp->data; id = net2hs(echo->id); if ((id >= 0) && (id < NTHREAD)) { int i; irqmask im; im = disable(); echo->arrivcyc = clkcount(); echo->arrivtic = clkticks; echo->arrivsec = clktime; for (i = 0; i < NPINGQUEUE; i++) { struct icmpEchoQueue *eq; eq = &echotab[i]; if (id == eq->tid) { ICMP_TRACE("Ping matches queue %d", i); if (((eq->head + 1) % NPINGHOLD) == eq->tail) { ICMP_TRACE("Queue full, discarding"); restore(im); netFreebuf(pkt); return SYSERR; } eq->pkts[eq->head] = pkt; eq->head = ((eq->head + 1) % NPINGHOLD); send(id, (message)pkt); restore(im); return OK; } } restore(im); } ICMP_TRACE("Reply id %d does not correspond to ping queue", id); netFreebuf(pkt); return SYSERR; case ICMP_ECHO: ICMP_TRACE("Enqueued Echo Request for daemon to reply"); mailboxSend(icmpqueue, (int)pkt); return OK; case ICMP_UNREACH: case ICMP_SRCQNCH: case ICMP_REDIRECT: case ICMP_TIMEEXCD: case ICMP_PARAMPROB: case ICMP_TMSTMP: case ICMP_TMSTMPREPLY: case ICMP_INFORQST: case ICMP_INFOREPLY: case ICMP_TRACEROUTE: ICMP_TRACE("ICMP message type %d not handled", icmp->type); break; default: ICMP_TRACE("ICMP message type %d unknown", icmp->type); break; } netFreebuf(pkt); return OK; }