Example #1
0
static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
			       struct mv88e6xxx_port_hwtstamp *ps,
			       struct sk_buff *skb, u16 reg,
			       struct sk_buff_head *rxq)
{
	u16 buf[4] = { 0 }, status, seq_id;
	struct skb_shared_hwtstamps *shwt;
	struct sk_buff_head received;
	u64 ns, timelo, timehi;
	unsigned long flags;
	int err;

	/* The latched timestamp belongs to one of the received frames. */
	__skb_queue_head_init(&received);
	spin_lock_irqsave(&rxq->lock, flags);
	skb_queue_splice_tail_init(rxq, &received);
	spin_unlock_irqrestore(&rxq->lock, flags);

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
				      reg, buf, ARRAY_SIZE(buf));
	mutex_unlock(&chip->reg_lock);
	if (err)
		pr_err("failed to get the receive time stamp\n");

	status = buf[0];
	timelo = buf[1];
	timehi = buf[2];
	seq_id = buf[3];

	if (status & MV88E6XXX_PTP_TS_VALID) {
		mutex_lock(&chip->reg_lock);
		err = mv88e6xxx_port_ptp_write(chip, ps->port_id, reg, 0);
		mutex_unlock(&chip->reg_lock);
		if (err)
			pr_err("failed to clear the receive status\n");
	}
	/* Since the device can only handle one time stamp at a time,
	 * we purge any extra frames from the queue.
	 */
	for ( ; skb; skb = __skb_dequeue(&received)) {
		if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
			ns = timehi << 16 | timelo;

			mutex_lock(&chip->reg_lock);
			ns = timecounter_cyc2time(&chip->tstamp_tc, ns);
			mutex_unlock(&chip->reg_lock);
			shwt = skb_hwtstamps(skb);
			memset(shwt, 0, sizeof(*shwt));
			shwt->hwtstamp = ns_to_ktime(ns);
			status &= ~MV88E6XXX_PTP_TS_VALID;
		}
		netif_rx_ni(skb);
	}
}
Example #2
0
/**
* @brief Generate score vector and dispatch to parse_sam.c
*
* @param gd global_densities_t to be filled
* @param user_args Pointer to seq_block_t struct holding the results from parsing
* @param bam_file samfile_t structure holding the header
* @param ft Filter previously set by set_filter()
* @return void
* @details Loops through chromosomes in the header and generates a score vector for each. Dispatch vector to parse_sam.c and digests and filters the return values.
* @note
* @todo nothing
*/
void write_density(global_densities_t * gd,user_arguments_t * user_args,samfile_t *bam_file,filter_t * ft){
	int *l_indp,*gen_indp,scount_ind,filter_index=-1,first_call=1;
    uint32_t chrom_tid=0,tid_vector=0,maxscores=0,cc=0,*lstart_ind,*lend_ind,*proc_chrom;
	usersize *cptr,*scoresp;//should be user defined

	time_t start,stop;
	seq_block_t bresults;
	SEXP scores,l_ind,gen_ind;
	chromosome_size_t cs={0};//here are all the limits for a chromosome

	proc_chrom=Calloc(bam_file->header->n_targets,uint32_t);
	bresults=seq_density(NULL,NULL,NULL,user_args,&cs,bam_file,&first_call);//fetch first read

	copy2globals(gd,&bresults);
	chrom_tid=bresults.chrom_index_next;
	if(user_args->VERBOSE>0)printStatus(bam_file->header->target_name[chrom_tid], &cc, bam_file->header->n_targets);

	while(bresults.file_status>0 && chrom_tid<bam_file->header->n_targets){//loop through chromosomes and fetch densities
		if(user_args->VERBOSE>0)printStatus(bam_file->header->target_name[chrom_tid], &cc, bam_file->header->n_targets);

    	time(&start);

		cs.min_pos=0;//start position first read
		cs.max_pos=bam_file->header->target_len[chrom_tid]+1;//+1 for 0 based sources

		cs.min_scorespace=cs.max_pos+user_args->EXTEND;//expect maximally this amount of values in resulting vector - will be refined after scanning the bam
		gd->gsize+=cs.min_scorespace;//calculate total amount of genomic region covered [spanning first read to last read]
		//the average read size is set to only 30 to be on the safe side
		cs.min_indexspace = cs.min_scorespace/(user_args->COMPRESSION+30);
		if(cs.min_indexspace<50)cs.min_indexspace=1000;//leave some space for testing

		#if verbose==1
			printf("\nSTATUS %d\n",bresults.file_status);
			printf("TID+1 %d <= TE %d\n",chrom_tid+1,bam_file->header->n_targets);
			printf("Index Preallocated for %s: %d Scores Preallocated: %d | TID: %d CC: %d\n",bam_file->header->target_name[chrom_tid],cs.min_indexspace,cs.max_pos,chrom_tid,cc);
		#endif
		cptr = Calloc(cs.max_pos+1,usersize);
		lstart_ind=Calloc(cs.min_indexspace,uint32_t);
		lend_ind=Calloc(cs.min_indexspace,uint32_t);

		bresults=seq_density(cptr,lstart_ind,lend_ind,user_args,&cs,bam_file,&first_call);//check if EOF -> status==0)

		if(user_args->FILTER){//skip chromosome in case its not found in filter sequences
			filter_index=seq_match(bam_file->header->target_name[chrom_tid],ft);//is the current chromosome in the filter list? If yes return filter index
			if(filter_index<0){
				time(&stop);
				chrom_tid=bresults.chrom_index_next;
				copy2globals(gd,&bresults);
				destroy_scores(cptr,lstart_ind,lend_ind);
				continue;
			}

			maxscores=bam_file->header->target_len[chrom_tid];//maximal chromosomal position
			cs.min_scorespace=filter_coverage(filter_index,ft);//override scorespace by bps covered by the filter
			cs.min_indexspace=ft->value_length[filter_index]/2;//override index space allocation
		}
		proc_chrom[chrom_tid]=1;//memorize which chromosomes where processed

		if(bresults.file_status<-5)warning("Error. Return value: %d\n",bresults.file_status);
		if(bresults.file_status==-5)warning("bam file doesn\'t appear to be sorted!");
		if(bresults.file_status<0){
			destroy_scores(cptr,lstart_ind,lend_ind);
			break;
		}

		#if verbose==1
		printf("SCAN MEM ALLOCATED: %ldMB\n",((sizeof(usersize)*cs.max_pos)+(2*cs.min_indexspace*sizeof(uint32_t)))/1000000);
		printf("RETURN VALUE %d\n",bresults.file_status);
		printf("R VECTOR ALLOCATION SIZE/LENGTH: %dMB / %d\n",(sizeof(usersize)*cs.min_scorespace)/1000000,sizeof(usersize)*cs.min_scorespace);
		printf("R VECTOR INDEX ALLOCATION SIZE/LENGTH: %dMB / %d\n",(4*(cs.min_indexspace+1))/1000000,cs.min_indexspace+1);
		printf("%d LOW QUALITY READS SKIPPED\n",bresults.lowqual);
		#endif

		cs.min_scorespace++;
		cs.min_scorespace=cs.min_scorespace/(4/sizeof(usersize));//Only half the space needed with uint16_t
		PROTECT(scores = NEW_INTEGER(cs.min_scorespace++));gd->upcounter++;//initialize compressed scores
		PROTECT(l_ind = NEW_INTEGER(cs.min_indexspace+1));gd->upcounter++;//initialize genomic index with starting positions of 0 blocks
		PROTECT(gen_ind = NEW_INTEGER(cs.min_indexspace+1));gd->upcounter++;//initialize linear index with list indexes of block starts

		scoresp =(usersize*) INTEGER_POINTER(scores);

		l_indp = INTEGER_POINTER(l_ind);
		gen_indp = INTEGER_POINTER(gen_ind);

		/*Send results to R*/
		uint32_t bstart=0,bend=0,bpos,scount=0,fcount=0,windowt=0,histc=0;
		for(scount_ind=0;scount_ind<cs.min_indexspace;scount_ind++){//go through the index
			if(!user_args->FILTER){
				bstart=lstart_ind[scount_ind];//start of data block in scores
				bend=lend_ind[scount_ind];//end of data block in scores
				if(bstart>bend){
					printf("--START--> %d --END--> %d --DIV--> %d\n",bstart,bend,bend-bstart);
					error("--POSSIBLE INDEX ERROR--> BEND-BSTART<0!\n");
				}
			}else{//intersect filter and index
				bstart=ft->values[filter_index][fcount++];//C index 0 based
				bend=ft->values[filter_index][fcount++];//C index 0 based
				if(bstart>maxscores){
					gd->lsize+=bend-bstart;
					if(fcount>3)bend=ft->values[filter_index][fcount-3];//just in case the end of the chromosome is reached -> use last end as index end
					else bend=bstart;
					break;
				}else if(bend>maxscores){
					gd->lsize+=bend-bstart;
					bend=maxscores;
				}
			}
			gen_indp[scount_ind]=bstart+1;//C index 0 based -> genomic position +1
			l_indp[scount_ind]=scount;//R index 1 based -> but accession will be in C
			for(bpos=bstart;bpos<=bend;bpos++){//go through every base pair
				#if pedantic==1
					if(scount>cs.min_scorespace*(4/sizeof(usersize)) || scount_ind>cs.min_indexspace){error("INDEXING FAULT\n");
					}
				#endif
				scoresp[scount++]=*(cptr+bpos);
				gd->lmaxScore=max(*(cptr+bpos),gd->lmaxScore);
				gd->lmapmass+=*(cptr+bpos);
				if(user_args->HWINDOW>1){
					histc++;
					windowt+=*(cptr+bpos);
					if(histc%user_args->HWINDOW==0){
						++gd->histogramp[windowt/user_args->HWINDOW];
						windowt=0;
					}
				} else if(user_args->HWINDOW==1)++gd->histogramp[*(cptr+bpos)];

			#if verbose==2
				printf("FINALLY VALUE2@ %d -> %d || POS: %d\n",scount,scoresp[scount-1],bpos);
			#endif
			}
			if(user_args->HWINDOW>1)++gd->histogramp[windowt/user_args->HWINDOW];//empty last window | prerequisite: HWINDOW<=COMPRESSION!
			histc=0;windowt=0;
			gd->lsize+=bend-bstart;//calculate amount of bps covered outside of blocks

		}

		gen_indp[scount_ind]=user_args->FILTER ? bend+1 : cs.max_pos+1;//override read based cs.maxpos to filter end in case of FILTER. +1 to indicate start of next block
		l_indp[scount_ind]=scount;
		#if pedantic==1
			if(scount>cs.min_scorespace*(4/sizeof(usersize)))error("Uninitialized variables in score vector detected: COUNT %d >  SPACE %d\n",scount,cs.min_scorespace*(4/sizeof(usersize)));
			if(scount_ind!=cs.min_indexspace)error("Uninitialized variables in index vector detected: %d <> %d\n",scount_ind,cs.min_indexspace);
		#endif


    	char lindname[strlen(bam_file->header->target_name[chrom_tid])+5];
    	sprintf(lindname,"%s",bam_file->header->target_name[chrom_tid]);
    	strcat(lindname,"_lind");

    	char gindname[strlen(bam_file->header->target_name[chrom_tid])+5];
    	sprintf(gindname,"%s",bam_file->header->target_name[chrom_tid]);
    	strcat(gindname,"_gind");

    	SET_STRING_ELT(gd->list_names,tid_vector,mkChar(bam_file->header->target_name[chrom_tid]));
    	SET_STRING_ELT(gd->list_names,tid_vector+gd->total_elements,mkChar(gindname));
    	SET_STRING_ELT(gd->list_names,tid_vector+(gd->total_elements*2),mkChar(lindname));
		SET_VECTOR_ELT(gd->list, tid_vector, scores);
		SET_VECTOR_ELT(gd->list, tid_vector+gd->total_elements, gen_ind);
		SET_VECTOR_ELT(gd->list, tid_vector+(gd->total_elements*2), l_ind);

		tid_vector++;

		time(&stop);

		#if verbose>0
		printf("\nAbout %.0f seconds. %d reads processed on %s\n", difftime(stop, start),bresults.total_reads,bam_file->header->target_name[chrom_tid]);
		printf("l_ind set at EL# %d g_ind at %d and scores at %d \n\n",tid_vector,tid_vector+gd->total_elements,tid_vector+(gd->total_elements*2));
		#endif
		chrom_tid=bresults.chrom_index_next;
		copy2globals(gd,&bresults);
		destroy_scores(cptr,lstart_ind,lend_ind);
    }
	if(user_args->VERBOSE>0 && bresults.file_status>=0){
		if(cc<=bam_file->header->n_targets){
			printf("\nWarning: the following chromosomes have no reads\n");
			int x=0,y=0;
			for(;x<bam_file->header->n_targets;x++){
				if(!proc_chrom[x]){
					printf("%s ",bam_file->header->target_name[x]);
					++y;
					if(y%5==0)printf("\n");
				}
			}
			printf("\n");
		}
	}
	Free(proc_chrom);
	if(bresults.file_status<0)gd->total_reads=0;
	return;
}
Example #3
0
static char* test_root_null() {
    int res = seq_match(NULL, NULL, 0, 1);
    mu_assert("error, res != SEQ_INVALID", res == SEQ_INVALID);
    return 0;
}
Example #4
0
#include "../keyseq.c"

int tests_run = 0;

static char* test_root_null() {
    int res = seq_match(NULL, NULL, 0, 1);
    mu_assert("error, res != SEQ_INVALID", res == SEQ_INVALID);
    return 0;
}

static char* test_len_zero() {
    node leaf = { .data = 1, .next = NULL };
    node root = { .data = 5, .next = &leaf };
    uint8_t buff[1] = { 5 };

    int res = seq_match(&root, buff, 0, 0);

    mu_assert("error, res != SEQ_PARTIAL", res == SEQ_PARTIAL);
    return 0;
}

static char* test_seq_len_one() {
    uint8_t report_i = 31;

    node leaf = { .data = report_i, .next = NULL };
    node root = { .data = 5, .next = &leaf };
    uint8_t buff[1] = { 5 };

    int res = seq_match(&root, buff, 0, 1);

    mu_assert("error, res != (report index)", res == report_i);
Example #5
0
/*
 * Check out the packet to see if it came from us.  This logic is necessary
 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
 * which arrive ('tis only fair).  This permits multiple copies of this
 * program to be run without having intermingled output (or statistics!).
 */
void
check_reply(struct addrinfo *ai_dst, struct msghdr *msg, int cc,
    ushort_t udp_src_port)
{
	struct ip *ip;
	struct icmp *icp;
	struct udphdr *up;
	union any_in_addr dst_addr;
	uchar_t *buf;
	int32_t *intp;
	struct sockaddr_in *from;
	struct timeval *tp;
	struct timeval tv;
	int hlen, hlen1;
	int64_t triptime;
	boolean_t valid_reply = _B_FALSE;
	boolean_t reply_matched_current_target;	/* Is the source address of */
						/* this reply same as where */
						/* we're sending currently? */
	boolean_t last_reply_from_targetaddr = _B_FALSE; /* Is this stats, */
						/* probe all with npackets>0 */
						/* and we received reply for */
						/* the last probe sent to */
						/* targetaddr */
	int cc_left;
	char tmp_buf[INET6_ADDRSTRLEN];
	static char *unreach[] = {
	    "Net Unreachable",
	    "Host Unreachable",
	    "Protocol Unreachable",
	    "Port Unreachable",
	    "Fragmentation needed and DF set",
	    "Source Route Failed",
	    /* The following are from RFC1700 */
	    "Net Unknown",
	    "Host Unknown",
	    "Source Host Isolated",
	    "Dest Net Prohibited",
	    "Dest Host Prohibited",
	    "Net Unreachable for TOS",
	    "Host Unreachable for TOS",
	    "Communication Administratively Prohibited",
	    "Host Precedence Violation",
	    "Precedence Cutoff in Effect"
	};
	static char *redirect[] = {
	    "Net",
	    "Host",
	    "TOS Net",
	    "TOS Host"
	};
	static char *timexceed[] = {
	    "Time exceeded in transit",
	    "Time exceeded during reassembly"
	};
	boolean_t print_newline = _B_FALSE;
	int i;

	/* decompose msghdr into useful pieces */
	buf = (uchar_t *)msg->msg_iov->iov_base;
	from = (struct sockaddr_in *)msg->msg_name;

	/* LINTED */
	intp = (int32_t *)buf;

	(void) gettimeofday(&tv, (struct timezone *)NULL);

	/* LINTED */
	ip = (struct ip *)buf;
	hlen = ip->ip_hl << 2;

	if ((cc < sizeof (struct ip)) || (cc < hlen + ICMP_MINLEN)) {
		if (verbose) {
			Printf("packet too short (%d bytes) from %s\n", cc,
			    pr_name((char *)&from->sin_addr, AF_INET));
		}
		return;
	}

	cc -= hlen;
	/* LINTED */
	icp = (struct icmp *)(buf + hlen);

	if (ip->ip_p == 0) {
		/*
		 * Assume that we are running on a pre-4.3BSD system
		 * such as SunOS before 4.0
		 */
		/* LINTED */
		icp = (struct icmp *)buf;
	}
	cc_left = cc - ICMP_MINLEN;

	switch (icp->icmp_type) {
	case ICMP_UNREACH:
		ip = &icp->icmp_ip;
		hlen1 = ip->ip_hl << 2;

		/* check if we have enough of the packet to work on */
		if ((cc_left < sizeof (struct ip)) ||
		    (cc_left < hlen1 + sizeof (struct udphdr))) {
			if (verbose) {
				Printf("packet too short (%d bytes) from %s\n",
				    cc, pr_name((char *)&from->sin_addr,
				    AF_INET));
			}
			return;
		}

		/* get the UDP packet */
		cc_left -= hlen1 + sizeof (struct udphdr);
		/* LINTED */
		up = (struct udphdr *)((uchar_t *)ip + hlen1);

		/* check to see if this is what we sent */
		if (icp->icmp_code == ICMP_UNREACH_PORT &&
		    ip->ip_p == IPPROTO_UDP &&
		    udp_src_port == up->uh_sport &&
		    use_udp) {
			valid_reply = _B_TRUE;
		} else {
			valid_reply = _B_FALSE;
		}

		if (valid_reply) {
			/*
			 * For this valid reply, if we are still sending to
			 * this target IP address, we'd like to do some
			 * updates to targetaddr, so hold SIGALRMs.
			 */
			(void) sighold(SIGALRM);
			is_alive = _B_TRUE;
			nreceived++;
			reply_matched_current_target =
			    seq_match(current_targetaddr->starting_seq_num,
				current_targetaddr->num_sent,
				ntohs(up->uh_dport));
			if (reply_matched_current_target) {
				current_targetaddr->got_reply = _B_TRUE;
				nreceived_last_target++;
				/*
				 * Determine if stats, probe-all, and
				 * npackets != 0, and this is the reply for
				 * the last probe we sent to current target
				 * address.
				 */
				if (stats && probe_all && npackets > 0 &&
				    ((current_targetaddr->starting_seq_num +
				    current_targetaddr->num_probes - 1) %
				    (MAX_PORT + 1) == ntohs(up->uh_dport)) &&
				    (current_targetaddr->num_probes ==
				    current_targetaddr->num_sent))
					last_reply_from_targetaddr = _B_TRUE;
			} else {
				/*
				 * If it's just probe_all and we just received
				 * a reply from a target address we were
				 * probing and had timed out (now we are probing
				 * some other target address), we ignore
				 * this reply.
				 */
				if (probe_all && !stats) {
					valid_reply = _B_FALSE;
					/*
					 * Only if it's verbose, we get a
					 * message regarding this reply,
					 * otherwise we are done here.
					 */
					if (!verbose) {
						(void) sigrelse(SIGALRM);
						return;
					}
				}
			}
		}

		/* stats mode doesn't print 'alive' messages */
		if (valid_reply && !stats) {
			/*
			 * if we are still sending to the same target address,
			 * then stop it, because we know it's alive.
			 */
			if (reply_matched_current_target) {
				(void) alarm(0);	/* cancel alarm */
				(void) sigset(SIGALRM, SIG_IGN);
				current_targetaddr->probing_done = _B_TRUE;
			}
			(void) sigrelse(SIGALRM);

			if (!probe_all) {
				Printf("%s is alive\n", targethost);
			} else {
				(void) inet_ntop(AF_INET, (void *)&ip->ip_dst,
				    tmp_buf, sizeof (tmp_buf));

				if (nflag) {
					Printf("%s is alive\n", tmp_buf);
				} else {
					Printf("%s (%s) is alive\n",
					    targethost, tmp_buf);
				}
			}
			if (reply_matched_current_target) {
				/*
				 * Let's get things going again, but now
				 * ping will start sending to next target IP
				 * address.
				 */
				send_scheduled_probe();
				(void) sigset(SIGALRM, sigalrm_handler);
				schedule_sigalrm();
			}
			return;
		} else {
			/*
			 * If we are not moving to next targetaddr, let's
			 * release the SIGALRM now. We don't want to stall in
			 * the middle of probing a targetaddr if the pr_name()
			 * call (see below) takes longer.
			 */
			if (!last_reply_from_targetaddr)
				(void) sigrelse(SIGALRM);
			/* else, we'll release it later */
		}

		dst_addr.addr = ip->ip_dst;
		if (valid_reply) {
			Printf("%d bytes from %s: ", cc,
			    pr_name((char *)&from->sin_addr, AF_INET));
			Printf("udp_port=%d. ", ntohs(up->uh_dport));
			print_newline = _B_TRUE;
		} else if (is_a_target(ai_dst, &dst_addr) || verbose) {
			if (icp->icmp_code >= A_CNT(unreach)) {
				Printf("ICMP %d Unreachable from gateway %s\n",
				    icp->icmp_code,
				    pr_name((char *)&from->sin_addr, AF_INET));
			} else {
				Printf("ICMP %s from gateway %s\n",
				    unreach[icp->icmp_code],
				    pr_name((char *)&from->sin_addr, AF_INET));
			}
			Printf(" for %s from %s", pr_protocol(ip->ip_p),
			    pr_name((char *)&ip->ip_src, AF_INET));
			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
			if (ip->ip_p == IPPROTO_TCP ||
			    ip->ip_p == IPPROTO_UDP) {
				Printf(" port %d ", ntohs(up->uh_dport));
			}
			print_newline = _B_TRUE;
		}

		/* if we are timing and the reply has a timeval */
		if (valid_reply && datalen >= sizeof (struct timeval) &&
		    cc_left >= sizeof (struct timeval)) {
			/* LINTED */
			tp = (struct timeval *)((char *)up +
			    sizeof (struct udphdr));
			(void) tvsub(&tv, tp);
			triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
			Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
			tsum += triptime;
			tsum2 += triptime*triptime;
			if (triptime < tmin)
				tmin = triptime;
			if (triptime > tmax)
				tmax = triptime;
			print_newline = _B_TRUE;
		}
		if (print_newline)
			(void) putchar('\n');
		/*
		 * If it's stats, probe-all, npackets > 0, and we received reply
		 * for the last probe sent to this target address, then we
		 * don't need to wait anymore, let's move on to next target
		 * address, now!
		 */
		if (last_reply_from_targetaddr) {
			(void) alarm(0);	/* cancel alarm */
			current_targetaddr->probing_done = _B_TRUE;
			(void) sigrelse(SIGALRM);
			send_scheduled_probe();
			schedule_sigalrm();
		}
		break;

	case ICMP_REDIRECT:
		if (cc_left < sizeof (struct ip)) {
			if (verbose) {
				Printf("packet too short (%d bytes) from %s\n",
				    cc, pr_name((char *)&from->sin_addr,
				    AF_INET));
			}
			return;
		}

		ip = &icp->icmp_ip;
		dst_addr.addr = ip->ip_dst;
		if (is_a_target(ai_dst, &dst_addr) || verbose) {
			if (icp->icmp_code >= A_CNT(redirect)) {
				Printf("ICMP %d redirect from gateway %s\n",
				    icp->icmp_code,
				    pr_name((char *)&from->sin_addr, AF_INET));
			} else {
				Printf("ICMP %s redirect from gateway %s\n",
				    redirect[icp->icmp_code],
				    pr_name((char *)&from->sin_addr, AF_INET));
			}
			Printf(" to %s",
			    pr_name((char *)&icp->icmp_gwaddr, AF_INET));
			Printf(" for %s\n",
			    pr_name((char *)&ip->ip_dst, AF_INET));
		}
		break;

	case ICMP_ECHOREPLY:
		if (ntohs(icp->icmp_id) == ident) {
			if (!use_udp && !use_icmp_ts)
				valid_reply = _B_TRUE;
			else
				valid_reply = _B_FALSE;
		} else {
			return;
		}

		if (valid_reply) {
			/*
			 * For this valid reply, if we are still sending to
			 * this target IP address, we'd like to do some
			 * updates to targetaddr, so hold SIGALRMs.
			 */
			(void) sighold(SIGALRM);
			is_alive = _B_TRUE;
			nreceived++;
			reply_matched_current_target =
			    seq_match(current_targetaddr->starting_seq_num,
				current_targetaddr->num_sent,
				ntohs(icp->icmp_seq));
			if (reply_matched_current_target) {
				current_targetaddr->got_reply = _B_TRUE;
				nreceived_last_target++;
				/*
				 * Determine if stats, probe-all, and
				 * npackets != 0, and this is the reply for
				 * the last probe we sent to current target
				 * address.
				 */
				if (stats && probe_all && npackets > 0 &&
				    ((current_targetaddr->starting_seq_num +
				    current_targetaddr->num_probes - 1) %
				    (MAX_ICMP_SEQ + 1) ==
				    ntohs(icp->icmp_seq)) &&
				    (current_targetaddr->num_probes ==
				    current_targetaddr->num_sent))
					last_reply_from_targetaddr = _B_TRUE;
			} else {
				/*
				 * If it's just probe_all and we just received
				 * a reply from a target address we were
				 * probing and had timed out (now we are probing
				 * some other target address), we ignore
				 * this reply.
				 */
				if (probe_all && !stats) {
					valid_reply = _B_FALSE;
					/*
					 * Only if it's verbose, we get a
					 * message regarding this reply,
					 * otherwise we are done here.
					 */
					if (!verbose) {
						(void) sigrelse(SIGALRM);
						return;
					}
				}
			}
		}

		if (!stats && valid_reply) {
			/*
			 * if we are still sending to the same target address,
			 * then stop it, because we know it's alive.
			 */
			if (reply_matched_current_target) {
				(void) alarm(0);	/* cancel alarm */
				(void) sigset(SIGALRM, SIG_IGN);
				current_targetaddr->probing_done = _B_TRUE;
			}
			(void) sigrelse(SIGALRM);

			if (!probe_all) {
				Printf("%s is alive\n", targethost);
			} else {
				/*
				 * If we are using send_reply, the real
				 * target address is not the src address of the
				 * replies. Use icmp_seq to find out where this
				 * probe was sent to.
				 */
				if (send_reply) {
					(void) find_dstaddr(
					    ntohs(icp->icmp_seq), &dst_addr);
					(void) inet_ntop(AF_INET,
					    (void *)&dst_addr.addr,
					    tmp_buf, sizeof (tmp_buf));
				} else {
					(void) inet_ntop(AF_INET,
					    (void *)&from->sin_addr,
					    tmp_buf, sizeof (tmp_buf));
				}
				if (nflag) {
					Printf("%s is alive\n", tmp_buf);
				} else {
					Printf("%s (%s) is alive\n",
					    targethost, tmp_buf);
				}
			}
			if (reply_matched_current_target) {
				/*
				 * Let's get things going again, but now
				 * ping will start sending to next target IP
				 * address.
				 */
				send_scheduled_probe();
				(void) sigset(SIGALRM, sigalrm_handler);
				schedule_sigalrm();
			}
			return;
		} else {
			/*
			 * If we are not moving to next targetaddr, let's
			 * release the SIGALRM now. We don't want to stall in
			 * the middle of probing a targetaddr if the pr_name()
			 * call (see below) takes longer.
			 */
			if (!last_reply_from_targetaddr)
				(void) sigrelse(SIGALRM);
			/* else, we'll release it later */
		}
		/*
		 * If we are using send_reply, the real target address is
		 * not the src address of the replies. Use icmp_seq to find out
		 * where this probe was sent to.
		 */
		if (send_reply) {
			(void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
			Printf("%d bytes from %s: ", cc,
			    pr_name((char *)&dst_addr.addr,  AF_INET));
		} else {
			Printf("%d bytes from %s: ", cc,
			    pr_name((char *)&from->sin_addr, AF_INET));
		}
		Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));

		if (valid_reply && datalen >= sizeof (struct timeval) &&
		    cc_left >= sizeof (struct timeval)) {
			/* LINTED */
			tp = (struct timeval *)&icp->icmp_data[0];
			(void) tvsub(&tv, tp);
			triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
			Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
			tsum += triptime;
			tsum2 += triptime*triptime;
			if (triptime < tmin)
				tmin = triptime;
			if (triptime > tmax)
				tmax = triptime;
		}
		(void) putchar('\n');

		/*
		 * If it's stats, probe-all, npackets > 0, and we received reply
		 * for the last probe sent to this target address, then we
		 * don't need to wait anymore, let's move on to next target
		 * address, now!
		 */
		if (last_reply_from_targetaddr) {
			(void) alarm(0);	/* cancel alarm */
			current_targetaddr->probing_done = _B_TRUE;
			(void) sigrelse(SIGALRM);
			send_scheduled_probe();
			schedule_sigalrm();
		}
		break;

	case ICMP_SOURCEQUENCH:
		if (cc_left < sizeof (struct ip)) {
			if (verbose) {
				Printf("packet too short (%d bytes) from %s\n",
				    cc, pr_name((char *)&from->sin_addr,
				    AF_INET));
			}
			return;
		}
		ip = &icp->icmp_ip;
		hlen1 = ip->ip_hl << 2;
		dst_addr.addr = ip->ip_dst;
		if (is_a_target(ai_dst, &dst_addr) || verbose) {
			Printf("ICMP Source Quench from %s\n",
			    pr_name((char *)&from->sin_addr, AF_INET));
			Printf(" for %s from %s", pr_protocol(ip->ip_p),
			    pr_name((char *)&ip->ip_src, AF_INET));
			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));

			/*
			 * if it's a UDP or TCP packet, we need at least first
			 * 4 bytes of it to see the src/dst ports
			 */
			if ((ip->ip_p == IPPROTO_TCP ||
			    ip->ip_p == IPPROTO_UDP) &&
			    (cc_left >= hlen1 + 4)) {
				/* LINTED */
				up = (struct udphdr *)((uchar_t *)ip + hlen1);
				Printf(" port %d", ntohs(up->uh_dport));
			}
			(void) putchar('\n');
		}
		break;

	case ICMP_PARAMPROB:
		if (cc_left < sizeof (struct ip)) {
			if (verbose) {
				Printf("packet too short (%d bytes) from %s\n",
				    cc, pr_name((char *)&from->sin_addr,
				    AF_INET));
			}
			return;
		}
		ip = &icp->icmp_ip;
		hlen1 = ip->ip_hl << 2;
		dst_addr.addr = ip->ip_dst;
		if (is_a_target(ai_dst, &dst_addr) || verbose) {
			switch (icp->icmp_code) {
			case ICMP_PARAMPROB_OPTABSENT:
				Printf("ICMP Missing a Required Option "
				    "parameter problem from %s\n",
				    pr_name((char *)&from->sin_addr, AF_INET));
				Printf(" option type = %d", icp->icmp_pptr);
				break;
			case ICMP_PARAMPROB_BADLENGTH:
				Printf("ICMP Bad Length parameter problem "
				    "from %s\n",
				    pr_name((char *)&from->sin_addr, AF_INET));
				Printf(" in byte %d", icp->icmp_pptr);
				if (icp->icmp_pptr <= hlen1) {
					Printf(" (value 0x%x)",
					    *((char *)ip + icp->icmp_pptr));
				}
				break;
			case 0:
			default:
				Printf("ICMP Parameter Problem from %s\n",
				    pr_name((char *)&from->sin_addr, AF_INET));
				Printf(" in byte %d", icp->icmp_pptr);
				if (icp->icmp_pptr <= hlen1) {
					Printf(" (value 0x%x)",
					    *((char *)ip + icp->icmp_pptr));
				}
				break;
			}

			Printf(" for %s from %s", pr_protocol(ip->ip_p),
			    pr_name((char *)&ip->ip_src, AF_INET));
			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));

			/*
			 * if it's a UDP or TCP packet, we need at least first
			 * 4 bytes of it to see the src/dst ports
			 */
			if ((ip->ip_p == IPPROTO_TCP ||
			    ip->ip_p == IPPROTO_UDP) &&
			    (cc_left >= hlen1 + 4)) {
				/* LINTED */
				up = (struct udphdr *)((uchar_t *)ip + hlen1);
				Printf(" port %d", ntohs(up->uh_dport));
			}
			(void) putchar('\n');
		}
		break;

	case ICMP_TIMXCEED:
		if (cc_left < sizeof (struct ip)) {
			if (verbose) {
				Printf("packet too short (%d bytes) from %s\n",
				    cc, pr_name((char *)&from->sin_addr,
				    AF_INET));
			}
			return;
		}
		ip = &icp->icmp_ip;
		hlen1 = ip->ip_hl << 2;
		dst_addr.addr = ip->ip_dst;
		if (is_a_target(ai_dst, &dst_addr) || verbose) {
			if (icp->icmp_code >= A_CNT(timexceed)) {
				Printf("ICMP %d time exceeded from %s\n",
				    icp->icmp_code,
				    pr_name((char *)&from->sin_addr, AF_INET));
			} else {
				Printf("ICMP %s from %s\n",
				    timexceed[icp->icmp_code],
				    pr_name((char *)&from->sin_addr, AF_INET));
			}
			Printf(" for %s from %s", pr_protocol(ip->ip_p),
			    pr_name((char *)&ip->ip_src, AF_INET));
			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
			if ((ip->ip_p == IPPROTO_TCP ||
			    ip->ip_p == IPPROTO_UDP) &&
			    (cc_left >= hlen1 + 4)) {
				/* LINTED */
				up = (struct udphdr *)((uchar_t *)ip + hlen1);
				Printf(" port %d", ntohs(up->uh_dport));
			}
			(void) putchar('\n');
		}
		break;

	case ICMP_TSTAMPREPLY:
		/* the packet should have enough space to store timestamps */
		if (cc_left < sizeof (struct id_ts)) {
			if (verbose) {
				Printf("packet too short (%d bytes) from %s\n",
				    cc, pr_name((char *)&from->sin_addr,
				    AF_INET));
			}
			return;
		}

		if (ntohs(icp->icmp_id) == ident) {
			if (use_icmp_ts)
				valid_reply = _B_TRUE;
			else
				valid_reply = _B_FALSE;
		} else {
			return;
		}

		if (valid_reply) {
			/*
			 * For this valid reply, if we are still sending to
			 * this target IP address, we'd like to do some
			 * updates to targetaddr, so hold SIGALRMs.
			 */
			(void) sighold(SIGALRM);
			is_alive = _B_TRUE;
			nreceived++;
			reply_matched_current_target =
			    seq_match(current_targetaddr->starting_seq_num,
				current_targetaddr->num_sent,
				ntohs(icp->icmp_seq));
			if (reply_matched_current_target) {
				current_targetaddr->got_reply = _B_TRUE;
				nreceived_last_target++;
				/*
				 * Determine if stats, probe-all, and
				 * npackets != 0, and this is the reply for
				 * the last probe we sent to current target
				 * address.
				 */
				if (stats && probe_all && npackets > 0 &&
				    ((current_targetaddr->starting_seq_num +
				    current_targetaddr->num_probes - 1) %
				    (MAX_ICMP_SEQ + 1) ==
				    ntohs(icp->icmp_seq)) &&
				    (current_targetaddr->num_probes ==
				    current_targetaddr->num_sent))
					last_reply_from_targetaddr = _B_TRUE;
			} else {
				/*
				 * If it's just probe_all and we just received
				 * a reply from a target address we were
				 * probing and had timed out (now we are probing
				 * some other target address), we ignore
				 * this reply.
				 */
				if (probe_all && !stats) {
					valid_reply = _B_FALSE;
					/*
					 * Only if it's verbose, we get a
					 * message regarding this reply,
					 * otherwise we are done here.
					 */
					if (!verbose) {
						(void) sigrelse(SIGALRM);
						return;
					}
				}
			}
		}

		if (!stats && valid_reply) {
			/*
			 * if we are still sending to the same target address,
			 * then stop it, because we know it's alive.
			 */
			if (reply_matched_current_target) {
				(void) alarm(0);	/* cancel alarm */
				(void) sigset(SIGALRM, SIG_IGN);
				current_targetaddr->probing_done = _B_TRUE;
			}
			(void) sigrelse(SIGALRM);

			if (!probe_all) {
				Printf("%s is alive\n", targethost);
			} else {
				/*
				 * If we are using send_reply, the real
				 * target address is not the src address of the
				 * replies. Use icmp_seq to find out where this
				 * probe was sent to.
				 */
				if (send_reply) {
					(void) find_dstaddr(
					    ntohs(icp->icmp_seq), &dst_addr);
					(void) inet_ntop(AF_INET,
					    (void *)&dst_addr.addr,
					    tmp_buf, sizeof (tmp_buf));
				} else {
					(void) inet_ntop(AF_INET,
					    (void *)&from->sin_addr,
					    tmp_buf, sizeof (tmp_buf));
				}
				if (nflag) {
					Printf("%s is alive\n", tmp_buf);
				} else {
					Printf("%s (%s) is alive\n",
					    targethost, tmp_buf);
				}
			}
			if (reply_matched_current_target) {
				/*
				 * Let's get things going again, but now
				 * ping will start sending to next target IP
				 * address.
				 */
				send_scheduled_probe();
				(void) sigset(SIGALRM, sigalrm_handler);
				schedule_sigalrm();
			}
			return;
		} else {
			/*
			 * If we are not moving to next targetaddr, let's
			 * release the SIGALRM now. We don't want to stall in
			 * the middle of probing a targetaddr if the pr_name()
			 * call (see below) takes longer.
			 */
			if (!last_reply_from_targetaddr)
				(void) sigrelse(SIGALRM);
			/* else, we'll release it later */
		}

		/*
		 * If we are using send_reply, the real target address is
		 * not the src address of the replies. Use icmp_seq to find out
		 * where this probe was sent to.
		 */
		if (send_reply) {
			(void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
			Printf("%d bytes from %s: ", cc,
			    pr_name((char *)&dst_addr.addr,  AF_INET));
		} else {
			Printf("%d bytes from %s: ", cc,
			    pr_name((char *)&from->sin_addr, AF_INET));
		}
		Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
		Printf("orig = %lu, recv = %lu, xmit = %lu ",
		    (ulong_t)ntohl(icp->icmp_otime),
		    (ulong_t)ntohl(icp->icmp_rtime),
		    (ulong_t)ntohl(icp->icmp_ttime));

		if (valid_reply) {
			/*
			 * icp->icmp_otime is the time passed since midnight.
			 * Therefore we need to adjust tv value, which is
			 * the time passed since Jan 1, 1970.
			 */
			triptime = (tv.tv_sec % (24LL * 60 * 60)) * MILLISEC +
			    (tv.tv_usec / (MICROSEC/MILLISEC));
			triptime -= ntohl(icp->icmp_otime);
			if (triptime < 0)
				triptime += 24LL * 60 * 60 * MILLISEC;

			Printf("time=%d. ms", (int)triptime);
			triptime *= (MICROSEC/MILLISEC);
			tsum += triptime;
			tsum2 += triptime*triptime;
			if (triptime < tmin)
				tmin = triptime;
			if (triptime > tmax)
				tmax = triptime;
		}
		(void) putchar('\n');
		/*
		 * If it's stats, probe-all, npackets > 0, and we received reply
		 * for the last probe sent to this target address, then we
		 * don't need to wait anymore, let's move on to next target
		 * address, now!
		 */
		if (last_reply_from_targetaddr) {
			(void) alarm(0);	/* cancel alarm */
			current_targetaddr->probing_done = _B_TRUE;
			(void) sigrelse(SIGALRM);
			send_scheduled_probe();
			schedule_sigalrm();
		}
		break;
	case ICMP_ROUTERADVERT:
	case ICMP_ROUTERSOLICIT:
		/* Router discovery messages */
		return;

	case ICMP_ECHO:
	case ICMP_TSTAMP:
	case ICMP_IREQ:
	case ICMP_MASKREQ:
		/* These were never passed out from the SunOS 4.X kernel. */
		return;

	case ICMP_IREQREPLY:
	case ICMP_MASKREPLY:
		/* Replies for information and address mask requests */
		return;

	default:
		if (verbose) {
			Printf("%d bytes from %s:\n", cc,
			    pr_name((char *)&from->sin_addr, AF_INET));
			Printf("icmp_type=%d (%s) ",
			    icp->icmp_type, pr_type(icp->icmp_type));
			Printf("icmp_code=%d\n", icp->icmp_code);
			for (i = 0; i < 12; i++) {
				Printf("x%2.2x: x%8.8x\n",
				    i * sizeof (int32_t), *intp++);
			}
		}
		break;
	}

	buf += sizeof (struct ip);
	hlen -= sizeof (struct ip);

	/* if verbose and there exists IP options */
	if (verbose && hlen > 0)
		pr_options((uchar_t *)buf, hlen);
}