File:  [Apple Darwin 0.x] / driverkit / tests / ether.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:50 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Ethernet object exerciser.
 */
 
#define dbg_prn(a,b,c,d,e,f)		\
{					\
	if(verbose) {			\
		printf(a,b,c,d,e,f);	\
	}				\
}

/*
 * Hmmm...we need KERNEL defined to get netif.h...
 * ...and if.h really should import sys/socket.h.
 */
#import <bsd/sys/socket.h>		
#define KERNEL	1
#import <net/netif.h>
#undef	KERNEL
#import <Enet/Ethernet.h>
#import <driverkit/KernDevUxpr.h>
#import <driverkit/generalFuncs.h>
#import <kernserv/queue.h>
#import <machkit/NXLock.h>
#import <libc.h>

#define MIN_SIZE 	100		// minimum packet size
#define MAX_SIZE	500		// maximum packet size
#define INCREMENT	20		// delta packet size
#define THROTTLE	10		// max # packets outstanding
#define LOOP_COUNT	1

/*
 * This is how we enqueue incoming buffers.
 */
typedef struct in_buf in_buf_t;
struct in_buf {
	netbuf_t nb;
	in_buf_t *next;
};

/*
 * Static functions.
 */
static void usage(char **argv);
static int runTest(netif_t nif,
	int min_packet_size,
	int max_packet_size,
	int increment,
	int throttle);
static int check_new_bufs(int min_size, int increment, int packets_recd);
static void etherTimeout(void *flag);
static netbuf_t wait_for_packets(netif_t nif);

/*
 * Static variables.
 */
in_buf_t 	*in_buf_next, *in_buf_last;
id 		in_buf_lock;			// NXLock - protects
						//   in_buf
enetAddress_t	destAdrs = { {0,1,2,3,4,5} };
#ifdef	notdef
id		buf_wait_lock;			// NXConditionLock - used to 
						//   wait for incoming buf
#endif	notdef

/*
 * User-specified parameters.
 */
int min_size  = MIN_SIZE;
int max_size  = MAX_SIZE;
int increment = INCREMENT;
int throttle  = THROTTLE;
int verbose = 0;
int loop_count = LOOP_COUNT;
						
int main(int argc, char **argv)
{
	id	etherId;
	netif_t	nif;
	char 	s[100];
	int 	arg;
	int	loop_num;
	
	for(arg=1; arg<argc; arg++) {
		switch(argv[arg][0]) {
		    case 'v':
		    	verbose++;
			break;
		    case 'n':
		    	min_size = atoi(&argv[arg][2]);
			break;
		    case 'x':
		    	max_size = atoi(&argv[arg][2]);
			break;
		    case 'i':
		    	increment = atoi(&argv[arg][2]);
			break;
		    case 't':
		    	throttle = atoi(&argv[arg][2]);
			break;
		    case 'l':
		    	loop_count = atoi(&argv[arg][2]);
			break;
		    default:
		    	usage(argv);
		}
	}

#ifdef	DDM_DEBUG
	IOInitDDM(1000, "EnetXpr");
	IOSetDDMMask(XPR_IODEVICE_INDEX,
		 XPR_NET | XPR_ENTX | XPR_ENRX | XPR_ENCOM | XPR_NDMA);
#endif	DDM_DEBUG
	IOInitGeneralFuncs();
	etherId = [Ethernet probe:0 deviceMaster:PORT_NULL];
	if(etherId == nil) {
		printf("Driver Probe failed; exiting.\n");
		exit(1);
	}
	nif = [etherId getNetif];
#ifdef	notdef
	buf_wait_lock = [NXConditionLock new];
#endif	notdef
	in_buf_lock   = [NXLock new];
	loop_num = 0;
	do {
		printf("...Loop %d\n", loop_num);
		if(runTest(nif, min_size, max_size, increment, throttle))
			break;
		loop_num++;
	} while ((loop_count == 0) || (loop_num < loop_count));
	printf("Hit <CR> to quit: ");
	gets(s);
	exit(0);
}

static void usage(char **argv)
{
	printf("Usage: %s [options]\n");
	printf("   Options:\n");
	printf("\tn=min_size   (default = %d)\n", MIN_SIZE);
	printf("\tx=max_size   (default = %d)\n", MAX_SIZE);
	printf("\ti=increment  (default = %d)\n", INCREMENT);
	printf("\tt=throttle   (default = %d)\n", THROTTLE);
	printf("\tl=loop count (default = %d; 0 means forever)\n", LOOP_COUNT); 
	printf("\tv=verbose mode\n");
	exit(1);
}
/*
 * Main test loop. Returns non-zero on error.
 */
static int runTest(netif_t nif,
	int min_size,
	int max_size,
	int increment,
	int throttle)
{
/*
 *	packets_recd = 0;
 * 	for(size=min to max) {
 *		getbuf a netbuf from driver;
 *		if(no bufs available or throttle exceeded) {
 *			wait for some rx buffers to arrive;
 *		}
 *		else {
 *			fill with some data pattern;
 *			if_output() the netbuf to the driver;
 *			packets_sent++;
 *		}
 *		if any new netbufs on in_buf queue {
 *			for each one {
 *				verify proper data;
 *				packets_recd++;
 *				nb_free() it;
 *			}
 *		}
 *      }
 *	wait a reasonable time for packets_sent == packets_recd, checking 
 *		all incoming data;
 */
 
 	int size;
	int packets_sent = 0;
	int packets_recd = 0;
	netbuf_t nb;
	int rtn;
	int current_size;
	int timeout_flag;
	int packets_out = 0;
	
 	packets_recd = 0;
	size = min_size;
	do {
		nb = if_getbuf(nif);
		if((nb == NULL) || (packets_out >= throttle)) {
			
			/*
			 * nb == NULL means that the driver has no more 
			 * buffers; exceeding the throttle means we should
			 * back off and let 'DMA' complete.
			 *
			 * We'll just have to wait for some network activity.
			 */
			nb = wait_for_packets(nif);
			if(nb == NULL) {
				
				/*
				 * Still no Tx bufs available, but some 
				 * Rx bufs showed up.
				 */
				goto handle_input;
			}
			/* 
			 * Else drop thru and send using nb.
			 */
		}

		/*
		 * nb_write() some data here eventually. For now, 
		 * just set the size to min_size + 
		 * (increment * packet_num).
		 */
		dbg_prn("sending  packet num %d size %d\n", 
			packets_sent, size, 3,4,5);
		current_size = min_size + (increment * packets_sent); 
		nb_shrink_bot(nb, nb_size(nb) - current_size);
		rtn = if_output(nif, nb, &destAdrs);
		if(rtn) {
			printf("Error on if_output (rtn = %d)\n", rtn);
			return -1;
		}
		packets_sent++;
		packets_out++;
		size += increment;
		
		/*
		 * Check for incoming packets.
		 */
handle_input:
		rtn = check_new_bufs(min_size, increment, packets_recd);
		if(rtn < 0) 
			return rtn;
		packets_recd += rtn;
		packets_out -= rtn;
		
	} while (size <= max_size);
	
	/*
	 * In a reasonable time, we should see all of the packets. 
	 */
	if(packets_recd != packets_sent) {
		dbg_prn("Exit main loop; waiting for incoming packets\n",
			1,2,3,4,5);
		timeout_flag = 0;
		IOScheduleFunc((IOThreadFunc)etherTimeout, &timeout_flag, 2);
		do {
			rtn = check_new_bufs(min_size, increment,
				packets_recd);
			if(rtn < 0) 
				return rtn;
			packets_recd += rtn;
		} while (!timeout_flag && (packets_recd != packets_sent));
		if(timeout_flag) {
			printf("%d packets sent, %d received: FATAL\n",
				packets_sent, packets_recd);
			return -1;
		}
		else {
			IOUnscheduleFunc((IOThreadFunc)etherTimeout,
				&timeout_flag);
		}
	}
	return 0;
}

/*
 * Timeout function, called out via IOScheduleFunc. Sets the specified flag to 1. 
 */
static void etherTimeout(void *flag)
{
	*((int *)flag) = 1;
#ifdef	notdef
	[buf_wait_lock lock];
	[buf_wait_lock unlockWith:TRUE];
#endif	notdef
}

/*
 * Wait for some packets to arrive or for if_getbuf() to succeed.
 * if_getbuf() is attempted every 50 ms (actually, with current libIO, 
 * every 1 second...). 
 *
 * If if_getbuf() succeeds, this returns a netbuf_t; else (in_buf non-empty)
 * returns NULL.
 */
static netbuf_t wait_for_packets(netif_t nif)
{
	netbuf_t nb;
	
	dbg_prn("...waiting for available packets\n", 1,2,3,4,5);
	while(1) {
	
		/*
		 * Any incoming bufs?
		 */
		[in_buf_lock lock];
		if(in_buf_next != NULL) {
			[in_buf_lock unlock];
			return NULL;
		}
		[in_buf_lock unlock];
		
		/*
		 * Any outgoing bufs?
		 */
		nb = if_getbuf(nif);
		if(nb) {
			return(nb);
		}	  
		
		/*
		 * Go to sleep. 
		 */
		/* IOSleep(50); */
		cthread_yield();
	}
}

/*
 * Check out any new netbufs in in_buf queue. Returns -1 on error, else 
 * return the number of new packets received and checked.
 *
 * One entry, packets_recd is the number of packets already seen.
 */
static int check_new_bufs(int min_size, int increment, int packets_recd)
{
	in_buf_t *ib;
	int new_packets = 0;
	int current_size;
	int error = 0;
	int current_packet = packets_recd;
	int recd_size;
	
	[in_buf_lock lock];
	ib = in_buf_next;
	if(ib) {
		in_buf_next = ib->next;
	}
	[in_buf_lock unlock];
	while(ib) {
			
		/*
		 * eventually check out data here...For now, just check size.
		 */
		current_size = min_size + (increment * (current_packet));
		recd_size = nb_size(ib->nb);
		dbg_prn("received packet num %d size %d\n", 
			current_packet, recd_size,3,4,5);
		if(recd_size != current_size) {
			printf("***bad size for in_packet %d\n", 
				current_packet);
			printf("   Expected %d   actual %d\n",
				current_size, recd_size);
			error++;
		}
		current_packet++;
		new_packets++;		
		
		/*
		 * Free both the netbuf and the in_buf.
		 */
		nb_free(ib->nb);
		IOFree(ib, sizeof(*ib));
		
		/*
		 * Get next in_buf.
		 */
		[in_buf_lock lock];
		ib = in_buf_next;
		if(ib) {
			in_buf_next = ib->next;
		}
		[in_buf_lock unlock];

	}
	if(error)
		return -1;
	else
		return new_packets;
}

/*
 * Provided for handling incoming packets. These should map one-to-one with the
 * packets we send via if_output(). This will actually be called from the 
 * driver's enetThread.
 *
 * All we do is save the incoming netbuf in in_buf. The main thread
 * does data and sequence checking.
 */
int if_handle_input(netif_t netif, 
	netbuf_t nb, 
	void *extra)
{
	in_buf_t *ib = IOMalloc(sizeof(in_buf_t));

	ib->nb = nb;
	ib->next = NULL;
	[in_buf_lock lock];
	if(in_buf_next == NULL) {
		in_buf_next = in_buf_last = ib;
	}
	else {
		in_buf_last->next = ib;
		in_buf_last = ib;
	}
	[in_buf_lock unlock];
#ifdef	notdef
	[buf_wait_lock lock];
	[buf_wait_lock unlockWith:TRUE];
#endif	notdef
	return 0;
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.