1 
2 /****************************************************************/
3 /*								*/
4 /*	nettest_dlpi.c						*/
5 /*								*/
6 /*	the actual test routines...				*/
7 /*								*/
8 /*	send_dlpi_co_stream()	perform a CO DLPI stream test	*/
9 /*	recv_dlpi_co_stream()					*/
10 /*	send_dlpi_co_rr()	perform a CO DLPI req/res	*/
11 /*	recv_dlpi_co_rr()					*/
12 /*	send_dlpi_cl_stream()	perform a CL DLPI stream test	*/
13 /*	recv_dlpi_cl_stream()					*/
14 /*	send_dlpi_cl_rr()	perform a CL DLPI req/res	*/
15 /*	recv_dlpi_cl_rr()					*/
16 /*								*/
17 /****************************************************************/
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #ifdef WANT_DLPI
24 char	nettest_dlpi_id[]="\
25 @(#)nettest_dlpi.c (c) Copyright 1993,1995,2004 Hewlett-Packard Co. Version 2.4.3";
26 
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
34 #include <malloc.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/poll.h>
38 #ifdef __osf__
39 #include <sys/dlpihdr.h>
40 #else /* __osf__ */
41 #include <sys/dlpi.h>
42 #ifdef __hpux__
43 #include <sys/dlpi_ext.h>
44 #endif /* __hpux__ */
45 #endif /* __osf__ */
46 
47 #include "netlib.h"
48 #include "netsh.h"
49 #include "nettest_dlpi.h"
50 
51 /* these are some variables global to all the DLPI tests. declare */
52 /* them static to make them global only to this file */
53 
54 static int
55   rsw_size,		/* remote send window size	*/
56   rrw_size,		/* remote recv window size	*/
57   lsw_size,		/* local  send window size 	*/
58   lrw_size,		/* local  recv window size 	*/
59   req_size = 100,	/* request size                   	*/
60   rsp_size = 200,	/* response size			*/
61   send_size,		/* how big are individual sends		*/
62   recv_size;		/* how big are individual receives	*/
63 
64 int
65   loc_ppa = 4,          /* the ppa for the local interface, */
66   /* as shown as the NM Id in lanscan */
67   rem_ppa = 4,          /* the ppa for the remote interface */
68   dlpi_sap = 84;        /* which 802.2 SAP should we use?   */
69 
70 char loc_dlpi_device[32] = "/dev/dlpi";
71 char rem_dlpi_device[32] = "/dev/dlpi";
72 
73 char dlpi_usage[] = "\n\
74 Usage: netperf [global options] -- [test options] \n\
75 \n\
76 CO/CL DLPI Test Options:\n\
77     -D dev[,dev]      Set the local/remote DLPI device file name\n\
78     -h                Display this text\n\
79     -M bytes          Set the recv size (DLCO_STREAM, DLCL_STREAM)\n\
80     -m bytes          Set the send size (DLCO_STREAM, DLCL_STREAM)\n\
81     -p loc[,rem]      Set the local/remote PPA for the test\n\
82     -R bytes          Set response size (DLCO_RR, DLCL_RR)\n\
83     -r bytes          Set request size (DLCO_RR, DLCL_RR)\n\
84     -s sap            Set the 802.2 sap for the test\n\
85     -W send[,recv]    Set remote send/recv window sizes\n\
86     -w send[,recv]    Set local send/recv window sizes\n\
87 \n\
88 For those options taking two parms, at least one must be specified;\n\
89 specifying one value without a comma will set both parms to that\n\
90 value, specifying a value with a leading comma will set just the second\n\
91 parm, a value with a trailing comma will set just the first. To set\n\
92 each parm to unique values, specify both and separate them with a\n\
93 comma.\n";
94 
95 
96 /* This routine implements the CO unidirectional data transfer test */
97 /* (a.k.a. stream) for the sockets interface. It receives its */
98 /* parameters via global variables from the shell and writes its */
99 /* output to the standard output. */
100 
101 
102 void
send_dlpi_co_stream()103 send_dlpi_co_stream()
104 {
105 
106   char *tput_title = "\
107 Recv   Send    Send                          \n\
108 Window Window  Message  Elapsed              \n\
109 Size   Size    Size     Time     Throughput  \n\
110 frames frames  bytes    secs.    %s/sec  \n\n";
111 
112   char *tput_fmt_0 =
113     "%7.2f\n";
114 
115   char *tput_fmt_1 =
116     "%5d  %5d  %6d    %-6.2f   %7.2f   \n";
117 
118   char *cpu_title = "\
119 Recv   Send    Send                          Utilization    Service Demand\n\
120 Window Window  Message  Elapsed              Send   Recv    Send    Recv\n\
121 Size   Size    Size     Time     Throughput  local  remote  local   remote\n\
122 frames frames  bytes    secs.    %-8.8s/s  %%      %%       us/KB   us/KB\n\n";
123 
124   char *cpu_fmt_0 =
125     "%6.3f\n";
126 
127   char *cpu_fmt_1 =
128     "%5d  %5d  %6d    %-6.2f     %7.2f   %-6.2f %-6.2f  %-6.3f  %-6.3f\n";
129 
130   char *ksink_fmt = "\n\
131 Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
132 Local  Remote  Local  Remote  Xfered   Per                 Per\n\
133 Send   Recv    Send   Recv             Send (avg)          Recv (avg)\n\
134 %5d   %5d  %5d   %5d %6.4g  %6.2f     %6d %6.2f   %6d\n";
135 
136 
137   float			elapsed_time;
138 
139 #ifdef WANT_INTERVALS
140   int interval_count;
141 #endif /* WANT_INTERVALS */
142 
143   /* what we want is to have a buffer space that is at least one */
144   /* send-size greater than our send window. this will insure that we */
145   /* are never trying to re-use a buffer that may still be in the hands */
146   /* of the transport. This buffer will be malloc'd after we have found */
147   /* the size of the local senc socket buffer. We will want to deal */
148   /* with alignment and offset concerns as well. */
149 
150   struct ring_elt *send_ring;
151   char	*message;
152   char	*message_ptr;
153   struct strbuf send_message;
154   char  dlsap[BUFSIZ];
155   int   dlsap_len;
156   int	*message_int_ptr;
157   int	message_offset;
158   int	malloc_size;
159 
160   int	len;
161   int	nummessages;
162   int	send_descriptor;
163   int	bytes_remaining;
164   /* with links like fddi, one can send > 32 bits worth of bytes */
165   /* during a test... ;-) */
166   double	bytes_sent;
167 
168 #ifdef DIRTY
169   int	i;
170 #endif /* DIRTY */
171 
172   float	local_cpu_utilization;
173   float	local_service_demand;
174   float	remote_cpu_utilization;
175   float	remote_service_demand;
176   double	thruput;
177 
178   struct	dlpi_co_stream_request_struct	*dlpi_co_stream_request;
179   struct	dlpi_co_stream_response_struct	*dlpi_co_stream_response;
180   struct	dlpi_co_stream_results_struct	*dlpi_co_stream_result;
181 
182   dlpi_co_stream_request	=
183     (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
184   dlpi_co_stream_response	=
185     (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
186   dlpi_co_stream_result	        =
187     (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
188 
189   if ( print_headers ) {
190     fprintf(where,"DLPI CO STREAM TEST\n");
191     if (local_cpu_usage || remote_cpu_usage)
192       fprintf(where,cpu_title,format_units());
193     else
194       fprintf(where,tput_title,format_units());
195   }
196 
197   /* initialize a few counters */
198 
199   nummessages	=	0;
200   bytes_sent	=	0.0;
201   times_up 	= 	0;
202 
203   /*set up the data descriptor                        */
204   send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
205   if (send_descriptor < 0){
206     perror("netperf: send_dlpi_co_stream: dlpi stream data descriptor");
207     exit(1);
208   }
209 
210   /* bind the puppy and get the assigned dlsap */
211   dlsap_len = BUFSIZ;
212   if (dl_bind(send_descriptor,
213               dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
214     fprintf(where,"send_dlpi_co_rr: bind failure\n");
215     fflush(where);
216     exit(1);
217   }
218 
219   if (debug) {
220     fprintf(where,"send_dlpi_co_stream: send_descriptor obtained...\n");
221   }
222 
223 #ifdef DL_HP_SET_LOCAL_WIN_REQ
224   if (lsw_size > 0) {
225     if (debug > 1) {
226       fprintf(where,"netperf: send_dlpi_co_stream: window send size altered from system default...\n");
227       fprintf(where,"                          send: %d\n",lsw_size);
228     }
229   }
230   if (lrw_size > 0) {
231     if (debug > 1) {
232       fprintf(where,
233 	      "netperf: send_dlpi_co_stream: window recv size altered from system default...\n");
234       fprintf(where,"                          recv: %d\n",lrw_size);
235     }
236   }
237 
238 
239   /* Now, we will find-out what the size actually became, and report */
240   /* that back to the user. If the call fails, we will just report a -1 */
241   /* back to the initiator for the recv buffer size. */
242 
243 
244   if (debug) {
245     fprintf(where,
246 	    "netperf: send_dlpi_co_stream: window sizes determined...\n");
247     fprintf(where,"         send: %d recv: %d\n",lsw_size,lrw_size);
248     ffluch(where);
249   }
250 
251 #else /* DL_HP_SET_LOCAL_WIN_REQ */
252 
253   lsw_size = -1;
254   lrw_size = -1;
255 
256 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
257 
258   /* we should pick a default send_size, it should not be larger than */
259   /* the min of the two interface MTU's, and should perhaps default to */
260   /* the Interface MTU, but for now, we will default it to 1024... if */
261   /* someone wants to change this, the should change the corresponding */
262   /* lines in the recv_dlpi_co_stream routine */
263 
264   if (send_size == 0) {
265     send_size = 1024;
266   }
267 
268   /* set-up the data buffer with the requested alignment and offset. */
269   /* After we have calculated the proper starting address, we want to */
270   /* put that back into the message variable so we go back to the */
271   /* proper place. note that this means that only the first send is */
272   /* guaranteed to be at the alignment specified by the -a parameter. I */
273   /* think that this is a little more "real-world" than what was found */
274   /* in previous versions. note also that we have allocated a quantity */
275   /* of memory that is at least one send-size greater than our socket */
276   /* buffer size. We want to be sure that there are at least two */
277   /* buffers allocated - this can be a bit of a problem when the */
278   /* send_size is bigger than the socket size, so we must check... the */
279   /* user may have wanted to explicitly set the "width" of our send */
280   /* buffers, we should respect that wish... */
281   if (send_width == 0) {
282     send_width = (lsw_size/send_size) + 1;
283     if (send_width == 1) send_width++;
284   }
285 
286   send_ring = allocate_buffer_ring(send_width,
287 				   send_size,
288 				   local_send_align,
289 				   local_send_offset);
290 
291   send_message.maxlen = send_size;
292   send_message.len = send_size;
293   send_message.buf = send_ring->buffer_ptr;
294 
295   /* If the user has requested cpu utilization measurements, we must */
296   /* calibrate the cpu(s). We will perform this task within the tests */
297   /* themselves. If the user has specified the cpu rate, then */
298   /* calibrate_local_cpu will return rather quickly as it will have */
299   /* nothing to do. If local_cpu_rate is zero, then we will go through */
300   /* all the "normal" calibration stuff and return the rate back.*/
301 
302   if (local_cpu_usage) {
303     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
304   }
305 
306   /* Tell the remote end to do a listen. The server alters the socket */
307   /* paramters on the other side at this point, hence the reason for */
308   /* all the values being passed in the setup message. If the user did */
309   /* not specify any of the parameters, they will be passed as 0, which */
310   /* will indicate to the remote that no changes beyond the system's */
311   /* default should be used. */
312 
313   netperf_request.content.request_type	 =	DO_DLPI_CO_STREAM;
314   dlpi_co_stream_request->send_win_size =	rsw_size;
315   dlpi_co_stream_request->recv_win_size =	rrw_size;
316   dlpi_co_stream_request->receive_size	 =	recv_size;
317   dlpi_co_stream_request->recv_alignment=	remote_recv_align;
318   dlpi_co_stream_request->recv_offset	 =	remote_recv_offset;
319   dlpi_co_stream_request->measure_cpu	 =	remote_cpu_usage;
320   dlpi_co_stream_request->cpu_rate	 =	remote_cpu_rate;
321   dlpi_co_stream_request->ppa           =      rem_ppa;
322   dlpi_co_stream_request->sap           =      dlpi_sap;
323   dlpi_co_stream_request->dev_name_len  =      strlen(rem_dlpi_device);
324   strcpy(dlpi_co_stream_request->dlpi_device,
325 	 rem_dlpi_device);
326 
327 #ifdef __alpha
328 
329   /* ok - even on a DEC box, strings are strings. I didn't really want */
330   /* to ntohl the words of a string. since I don't want to teach the */
331   /* send_ and recv_ _request and _response routines about the types, */
332   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
333   /* solution would be to use XDR, but I am still leary of being able */
334   /* to find XDR libs on all platforms I want running netperf. raj */
335   {
336     int *charword;
337     int *initword;
338     int *lastword;
339 
340     initword = (int *) dlpi_co_stream_request->dlpi_device;
341     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
342 
343     for (charword = initword;
344 	 charword < lastword;
345 	 charword++) {
346 
347       *charword = ntohl(*charword);
348     }
349   }
350 #endif /* __alpha */
351 
352   if (test_time) {
353     dlpi_co_stream_request->test_length	=	test_time;
354   }
355   else {
356     dlpi_co_stream_request->test_length	=	test_bytes;
357   }
358 #ifdef DIRTY
359   dlpi_co_stream_request->dirty_count       =       rem_dirty_count;
360   dlpi_co_stream_request->clean_count       =       rem_clean_count;
361 #endif /* DIRTY */
362 
363 
364   if (debug > 1) {
365     fprintf(where,
366 	    "netperf: send_dlpi_co_stream: requesting DLPI CO stream test\n");
367   }
368 
369   send_request();
370 
371   /* The response from the remote will contain all of the relevant 	*/
372   /* parameters for this test type. We will put them back into 	*/
373   /* the variables here so they can be displayed if desired.  The	*/
374   /* remote will have calibrated CPU if necessary, and will have done	*/
375   /* all the needed set-up we will have calibrated the cpu locally	*/
376   /* before sending the request, and will grab the counter value right	*/
377   /* after the connect returns. The remote will grab the counter right	*/
378   /* after the accept call. This saves the hassle of extra messages	*/
379   /* being sent for the TCP tests.					*/
380 
381   recv_response();
382 
383   if (!netperf_response.content.serv_errno) {
384     if (debug)
385       fprintf(where,"remote listen done.\n");
386     rrw_size	=	dlpi_co_stream_response->recv_win_size;
387     rsw_size	=	dlpi_co_stream_response->send_win_size;
388     remote_cpu_usage=	dlpi_co_stream_response->measure_cpu;
389     remote_cpu_rate = 	dlpi_co_stream_response->cpu_rate;
390   }
391   else {
392     Set_errno(netperf_response.content.serv_errno);
393     perror("netperf: remote error");
394     exit(1);
395   }
396 
397   /* Connect up to the remote port on the data descriptor */
398   if(dl_connect(send_descriptor,
399 		dlpi_co_stream_response->station_addr,
400 		dlpi_co_stream_response->station_addr_len) != 0) {
401     fprintf(where,"recv_dlpi_co_stream: connect failure\n");
402     fflush(where);
403     exit(1);
404   }
405 
406   /* Data Socket set-up is finished. If there were problems, either the */
407   /* connect would have failed, or the previous response would have */
408   /* indicated a problem. I failed to see the value of the extra */
409   /* message after the accept on the remote. If it failed, we'll see it */
410   /* here. If it didn't, we might as well start pumping data. */
411 
412   /* Set-up the test end conditions. For a stream test, they can be */
413   /* either time or byte-count based. */
414 
415   if (test_time) {
416     /* The user wanted to end the test after a period of time. */
417     times_up = 0;
418     bytes_remaining = 0;
419     start_timer(test_time);
420   }
421   else {
422     /* The tester wanted to send a number of bytes. */
423     bytes_remaining = test_bytes;
424     times_up = 1;
425   }
426 
427   /* The cpu_start routine will grab the current time and possibly */
428   /* value of the idle counter for later use in measuring cpu */
429   /* utilization and/or service demand and thruput. */
430 
431   cpu_start(local_cpu_usage);
432 
433   /* We use an "OR" to control test execution. When the test is */
434   /* controlled by time, the byte count check will always return false. */
435   /* When the test is controlled by byte count, the time test will */
436   /* always return false. When the test is finished, the whole */
437   /* expression will go false and we will stop sending data. */
438 
439 #ifdef DIRTY
440   /* initialize the random number generator for putting dirty stuff */
441   /* into the send buffer. raj */
442   srand((int) getpid());
443 #endif /* DIRTY */
444 
445   while ((!times_up) || (bytes_remaining > 0)) {
446 
447 #ifdef DIRTY
448     /* we want to dirty some number of consecutive integers in the buffer */
449     /* we are about to send. we may also want to bring some number of */
450     /* them cleanly into the cache. The clean ones will follow any dirty */
451     /* ones into the cache. */
452     message_int_ptr = (int *)message_ptr;
453     for (i = 0; i < loc_dirty_count; i++) {
454       *message_int_ptr = rand();
455       message_int_ptr++;
456     }
457     for (i = 0; i < loc_clean_count; i++) {
458       loc_dirty_count = *message_int_ptr;
459       message_int_ptr++;
460     }
461 #endif /* DIRTY */
462 
463     if((putmsg(send_descriptor,
464 	       0,
465 	       &send_message,
466 	       0)) != 0) {
467       if (errno == EINTR)
468 	break;
469       perror("netperf: data send error");
470       exit(1);
471     }
472     send_ring = send_ring->next;
473     send_message.buf = send_ring->buffer_ptr;
474 #ifdef WANT_INTERVALS
475     for (interval_count = 0;
476 	 interval_count < interval_wate;
477 	 interval_count++);
478 #endif /* WANT_INTERVALS */
479 
480     if (debug > 4) {
481       fprintf(where,"netperf: send_clpi_co_stream: putmsg called ");
482       fprintf(where,"len is %d\n",send_message.len);
483       fflush(where);
484     }
485 
486     nummessages++;
487     if (bytes_remaining) {
488       bytes_remaining -= send_size;
489     }
490   }
491 
492   /* The test is over. Flush the buffers to the remote end. We do a */
493   /* graceful release to insure that all data has been taken by the */
494   /* remote. this needs a little work - there is no three-way */
495   /* handshake with type two as there is with TCP, so there really */
496   /* should be a message exchange here. however, we will finesse it by */
497   /* saying that the tests shoudl run for a while. */
498 
499   if (debug) {
500     fprintf(where,"sending test end signal \n");
501     fflush(where);
502   }
503 
504   send_message.len = (send_size - 1);
505   if (send_message.len == 0) send_message.len = 2;
506 
507   if((putmsg(send_descriptor,
508 	     0,
509 	     &send_message,
510 	     0)) != 0) {
511     perror("netperf: data send error");
512     exit(1);
513   }
514 
515   /* this call will always give us the elapsed time for the test, and */
516   /* will also store-away the necessaries for cpu utilization */
517 
518   cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being measured? */
519   /* how long did we really run? */
520 
521   /* Get the statistics from the remote end. The remote will have */
522   /* calculated service demand and all those interesting things. If it */
523   /* wasn't supposed to care, it will return obvious values. */
524 
525   recv_response();
526   if (!netperf_response.content.serv_errno) {
527     if (debug)
528       fprintf(where,"remote results obtained\n");
529   }
530   else {
531     Set_errno(netperf_response.content.serv_errno);
532     perror("netperf: remote error");
533 
534     exit(1);
535   }
536 
537   /* We now calculate what our thruput was for the test. In the future, */
538   /* we may want to include a calculation of the thruput measured by */
539   /* the remote, but it should be the case that for a TCP stream test, */
540   /* that the two numbers should be *very* close... We calculate */
541   /* bytes_sent regardless of the way the test length was controlled. */
542   /* If it was time, we needed to, and if it was by bytes, the user may */
543   /* have specified a number of bytes that wasn't a multiple of the */
544   /* send_size, so we really didn't send what he asked for ;-) */
545 
546   bytes_sent	= ((double) send_size * (double) nummessages) + (double) len;
547   thruput		= calc_thruput(bytes_sent);
548 
549   if (local_cpu_usage || remote_cpu_usage) {
550     /* We must now do a little math for service demand and cpu */
551     /* utilization for the system(s) */
552     /* Of course, some of the information might be bogus because */
553     /* there was no idle counter in the kernel(s). We need to make */
554     /* a note of this for the user's benefit...*/
555     if (local_cpu_usage) {
556       if (local_cpu_rate == 0.0) {
557 	fprintf(where,
558 		"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
559 	fprintf(where,
560 		"Local CPU usage numbers based on process information only!\n");
561 	fflush(where);
562       }
563       local_cpu_utilization	= calc_cpu_util(0.0);
564       local_service_demand	= calc_service_demand(bytes_sent,
565 						      0.0,
566 						      0.0,
567 						      0);
568     }
569     else {
570       local_cpu_utilization	= -1.0;
571       local_service_demand	= -1.0;
572     }
573 
574     if (remote_cpu_usage) {
575       if (remote_cpu_rate == 0.0) {
576 	fprintf(where,
577 		"DANGER   DANGER  DANGER   DANGER   DANGER  DANGER   DANGER!\n");
578 	fprintf(where,
579 		"Remote CPU usage numbers based on process information only!\n");
580 	fflush(where);
581       }
582       remote_cpu_utilization	= dlpi_co_stream_result->cpu_util;
583       remote_service_demand	= calc_service_demand(bytes_sent,
584 						      0.0,
585 						      remote_cpu_utilization,
586 						      dlpi_co_stream_result->num_cpus);
587     }
588     else {
589       remote_cpu_utilization = -1.0;
590       remote_service_demand  = -1.0;
591     }
592 
593     /* We are now ready to print all the information. If the user */
594     /* has specified zero-level verbosity, we will just print the */
595     /* local service demand, or the remote service demand. If the */
596     /* user has requested verbosity level 1, he will get the basic */
597     /* "streamperf" numbers. If the user has specified a verbosity */
598     /* of greater than 1, we will display a veritable plethora of */
599     /* background information from outside of this block as it it */
600     /* not cpu_measurement specific...  */
601 
602     switch (verbosity) {
603     case 0:
604       if (local_cpu_usage) {
605 	fprintf(where,
606 		cpu_fmt_0,
607 		local_service_demand);
608       }
609       else {
610 	fprintf(where,
611 		cpu_fmt_0,
612 		remote_service_demand);
613       }
614       break;
615     case 1:
616     case 2:
617       fprintf(where,
618 	      cpu_fmt_1,		/* the format string */
619 	      rrw_size,		/* remote recvbuf size */
620 	      lsw_size,		/* local sendbuf size */
621 	      send_size,		/* how large were the sends */
622 	      elapsed_time,		/* how long was the test */
623 	      thruput, 		/* what was the xfer rate */
624 	      local_cpu_utilization,	/* local cpu */
625 	      remote_cpu_utilization,	/* remote cpu */
626 	      local_service_demand,	/* local service demand */
627 	      remote_service_demand);	/* remote service demand */
628       break;
629     }
630   }
631   else {
632     /* The tester did not wish to measure service demand. */
633     switch (verbosity) {
634     case 0:
635       fprintf(where,
636 	      tput_fmt_0,
637 	      thruput);
638       break;
639     case 1:
640     case 2:
641       fprintf(where,
642 	      tput_fmt_1,		/* the format string */
643 	      rrw_size, 		/* remote recvbuf size */
644 	      lsw_size, 		/* local sendbuf size */
645 	      send_size,		/* how large were the sends */
646 	      elapsed_time, 		/* how long did it take */
647 	      thruput);/* how fast did it go */
648       break;
649     }
650   }
651 
652   /* it would be a good thing to include information about some of the */
653   /* other parameters that may have been set for this test, but at the */
654   /* moment, I do not wish to figure-out all the  formatting, so I will */
655   /* just put this comment here to help remind me that it is something */
656   /* that should be done at a later time. */
657 
658   if (verbosity > 1) {
659     /* The user wanted to know it all, so we will give it to him. */
660     /* This information will include as much as we can find about */
661     /* TCP statistics, the alignments of the sends and receives */
662     /* and all that sort of rot... */
663 
664     fprintf(where,
665 	    ksink_fmt,
666 	    "Bytes",
667 	    "Bytes",
668 	    "Bytes",
669 	    local_send_align,
670 	    remote_recv_align,
671 	    local_send_offset,
672 	    remote_recv_offset,
673 	    bytes_sent,
674 	    bytes_sent / (double)nummessages,
675 	    nummessages,
676 	    bytes_sent / (double)dlpi_co_stream_result->recv_calls,
677 	    dlpi_co_stream_result->recv_calls);
678   }
679 
680 }
681 
682 
683 /* This is the server-side routine for the tcp stream test. It is */
684 /* implemented as one routine. I could break things-out somewhat, but */
685 /* didn't feel it was necessary. */
686 
687 int
recv_dlpi_co_stream()688   recv_dlpi_co_stream()
689 {
690 
691   int	data_descriptor;
692   int	flags = 0;
693   int	measure_cpu;
694   int	bytes_received;
695   int	receive_calls;
696   float	elapsed_time;
697 
698   struct ring_elt *recv_ring;
699   char	*message_ptr;
700   char	*message;
701   int   *message_int_ptr;
702   struct strbuf recv_message;
703   int   dirty_count;
704   int   clean_count;
705   int   i;
706 
707   struct	dlpi_co_stream_request_struct	*dlpi_co_stream_request;
708   struct	dlpi_co_stream_response_struct	*dlpi_co_stream_response;
709   struct	dlpi_co_stream_results_struct	*dlpi_co_stream_results;
710 
711   dlpi_co_stream_request	= (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
712   dlpi_co_stream_response	= (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
713   dlpi_co_stream_results	= (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
714 
715   if (debug) {
716     fprintf(where,"netserver: recv_dlpi_co_stream: entered...\n");
717     fflush(where);
718   }
719 
720   /* We want to set-up the listen socket with all the desired */
721   /* parameters and then let the initiator know that all is ready. If */
722   /* socket size defaults are to be used, then the initiator will have */
723   /* sent us 0's. If the socket sizes cannot be changed, then we will */
724   /* send-back what they are. If that information cannot be determined, */
725   /* then we send-back -1's for the sizes. If things go wrong for any */
726   /* reason, we will drop back ten yards and punt. */
727 
728   /* If anything goes wrong, we want the remote to know about it. It */
729   /* would be best if the error that the remote reports to the user is */
730   /* the actual error we encountered, rather than some bogus unexpected */
731   /* response type message. */
732 
733   netperf_response.content.response_type = DLPI_CO_STREAM_RESPONSE;
734 
735   /* We now alter the message_ptr variable to be at the desired */
736   /* alignment with the desired offset. */
737 
738   if (debug > 1) {
739     fprintf(where,"recv_dlpi_co_stream: requested alignment of %d\n",
740 	    dlpi_co_stream_request->recv_alignment);
741     fflush(where);
742   }
743 
744 
745   /* Grab a descriptor to listen on, and then listen on it. */
746 
747   if (debug > 1) {
748     fprintf(where,"recv_dlpi_co_stream: grabbing a descriptor...\n");
749     fflush(where);
750   }
751 
752 
753 
754 #ifdef __alpha
755 
756   /* ok - even on a DEC box, strings are strings. I din't really want */
757   /* to ntohl the words of a string. since I don't want to teach the */
758   /* send_ and recv_ _request and _response routines about the types, */
759   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
760   /* solution would be to use XDR, but I am still leary of being able */
761   /* to find XDR libs on all platforms I want running netperf. raj */
762   {
763     int *charword;
764     int *initword;
765     int *lastword;
766 
767     initword = (int *) dlpi_co_stream_request->dlpi_device;
768     lastword = initword + ((dlpi_co_stream_request->dev_name_len + 3) / 4);
769 
770     for (charword = initword;
771 	 charword < lastword;
772 	 charword++) {
773 
774       *charword = htonl(*charword);
775     }
776   }
777 #endif /* __alpha */
778 
779   data_descriptor = dl_open(dlpi_co_stream_request->dlpi_device,
780 			    dlpi_co_stream_request->ppa);
781   if (data_descriptor < 0) {
782     netperf_response.content.serv_errno = errno;
783     send_response();
784     exit(1);
785   }
786 
787   /* Let's get an address assigned to this descriptor so we can tell the */
788   /* initiator how to reach the data descriptor. There may be a desire to */
789   /* nail this descriptor to a specific address in a multi-homed, */
790   /* multi-connection situation, but for now, we'll ignore the issue */
791   /* and concentrate on single connection testing. */
792 
793   /* bind the sap and retrieve the dlsap assigned by the system  */
794   dlpi_co_stream_response->station_addr_len = 14; /* arbitrary */
795   if (dl_bind(data_descriptor,
796 	      dlpi_co_stream_request->sap,
797 	      DL_CODLS,
798 	      (char *)dlpi_co_stream_response->station_addr,
799 	      &dlpi_co_stream_response->station_addr_len) != 0) {
800     fprintf(where,"recv_dlpi_co_stream: bind failure\n");
801     fflush(where);
802     exit(1);
803   }
804 
805   /* The initiator may have wished-us to modify the socket buffer */
806   /* sizes. We should give it a shot. If he didn't ask us to change the */
807   /* sizes, we should let him know what sizes were in use at this end. */
808   /* If none of this code is compiled-in, then we will tell the */
809   /* initiator that we were unable to play with the socket buffer by */
810   /* setting the size in the response to -1. */
811 
812 #ifdef DL_HP_SET_LOCAL_WIN_REQ
813 
814   if (dlpi_co_stream_request->recv_win_size) {
815   }
816   /* Now, we will find-out what the size actually became, and report */
817   /* that back to the user. If the call fails, we will just report a -1 */
818   /* back to the initiator for the recv buffer size. */
819 
820 #else /* the system won't let us play with the buffers */
821 
822   dlpi_co_stream_response->recv_win_size	= -1;
823 
824 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
825 
826   /* what sort of sizes did we end-up with? */
827   /* this bit of code whould default to the Interface MTU */
828   if (dlpi_co_stream_request->receive_size == 0) {
829     recv_size = 1024;
830   }
831   else {
832     recv_size = dlpi_co_stream_request->receive_size;
833   }
834 
835   /* tell the other fellow what our receive size became */
836   dlpi_co_stream_response->receive_size = recv_size;
837 
838   /* just a little prep work for when we may have to behave like the */
839   /* sending side... */
840   message = (char *)malloc(recv_size * 2);
841   if (message == NULL) {
842     printf("malloc(%d) failed!\n", recv_size * 2);
843     exit(1);
844   }
845 
846   message_ptr = ALIGN_BUFFER(message, dlpi_co_stream_request->recv_alignment, dlpi_co_stream_request->recv_offset);
847   recv_message.maxlen = recv_size;
848   recv_message.len = 0;
849   recv_message.buf = message_ptr;
850 
851   if (debug > 1) {
852     fprintf(where,
853 	    "recv_dlpi_co_stream: receive alignment and offset set...\n");
854     fflush(where);
855   }
856 
857   netperf_response.content.serv_errno   = 0;
858 
859   /* But wait, there's more. If the initiator wanted cpu measurements, */
860   /* then we must call the calibrate routine, which will return the max */
861   /* rate back to the initiator. If the CPU was not to be measured, or */
862   /* something went wrong with the calibration, we will return a -1 to */
863   /* the initiator. */
864 
865   dlpi_co_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
866   if (dlpi_co_stream_request->measure_cpu) {
867     dlpi_co_stream_response->measure_cpu = 1;
868     dlpi_co_stream_response->cpu_rate =
869       calibrate_local_cpu(dlpi_co_stream_request->cpu_rate);
870   }
871 
872   send_response();
873 
874   /* accept a connection on this file descriptor. at some point, */
875   /* dl_accept will "do the right thing" with the last two parms, but */
876   /* for now it ignores them, so we will pass zeros. */
877 
878   if(dl_accept(data_descriptor, 0, 0) != 0) {
879     fprintf(where,
880 	    "recv_dlpi_co_stream: error in accept, errno %d\n",
881 	    errno);
882     fflush(where);
883     netperf_response.content.serv_errno = errno;
884     send_response();
885     exit(1);
886   }
887 
888   if (debug) {
889     fprintf(where,"netserver:recv_dlpi_co_stream: connection accepted\n");
890     fflush(where);
891   }
892 
893   /* Now it's time to start receiving data on the connection. We will */
894   /* first grab the apropriate counters and then start grabbing. */
895 
896   cpu_start(dlpi_co_stream_request->measure_cpu);
897 
898 #ifdef DIRTY
899   /* we want to dirty some number of consecutive integers in the buffer */
900   /* we are about to recv. we may also want to bring some number of */
901   /* them cleanly into the cache. The clean ones will follow any dirty */
902   /* ones into the cache. */
903 
904   dirty_count = dlpi_co_stream_request->dirty_count;
905   clean_count = dlpi_co_stream_request->clean_count;
906   message_int_ptr = (int *)message_ptr;
907   for (i = 0; i < dirty_count; i++) {
908     *message_int_ptr = rand();
909     message_int_ptr++;
910   }
911   for (i = 0; i < clean_count; i++) {
912     dirty_count = *message_int_ptr;
913     message_int_ptr++;
914   }
915 #endif /* DIRTY */
916 
917   recv_message.len = recv_size;
918   while (recv_message.len == recv_size) {
919     if (getmsg(data_descriptor,
920 	       0,
921 	       &recv_message,
922 	       &flags) != 0) {
923       netperf_response.content.serv_errno = errno;
924       send_response();
925       exit(1);
926     }
927     bytes_received += recv_message.len;
928     receive_calls++;
929 
930     if (debug) {
931       fprintf(where,
932 	      "netserver:recv_dlpi_co_stream: getmsg accepted %d bytes\n",
933 	      recv_message.len);
934       fflush(where);
935     }
936 
937 
938 #ifdef DIRTY
939     message_int_ptr = (int *)message_ptr;
940     for (i = 0; i < dirty_count; i++) {
941       *message_int_ptr = rand();
942       message_int_ptr++;
943     }
944     for (i = 0; i < clean_count; i++) {
945       dirty_count = *message_int_ptr;
946       message_int_ptr++;
947     }
948 #endif /* DIRTY */
949 
950   }
951 
952   /* The loop now exits due to zero bytes received. */
953   /* should perform a disconnect to signal the sender that */
954   /* we have received all the data sent. */
955 
956   if (close(data_descriptor) == -1) {
957     netperf_response.content.serv_errno = errno;
958     send_response();
959     exit(1);
960   }
961 
962   cpu_stop(dlpi_co_stream_request->measure_cpu,&elapsed_time);
963 
964   /* send the results to the sender			*/
965 
966   if (debug) {
967     fprintf(where,
968 	    "recv_dlpi_co_stream: got %d bytes\n",
969 	    bytes_received);
970     fprintf(where,
971 	    "recv_dlpi_co_stream: got %d recvs\n",
972 	    receive_calls);
973     fflush(where);
974   }
975 
976   dlpi_co_stream_results->bytes_received	= bytes_received;
977   dlpi_co_stream_results->elapsed_time	= elapsed_time;
978   dlpi_co_stream_results->recv_calls		= receive_calls;
979 
980   if (dlpi_co_stream_request->measure_cpu) {
981     dlpi_co_stream_results->cpu_util	= calc_cpu_util(0.0);
982   };
983 
984   if (debug > 1) {
985     fprintf(where,
986 	    "recv_dlpi_co_stream: test complete, sending results.\n");
987     fflush(where);
988   }
989 
990   send_response();
991 }
992 
993 /*********************************/
994 
send_dlpi_co_rr(char remote_host[])995 int send_dlpi_co_rr(char remote_host[])
996 {
997 
998   char *tput_title = "\
999  Local /Remote\n\
1000  Window Size   Request  Resp.   Elapsed  Trans.\n\
1001  Send   Recv   Size     Size    Time     Rate         \n\
1002  frames frames bytes    bytes   secs.    per sec   \n\n";
1003 
1004   char *tput_fmt_0 =
1005     "%7.2f\n";
1006 
1007   char *tput_fmt_1_line_1 = "\
1008  %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
1009   char *tput_fmt_1_line_2 = "\
1010  %-6d %-6d\n";
1011 
1012   char *cpu_title = "\
1013  Local /Remote\n\
1014  Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
1015  Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
1016  frames frames bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Tr\n\n";
1017 
1018   char *cpu_fmt_0 =
1019     "%6.3f\n";
1020 
1021   char *cpu_fmt_1_line_1 = "\
1022  %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
1023 
1024   char *cpu_fmt_1_line_2 = "\
1025  %-6d %-6d\n";
1026 
1027   char *ksink_fmt = "\
1028  Alignment      Offset\n\
1029  Local  Remote  Local  Remote\n\
1030  Send   Recv    Send   Recv\n\
1031  %5d  %5d   %5d  %5d\n";
1032 
1033 
1034   int			timed_out = 0;
1035   float			elapsed_time;
1036   int	    dlsap_len;
1037   char      dlsap[BUFSIZ];
1038 
1039   int   flags = 0;
1040   char	*send_message_ptr;
1041   char	*recv_message_ptr;
1042   char	*temp_message_ptr;
1043   struct strbuf send_message;
1044   struct strbuf recv_message;
1045 
1046   int	nummessages;
1047   int	send_descriptor;
1048   int	trans_remaining;
1049   double	bytes_xferd;
1050 
1051   int	rsp_bytes_left;
1052 
1053   /* we assume that station adresses fit within two ints */
1054   unsigned int   remote_address[1];
1055 
1056   float	local_cpu_utilization;
1057   float	local_service_demand;
1058   float	remote_cpu_utilization;
1059   float	remote_service_demand;
1060   double	thruput;
1061 
1062   struct	dlpi_co_rr_request_struct	*dlpi_co_rr_request;
1063   struct	dlpi_co_rr_response_struct	*dlpi_co_rr_response;
1064   struct	dlpi_co_rr_results_struct	*dlpi_co_rr_result;
1065 
1066   dlpi_co_rr_request	=
1067     (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
1068   dlpi_co_rr_response	=
1069     (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
1070   dlpi_co_rr_result	=
1071     (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
1072 
1073   /* since we are now disconnected from the code that established the */
1074   /* control socket, and since we want to be able to use different */
1075   /* protocols and such, we are passed the name of the remote host and */
1076   /* must turn that into the test specific addressing information. */
1077 
1078   if ( print_headers ) {
1079     fprintf(where,"DLPI CO REQUEST/RESPONSE TEST\n");
1080     if (local_cpu_usage || remote_cpu_usage)
1081       fprintf(where,cpu_title,format_units());
1082     else
1083       fprintf(where,tput_title,format_units());
1084   }
1085 
1086   /* initialize a few counters */
1087 
1088   nummessages	=	0;
1089   bytes_xferd	=	0.0;
1090   times_up 	= 	0;
1091 
1092   /* set-up the data buffers with the requested alignment and offset */
1093   temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
1094   if (temp_message_ptr == NULL) {
1095     printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET);
1096     exit(1);
1097   }
1098   send_message_ptr = (char *)(( (long) temp_message_ptr +
1099 			       (long) local_send_align - 1) &
1100 			      ~((long) local_send_align - 1));
1101   send_message_ptr = send_message_ptr + local_send_offset;
1102   send_message.maxlen = req_size+MAXALIGNMENT+MAXOFFSET;
1103   send_message.len    = req_size;
1104   send_message.buf    = send_message_ptr;
1105 
1106   temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
1107   if (temp_message_ptr == NULL) {
1108     printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET);
1109     exit(1);
1110   }
1111   recv_message_ptr = (char *)(( (long) temp_message_ptr +
1112 			       (long) local_recv_align - 1) &
1113 			      ~((long) local_recv_align - 1));
1114   recv_message_ptr = recv_message_ptr + local_recv_offset;
1115   recv_message.maxlen = rsp_size+MAXALIGNMENT+MAXOFFSET;
1116   recv_message.len    = 0;
1117   recv_message.buf    = send_message_ptr;
1118 
1119   /*set up the data socket                        */
1120 
1121   send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
1122   if (send_descriptor < 0){
1123     perror("netperf: send_dlpi_co_rr: tcp stream data descriptor");
1124     exit(1);
1125   }
1126 
1127   if (debug) {
1128     fprintf(where,"send_dlpi_co_rr: send_descriptor obtained...\n");
1129   }
1130 
1131   /* bind the puppy and get the assigned dlsap */
1132 
1133   dlsap_len = BUFSIZ;
1134   if (dl_bind(send_descriptor,
1135 	      dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
1136     fprintf(where,"send_dlpi_co_rr: bind failure\n");
1137     fflush(where);
1138     exit(1);
1139   }
1140 
1141   /* Modify the local socket size. The reason we alter the send buffer */
1142   /* size here rather than when the connection is made is to take care */
1143   /* of decreases in buffer size. Decreasing the window size after */
1144   /* connection establishment is a TCP no-no. Also, by setting the */
1145   /* buffer (window) size before the connection is established, we can */
1146   /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
1147   /* the minimum receive buffer size at each half of the connection. */
1148   /* This is why we are altering the receive buffer size on the sending */
1149   /* size of a unidirectional transfer. If the user has not requested */
1150   /* that the socket buffers be altered, we will try to find-out what */
1151   /* their values are. If we cannot touch the socket buffer in any way, */
1152   /* we will set the values to -1 to indicate that.  */
1153 
1154 #ifdef DL_HP_SET_LOCAL_WIN_REQ
1155   if (lsw_size > 0) {
1156     if (debug > 1) {
1157       fprintf(where,"netperf: send_dlpi_co_rr: socket send size altered from system default...\n");
1158       fprintf(where,"                          send: %d\n",lsw_size);
1159     }
1160   }
1161   if (lrw_size > 0) {
1162     if (debug > 1) {
1163       fprintf(where,"netperf: send_dlpi_co_rr: socket recv size altered from system default...\n");
1164       fprintf(where,"                          recv: %d\n",lrw_size);
1165     }
1166   }
1167 
1168 
1169   /* Now, we will find-out what the size actually became, and report */
1170   /* that back to the user. If the call fails, we will just report a -1 */
1171   /* back to the initiator for the recv buffer size. */
1172 
1173 
1174   if (debug) {
1175     fprintf(where,"netperf: send_dlpi_co_rr: socket sizes determined...\n");
1176     fprintf(where,"         send: %d recv: %d\n",lsw_size,lrw_size);
1177   }
1178 
1179 #else /* DL_HP_SET_LOCAL_WIN_REQ */
1180 
1181   lsw_size = -1;
1182   lrw_size = -1;
1183 
1184 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
1185 
1186   /* If the user has requested cpu utilization measurements, we must */
1187   /* calibrate the cpu(s). We will perform this task within the tests */
1188   /* themselves. If the user has specified the cpu rate, then */
1189   /* calibrate_local_cpu will return rather quickly as it will have */
1190   /* nothing to do. If local_cpu_rate is zero, then we will go through */
1191   /* all the "normal" calibration stuff and return the rate back.*/
1192 
1193   if (local_cpu_usage) {
1194     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1195   }
1196 
1197   /* Tell the remote end to do a listen. The server alters the socket */
1198   /* paramters on the other side at this point, hence the reason for */
1199   /* all the values being passed in the setup message. If the user did */
1200   /* not specify any of the parameters, they will be passed as 0, which */
1201   /* will indicate to the remote that no changes beyond the system's */
1202   /* default should be used. Alignment is the exception, it will */
1203   /* default to 8, which will be no alignment alterations. */
1204 
1205   netperf_request.content.request_type	        =	DO_DLPI_CO_RR;
1206   dlpi_co_rr_request->recv_win_size	=	rrw_size;
1207   dlpi_co_rr_request->send_win_size	=	rsw_size;
1208   dlpi_co_rr_request->recv_alignment	=	remote_recv_align;
1209   dlpi_co_rr_request->recv_offset	=	remote_recv_offset;
1210   dlpi_co_rr_request->send_alignment	=	remote_send_align;
1211   dlpi_co_rr_request->send_offset	=	remote_send_offset;
1212   dlpi_co_rr_request->request_size	=	req_size;
1213   dlpi_co_rr_request->response_size	=	rsp_size;
1214   dlpi_co_rr_request->measure_cpu	=	remote_cpu_usage;
1215   dlpi_co_rr_request->cpu_rate	        =	remote_cpu_rate;
1216   dlpi_co_rr_request->ppa               =       rem_ppa;
1217   dlpi_co_rr_request->sap               =       dlpi_sap;
1218   dlpi_co_rr_request->dev_name_len      =       strlen(rem_dlpi_device);
1219   strcpy(dlpi_co_rr_request->dlpi_device,
1220 	 rem_dlpi_device);
1221 #ifdef __alpha
1222 
1223   /* ok - even on a DEC box, strings are strings. I din't really want */
1224   /* to ntohl the words of a string. since I don't want to teach the */
1225   /* send_ and recv_ _request and _response routines about the types, */
1226   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1227   /* solution would be to use XDR, but I am still leary of being able */
1228   /* to find XDR libs on all platforms I want running netperf. raj */
1229   {
1230     int *charword;
1231     int *initword;
1232     int *lastword;
1233 
1234     initword = (int *) dlpi_co_rr_request->dlpi_device;
1235     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
1236 
1237     for (charword = initword;
1238 	 charword < lastword;
1239 	 charword++) {
1240 
1241       *charword = ntohl(*charword);
1242     }
1243   }
1244 #endif /* __alpha */
1245 
1246   if (test_time) {
1247     dlpi_co_rr_request->test_length	=	test_time;
1248   }
1249   else {
1250     dlpi_co_rr_request->test_length	=	test_trans * -1;
1251   }
1252 
1253   if (debug > 1) {
1254     fprintf(where,"netperf: send_dlpi_co_rr: requesting TCP stream test\n");
1255   }
1256 
1257   send_request();
1258 
1259   /* The response from the remote will contain all of the relevant 	*/
1260   /* socket parameters for this test type. We will put them back into 	*/
1261   /* the variables here so they can be displayed if desired.  The	*/
1262   /* remote will have calibrated CPU if necessary, and will have done	*/
1263   /* all the needed set-up we will have calibrated the cpu locally	*/
1264   /* before sending the request, and will grab the counter value right	*/
1265   /* after the connect returns. The remote will grab the counter right	*/
1266   /* after the accept call. This saves the hassle of extra messages	*/
1267   /* being sent for the TCP tests.					*/
1268 
1269   recv_response();
1270 
1271   if (!netperf_response.content.serv_errno) {
1272     if (debug)
1273       fprintf(where,"remote listen done.\n");
1274     rrw_size	=	dlpi_co_rr_response->recv_win_size;
1275     rsw_size	=	dlpi_co_rr_response->send_win_size;
1276     remote_cpu_usage=	dlpi_co_rr_response->measure_cpu;
1277     remote_cpu_rate = 	dlpi_co_rr_response->cpu_rate;
1278 
1279   }
1280   else {
1281     Set_errno(netperf_response.content.serv_errno);
1282     perror("netperf: remote error");
1283 
1284     exit(1);
1285   }
1286 
1287   /*Connect up to the remote port on the data descriptor  */
1288 
1289   if(dl_connect(send_descriptor,
1290 		dlpi_co_rr_response->station_addr,
1291 		dlpi_co_rr_response->station_addr_len) != 0) {
1292     fprintf(where,"send_dlpi_co_rr: connect failure\n");
1293     fflush(where);
1294     exit(1);
1295   }
1296 
1297   /* Data Socket set-up is finished. If there were problems, either the */
1298   /* connect would have failed, or the previous response would have */
1299   /* indicated a problem. I failed to see the value of the extra */
1300   /* message after the accept on the remote. If it failed, we'll see it */
1301   /* here. If it didn't, we might as well start pumping data. */
1302 
1303   /* Set-up the test end conditions. For a request/response test, they */
1304   /* can be either time or transaction based. */
1305 
1306   if (test_time) {
1307     /* The user wanted to end the test after a period of time. */
1308     times_up = 0;
1309     trans_remaining = 0;
1310     start_timer(test_time);
1311   }
1312   else {
1313     /* The tester wanted to send a number of bytes. */
1314     trans_remaining = test_bytes;
1315     times_up = 1;
1316   }
1317 
1318   /* The cpu_start routine will grab the current time and possibly */
1319   /* value of the idle counter for later use in measuring cpu */
1320   /* utilization and/or service demand and thruput. */
1321 
1322   cpu_start(local_cpu_usage);
1323 
1324   /* We use an "OR" to control test execution. When the test is */
1325   /* controlled by time, the byte count check will always return false. */
1326   /* When the test is controlled by byte count, the time test will */
1327   /* always return false. When the test is finished, the whole */
1328   /* expression will go false and we will stop sending data. I think I */
1329   /* just arbitrarily decrement trans_remaining for the timed test, but */
1330   /* will not do that just yet... One other question is whether or not */
1331   /* the send buffer and the receive buffer should be the same buffer. */
1332 
1333   while ((!times_up) || (trans_remaining > 0)) {
1334     /* send the request */
1335     if((putmsg(send_descriptor,
1336 	       0,
1337 	       &send_message,
1338 	       0)) != 0) {
1339       if (errno == EINTR) {
1340 	/* we hit the end of a */
1341 	/* timed test. */
1342 	timed_out = 1;
1343 	break;
1344       }
1345       perror("send_dlpi_co_rr: putmsg error");
1346       exit(1);
1347     }
1348 
1349     if (debug) {
1350       fprintf(where,"recv_message.len %d\n",recv_message.len);
1351       fprintf(where,"send_message.len %d\n",send_message.len);
1352       fflush(where);
1353     }
1354 
1355     /* receive the response */
1356     /* this needs some work with streams buffers if we are going to */
1357     /* support requests and responses larger than the MTU of the */
1358     /* network, but this can wait until later */
1359     rsp_bytes_left = rsp_size;
1360     recv_message.len = rsp_size;
1361     while(rsp_bytes_left > 0) {
1362       if((getmsg(send_descriptor,
1363 		 0,
1364 		 &recv_message,
1365 		 &flags)) < 0) {
1366 	if (errno == EINTR) {
1367 	  /* We hit the end of a timed test. */
1368 	  timed_out = 1;
1369 	  break;
1370 	}
1371 	perror("send_dlpi_co_rr: data recv error");
1372 	exit(1);
1373       }
1374       rsp_bytes_left -= recv_message.len;
1375     }
1376 
1377     if (timed_out) {
1378       /* we may have been in a nested while loop - we need */
1379       /* another call to break. */
1380       break;
1381     }
1382 
1383     nummessages++;
1384     if (trans_remaining) {
1385       trans_remaining--;
1386     }
1387 
1388     if (debug > 3) {
1389       fprintf(where,
1390 	      "Transaction %d completed\n",
1391 	      nummessages);
1392       fflush(where);
1393     }
1394   }
1395 
1396   /* At this point we used to call shutdown onthe data socket to be */
1397   /* sure all the data was delivered, but this was not germane in a */
1398   /* request/response test, and it was causing the tests to "hang" when */
1399   /* they were being controlled by time. So, I have replaced this */
1400   /* shutdown call with a call to close that can be found later in the */
1401   /* procedure. */
1402 
1403   /* this call will always give us the elapsed time for the test, and */
1404   /* will also store-away the necessaries for cpu utilization */
1405 
1406   cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being measured? */
1407   /* how long did we really run? */
1408 
1409   /* Get the statistics from the remote end. The remote will have */
1410   /* calculated service demand and all those interesting things. If it */
1411   /* wasn't supposed to care, it will return obvious values. */
1412 
1413   recv_response();
1414   if (!netperf_response.content.serv_errno) {
1415     if (debug)
1416       fprintf(where,"remote results obtained\n");
1417   }
1418   else {
1419     Set_errno(netperf_response.content.serv_errno);
1420     perror("netperf: remote error");
1421 
1422     exit(1);
1423   }
1424 
1425   /* We now calculate what our thruput was for the test. In the future, */
1426   /* we may want to include a calculation of the thruput measured by */
1427   /* the remote, but it should be the case that for a TCP stream test, */
1428   /* that the two numbers should be *very* close... We calculate */
1429   /* bytes_sent regardless of the way the test length was controlled. */
1430   /* If it was time, we needed to, and if it was by bytes, the user may */
1431   /* have specified a number of bytes that wasn't a multiple of the */
1432   /* send_size, so we really didn't send what he asked for ;-) We use */
1433   /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
1434   /* 1024. A future enhancement *might* be to choose from a couple of */
1435   /* unit selections. */
1436 
1437   bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
1438   thruput		= calc_thruput(bytes_xferd);
1439 
1440   if (local_cpu_usage || remote_cpu_usage) {
1441     /* We must now do a little math for service demand and cpu */
1442     /* utilization for the system(s) */
1443     /* Of course, some of the information might be bogus because */
1444     /* there was no idle counter in the kernel(s). We need to make */
1445     /* a note of this for the user's benefit...*/
1446     if (local_cpu_usage) {
1447       if (local_cpu_rate == 0.0) {
1448 	fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
1449 	fprintf(where,"Local CPU usage numbers based on process information only!\n");
1450 	fflush(where);
1451       }
1452       local_cpu_utilization = calc_cpu_util(0.0);
1453       /* since calc_service demand is doing ms/Kunit we will */
1454       /* multiply the number of transaction by 1024 to get */
1455       /* "good" numbers */
1456       local_service_demand  = calc_service_demand((double) nummessages*1024,
1457 						  0.0,
1458 						  0.0,
1459 						  0);
1460     }
1461     else {
1462       local_cpu_utilization	= -1.0;
1463       local_service_demand	= -1.0;
1464     }
1465 
1466     if (remote_cpu_usage) {
1467       if (remote_cpu_rate == 0.0) {
1468 	fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!\n");
1469 	fprintf(where,"Remote CPU usage numbers based on process information only!\n");
1470 	fflush(where);
1471       }
1472       remote_cpu_utilization = dlpi_co_rr_result->cpu_util;
1473       /* since calc_service demand is doing ms/Kunit we will */
1474       /* multiply the number of transaction by 1024 to get */
1475       /* "good" numbers */
1476       remote_service_demand = calc_service_demand((double) nummessages*1024,
1477 						  0.0,
1478 						  remote_cpu_utilization,
1479 						  dlpi_co_rr_result->num_cpus);
1480     }
1481     else {
1482       remote_cpu_utilization = -1.0;
1483       remote_service_demand  = -1.0;
1484     }
1485 
1486     /* We are now ready to print all the information. If the user */
1487     /* has specified zero-level verbosity, we will just print the */
1488     /* local service demand, or the remote service demand. If the */
1489     /* user has requested verbosity level 1, he will get the basic */
1490     /* "streamperf" numbers. If the user has specified a verbosity */
1491     /* of greater than 1, we will display a veritable plethora of */
1492     /* background information from outside of this block as it it */
1493     /* not cpu_measurement specific...  */
1494 
1495     switch (verbosity) {
1496     case 0:
1497       if (local_cpu_usage) {
1498 	fprintf(where,
1499 		cpu_fmt_0,
1500 		local_service_demand);
1501       }
1502       else {
1503 	fprintf(where,
1504 		cpu_fmt_0,
1505 		remote_service_demand);
1506       }
1507       break;
1508     case 1:
1509       fprintf(where,
1510 	      cpu_fmt_1_line_1,		/* the format string */
1511 	      lsw_size,		/* local sendbuf size */
1512 	      lrw_size,
1513 	      req_size,		/* how large were the requests */
1514 	      rsp_size,		/* guess */
1515 	      elapsed_time,		/* how long was the test */
1516 	      nummessages/elapsed_time,
1517 	      local_cpu_utilization,	/* local cpu */
1518 	      remote_cpu_utilization,	/* remote cpu */
1519 	      local_service_demand,	/* local service demand */
1520 	      remote_service_demand);	/* remote service demand */
1521       fprintf(where,
1522 	      cpu_fmt_1_line_2,
1523 	      rsw_size,
1524 	      rrw_size);
1525       break;
1526     }
1527   }
1528   else {
1529     /* The tester did not wish to measure service demand. */
1530     switch (verbosity) {
1531     case 0:
1532       fprintf(where,
1533 	      tput_fmt_0,
1534 	      nummessages/elapsed_time);
1535       break;
1536     case 1:
1537       fprintf(where,
1538 	      tput_fmt_1_line_1,	/* the format string */
1539 	      lsw_size,
1540 	      lrw_size,
1541 	      req_size,		/* how large were the requests */
1542 	      rsp_size,		/* how large were the responses */
1543 	      elapsed_time, 		/* how long did it take */
1544 	      nummessages/elapsed_time);
1545       fprintf(where,
1546 	      tput_fmt_1_line_2,
1547 	      rsw_size, 		/* remote recvbuf size */
1548 	      rrw_size);
1549 
1550       break;
1551     }
1552   }
1553 
1554   /* it would be a good thing to include information about some of the */
1555   /* other parameters that may have been set for this test, but at the */
1556   /* moment, I do not wish to figure-out all the  formatting, so I will */
1557   /* just put this comment here to help remind me that it is something */
1558   /* that should be done at a later time. */
1559 
1560   if (verbosity > 1) {
1561     /* The user wanted to know it all, so we will give it to him. */
1562     /* This information will include as much as we can find about */
1563     /* TCP statistics, the alignments of the sends and receives */
1564     /* and all that sort of rot... */
1565 
1566     fprintf(where,
1567 	    ksink_fmt);
1568   }
1569   /* The test is over. Kill the data descriptor */
1570 
1571   if (close(send_descriptor) == -1) {
1572     perror("send_dlpi_co_rr: cannot shutdown tcp stream descriptor");
1573   }
1574 
1575 }
1576 
1577 void
send_dlpi_cl_stream(char remote_host[])1578   send_dlpi_cl_stream(char remote_host[])
1579 {
1580   /************************************************************************/
1581   /*									*/
1582   /*               	UDP Unidirectional Send Test                    */
1583   /*									*/
1584   /************************************************************************/
1585   char *tput_title =
1586     "Window  Message  Elapsed      Messages                \n\
1587 Size    Size     Time         Okay Errors   Throughput\n\
1588 frames  bytes    secs            #      #   %s/sec\n\n";
1589 
1590   char *tput_fmt_0 =
1591     "%7.2f\n";
1592 
1593   char *tput_fmt_1 =
1594     "%5d   %5d    %-7.2f   %7d %6d    %7.2f\n\
1595 %5d            %-7.2f   %7d           %7.2f\n\n";
1596 
1597 
1598   char *cpu_title =
1599     "Window  Message  Elapsed      Messages                   CPU     Service\n\
1600 Size    Size     Time         Okay Errors   Throughput   Util    Demand\n\
1601 frames  bytes    secs            #      #   %s/sec   %%       us/KB\n\n";
1602 
1603   char *cpu_fmt_0 =
1604     "%6.2f\n";
1605 
1606   char *cpu_fmt_1 =
1607     "%5d   %5d    %-7.2f   %7d %6d    %7.1f      %-6.2f  %-6.3f\n\
1608 %5d            %-7.2f   %7d           %7.1f      %-6.2f  %-6.3f\n\n";
1609 
1610   int	messages_recvd;
1611   float	elapsed_time,
1612   local_cpu_utilization,
1613   remote_cpu_utilization;
1614 
1615   float	local_service_demand, remote_service_demand;
1616   double	local_thruput, remote_thruput;
1617   double	bytes_sent;
1618   double	bytes_recvd;
1619 
1620 
1621   int	*message_int_ptr;
1622   char	*message_ptr;
1623   char	*message;
1624   char  sctl_data[BUFSIZ];
1625   struct strbuf send_message;
1626   struct strbuf sctl_message;
1627   dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
1628 
1629   char dlsap[BUFSIZ];
1630   int  dlsap_len;
1631   int	message_offset;
1632   int	message_max_offset;
1633   int	failed_sends;
1634   int	failed_cows;
1635   int 	messages_sent;
1636   int 	data_descriptor;
1637 
1638 
1639 #ifdef WANT_INTERVALS
1640   int	interval_count;
1641 #endif /* WANT_INTERVALS */
1642 #ifdef DIRTY
1643   int	i;
1644 #endif /* DIRTY */
1645 
1646   struct	dlpi_cl_stream_request_struct	*dlpi_cl_stream_request;
1647   struct	dlpi_cl_stream_response_struct	*dlpi_cl_stream_response;
1648   struct	dlpi_cl_stream_results_struct	*dlpi_cl_stream_results;
1649 
1650   dlpi_cl_stream_request	= (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
1651   dlpi_cl_stream_response	= (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
1652   dlpi_cl_stream_results	= (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
1653 
1654   if ( print_headers ) {
1655     printf("DLPI CL UNIDIRECTIONAL SEND TEST\n");
1656     if (local_cpu_usage || remote_cpu_usage)
1657       printf(cpu_title,format_units());
1658     else
1659       printf(tput_title,format_units());
1660   }
1661 
1662   failed_sends	= 0;
1663   messages_sent	= 0;
1664   times_up	= 0;
1665 
1666   /*set up the data descriptor			*/
1667 
1668   data_descriptor = dl_open(loc_dlpi_device,loc_ppa);
1669   if (data_descriptor < 0){
1670     perror("send_dlpi_cl_stream: data descriptor");
1671     exit(1);
1672   }
1673 
1674   /* bind the puppy and get the assigned dlsap */
1675   dlsap_len = BUFSIZ;
1676   if (dl_bind(data_descriptor,
1677               dlpi_sap, DL_CLDLS, dlsap, &dlsap_len) != 0) {
1678     fprintf(where,"send_dlpi_cl_stream: bind failure\n");
1679     fflush(where);
1680     exit(1);
1681   }
1682 
1683   /* Modify the local socket size (SNDBUF size)    */
1684 
1685 #ifdef DL_HP_SET_LOCAL_WIN_REQ
1686   if (lsw_size > 0) {
1687     if (debug > 1) {
1688       fprintf(where,"netperf: send_dlpi_cl_stream: descriptor send size altered from system default...\n");
1689       fprintf(where,"                          send: %d\n",lsw_size);
1690     }
1691   }
1692   if (lrw_size > 0) {
1693     if (debug > 1) {
1694       fprintf(where,"netperf: send_dlpi_cl_stream: descriptor recv size altered from system default...\n");
1695       fprintf(where,"                          recv: %d\n",lrw_size);
1696     }
1697   }
1698 
1699 
1700   /* Now, we will find-out what the size actually became, and report */
1701   /* that back to the user. If the call fails, we will just report a -1 */
1702   /* back to the initiator for the recv buffer size. */
1703 
1704 #else /* DL_HP_SET_LOCAL_WIN_REQ */
1705 
1706   lsw_size = -1;
1707   lrw_size = -1;
1708 
1709 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
1710 
1711   /* now, we want to see if we need to set the send_size */
1712   if (send_size == 0) {
1713     send_size = 1024;
1714   }
1715 
1716 
1717   /* set-up the data buffer with the requested alignment and offset, */
1718   /* most of the numbers here are just a hack to pick something nice */
1719   /* and big in an attempt to never try to send a buffer a second time */
1720   /* before it leaves the node...unless the user set the width */
1721   /* explicitly. */
1722   if (send_width == 0) send_width = 32;
1723   message = (char *)malloc(send_size * (send_width + 1) + local_send_align + local_send_offset);
1724   if (message == NULL) {
1725     printf("malloc(%d) failed!\n", send_size * (send_width + 1) + local_send_align + local_send_offset);
1726     exit(1);
1727   }
1728   message_ptr = (char *)(( (long) message +
1729 			  (long) local_send_align - 1) &
1730 			 ~((long) local_send_align - 1));
1731   message_ptr = message_ptr + local_send_offset;
1732   message = message_ptr;
1733   send_message.maxlen = send_size;
1734   send_message.len = send_size;
1735   send_message.buf = message;
1736 
1737   sctl_message.maxlen = BUFSIZ;
1738   sctl_message.len    = 0;
1739   sctl_message.buf    = sctl_data;
1740 
1741   /* if the user supplied a cpu rate, this call will complete rather */
1742   /* quickly, otherwise, the cpu rate will be retured to us for */
1743   /* possible display. The Library will keep it's own copy of this data */
1744   /* for use elsewhere. We will only display it. (Does that make it */
1745   /* "opaque" to us?) */
1746 
1747   if (local_cpu_usage)
1748     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1749 
1750   /* Tell the remote end to set up the data connection. The server */
1751   /* sends back the port number and alters the socket parameters there. */
1752   /* Of course this is a datagram service so no connection is actually */
1753   /* set up, the server just sets up the socket and binds it. */
1754 
1755   netperf_request.content.request_type                 = DO_DLPI_CL_STREAM;
1756   dlpi_cl_stream_request->recv_win_size	        = rrw_size;
1757   dlpi_cl_stream_request->message_size	        = send_size;
1758   dlpi_cl_stream_request->recv_alignment	= remote_recv_align;
1759   dlpi_cl_stream_request->recv_offset		= remote_recv_offset;
1760   dlpi_cl_stream_request->measure_cpu		= remote_cpu_usage;
1761   dlpi_cl_stream_request->cpu_rate		= remote_cpu_rate;
1762   dlpi_cl_stream_request->ppa                   = rem_ppa;
1763   dlpi_cl_stream_request->sap                   = dlpi_sap;
1764   dlpi_cl_stream_request->dev_name_len          = strlen(rem_dlpi_device);
1765   strcpy(dlpi_cl_stream_request->dlpi_device,
1766 	 rem_dlpi_device);
1767 
1768 #ifdef __alpha
1769 
1770   /* ok - even on a DEC box, strings are strings. I din't really want */
1771   /* to ntohl the words of a string. since I don't want to teach the */
1772   /* send_ and recv_ _request and _response routines about the types, */
1773   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1774   /* solution would be to use XDR, but I am still leary of being able */
1775   /* to find XDR libs on all platforms I want running netperf. raj */
1776   {
1777     int *charword;
1778     int *initword;
1779     int *lastword;
1780 
1781     initword = (int *) dlpi_cl_stream_request->dlpi_device;
1782     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
1783 
1784     for (charword = initword;
1785 	 charword < lastword;
1786 	 charword++) {
1787 
1788       *charword = ntohl(*charword);
1789     }
1790   }
1791 #endif /* __alpha */
1792 
1793   if (test_time) {
1794     dlpi_cl_stream_request->test_length	=	test_time;
1795   }
1796   else {
1797     dlpi_cl_stream_request->test_length	=	test_bytes * -1;
1798   }
1799 
1800 
1801   send_request();
1802 
1803   recv_response();
1804 
1805   if (!netperf_response.content.serv_errno) {
1806     if (debug)
1807       fprintf(where,"send_dlpi_cl_stream: remote data connection done.\n");
1808   }
1809   else {
1810     Set_errno(netperf_response.content.serv_errno);
1811     perror("send_dlpi_cl_stream: error on remote");
1812     exit(1);
1813   }
1814 
1815   /* place some of the remote's addressing information into the send */
1816   /* structure so our sends can be sent to the correct place. Also get */
1817   /* some of the returned socket buffer information for user display. */
1818 
1819   /* set-up the destination addressing control info */
1820   data_req->dl_primitive = DL_UNITDATA_REQ;
1821   bcopy((char *)(dlpi_cl_stream_response->station_addr),
1822 	((char *)data_req + sizeof(dl_unitdata_req_t)),
1823 	dlpi_cl_stream_response->station_addr_len);
1824   data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
1825   data_req->dl_dest_addr_length = dlpi_cl_stream_response->station_addr_len;
1826   /* there is a dl_priority structure too, but I am ignoring it for */
1827   /* the time being. */
1828   /* however... it is best to put some value in there lest some code
1829      get grumpy about it - fix from Nicolas Thomas */
1830   data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
1831   data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
1832 
1833   sctl_message.len = sizeof(dl_unitdata_req_t) +
1834     data_req->dl_dest_addr_length;
1835 
1836   rrw_size	        = dlpi_cl_stream_response->recv_win_size;
1837   rsw_size	        = dlpi_cl_stream_response->send_win_size;
1838   remote_cpu_rate	= dlpi_cl_stream_response->cpu_rate;
1839 
1840 
1841   /* set up the timer to call us after test_time	*/
1842   start_timer(test_time);
1843 
1844   /* Get the start count for the idle counter and the start time */
1845 
1846   cpu_start(local_cpu_usage);
1847 
1848 #ifdef WANT_INTERVALS
1849   interval_count = interval_burst;
1850 #endif /* WANT_INTERVALS */
1851 
1852   /* Send datagrams like there was no tomorrow */
1853   while (!times_up) {
1854 #ifdef DIRTY
1855     /* we want to dirty some number of consecutive integers in the buffer */
1856     /* we are about to send. we may also want to bring some number of */
1857     /* them cleanly into the cache. The clean ones will follow any dirty */
1858     /* ones into the cache. */
1859     message_int_ptr = (int *)message_ptr;
1860     for (i = 0; i < loc_dirty_count; i++) {
1861       *message_int_ptr = 4;
1862       message_int_ptr++;
1863     }
1864     for (i = 0; i < loc_clean_count; i++) {
1865       loc_dirty_count = *message_int_ptr;
1866       message_int_ptr++;
1867     }
1868 #endif /* DIRTY */
1869     if (putmsg(data_descriptor,
1870 	       &sctl_message,
1871 	       &send_message,
1872 	       0)  != 0) {
1873       if (errno == EINTR) {
1874 	break;
1875       }
1876       if (errno == ENOBUFS) {
1877 	/* we might not ever hit this with STREAMS, it would probably */
1878 	/* be better to do a getinfo request at the end of the test to */
1879 	/* get all sorts of gory statistics. in the meantime, we will */
1880 	/* keep this code in place. */
1881 	failed_sends++;
1882 	continue;
1883       }
1884       perror("send_dlpi_cl_stream: data send error");
1885       if (debug) {
1886 	fprintf(where,"messages_sent %u\n",messages_sent);
1887 	fflush(where);
1888       }
1889       exit(1);
1890     }
1891     messages_sent++;
1892 
1893     /* now we want to move our pointer to the next position in the */
1894     /* data buffer...since there was a successful send */
1895 
1896 
1897 #ifdef WANT_INTERVALS
1898     /* in this case, the interval count is the count-down couter */
1899     /* to decide to sleep for a little bit */
1900     if ((interval_burst) && (--interval_count == 0)) {
1901       /* call the sleep routine for some milliseconds, if our */
1902       /* timer popped while we were in there, we want to */
1903       /* break out of the loop. */
1904       if (msec_sleep(interval_wate)) {
1905 	break;
1906       }
1907       interval_count = interval_burst;
1908     }
1909 
1910 #endif /* WANT_INTERVALS */
1911 
1912   }
1913 
1914   /* This is a timed test, so the remote will be returning to us after */
1915   /* a time. We should not need to send any "strange" messages to tell */
1916   /* the remote that the test is completed, unless we decide to add a */
1917   /* number of messages to the test. */
1918 
1919   /* the test is over, so get stats and stuff */
1920   cpu_stop(local_cpu_usage,
1921 	   &elapsed_time);
1922 
1923   /* Get the statistics from the remote end	*/
1924   recv_response();
1925   if (!netperf_response.content.serv_errno) {
1926     if (debug)
1927       fprintf(where,"send_dlpi_cl_stream: remote results obtained\n");
1928   }
1929   else {
1930     Set_errno(netperf_response.content.serv_errno);
1931     perror("send_dlpi_cl_stream: error on remote");
1932     exit(1);
1933   }
1934 
1935   bytes_sent	= send_size * messages_sent;
1936   local_thruput	= calc_thruput(bytes_sent);
1937 
1938   messages_recvd	= dlpi_cl_stream_results->messages_recvd;
1939   bytes_recvd	= send_size * messages_recvd;
1940 
1941   /* we asume that the remote ran for as long as we did */
1942 
1943   remote_thruput	= calc_thruput(bytes_recvd);
1944 
1945   /* print the results for this descriptor and message size */
1946 
1947   if (local_cpu_usage || remote_cpu_usage) {
1948     /* We must now do a little math for service demand and cpu */
1949     /* utilization for the system(s) We pass zeros for the local */
1950     /* cpu utilization and elapsed time to tell the routine to use */
1951     /* the libraries own values for those. */
1952     if (local_cpu_usage) {
1953       if (local_cpu_rate == 0.0) {
1954 	fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
1955 	fprintf(where,"Local CPU usage numbers based on process information only!\n");
1956 	fflush(where);
1957       }
1958 
1959       local_cpu_utilization	= calc_cpu_util(0.0);
1960       local_service_demand	= calc_service_demand(bytes_sent,
1961 						      0.0,
1962 						      0.0,
1963 						      0);
1964     }
1965     else {
1966       local_cpu_utilization	= -1.0;
1967       local_service_demand	= -1.0;
1968     }
1969 
1970     /* The local calculations could use variables being kept by */
1971     /* the local netlib routines. The remote calcuations need to */
1972     /* have a few things passed to them. */
1973     if (remote_cpu_usage) {
1974       if (remote_cpu_rate == 0.0) {
1975 	fprintf(where,"DANGER   DANGER  DANGER   DANGER  DANGER   DANGER   DANGER!\n");
1976 	fprintf(where,"REMOTE CPU usage numbers based on process information only!\n");
1977 	fflush(where);
1978       }
1979 
1980       remote_cpu_utilization	= dlpi_cl_stream_results->cpu_util;
1981       remote_service_demand	= calc_service_demand(bytes_recvd,
1982 						      0.0,
1983 						      remote_cpu_utilization,
1984 						      dlpi_cl_stream_results->num_cpus);
1985     }
1986     else {
1987       remote_cpu_utilization	= -1.0;
1988       remote_service_demand	= -1.0;
1989     }
1990 
1991     /* We are now ready to print all the information. If the user */
1992     /* has specified zero-level verbosity, we will just print the */
1993     /* local service demand, or the remote service demand. If the */
1994     /* user has requested verbosity level 1, he will get the basic */
1995     /* "streamperf" numbers. If the user has specified a verbosity */
1996     /* of greater than 1, we will display a veritable plethora of */
1997     /* background information from outside of this block as it it */
1998     /* not cpu_measurement specific...  */
1999 
2000     switch (verbosity) {
2001     case 0:
2002       if (local_cpu_usage) {
2003 	fprintf(where,
2004 		cpu_fmt_0,
2005 		local_service_demand);
2006       }
2007       else {
2008 	fprintf(where,
2009 		cpu_fmt_0,
2010 		remote_service_demand);
2011       }
2012       break;
2013     case 1:
2014       fprintf(where,
2015 	      cpu_fmt_1,		/* the format string */
2016 	      lsw_size,		/* local sendbuf size */
2017 	      send_size,		/* how large were the sends */
2018 	      elapsed_time,		/* how long was the test */
2019 	      messages_sent,
2020 	      failed_sends,
2021 	      local_thruput, 		/* what was the xfer rate */
2022 	      local_cpu_utilization,	/* local cpu */
2023 	      local_service_demand,	/* local service demand */
2024 	      rrw_size,
2025 	      elapsed_time,
2026 	      messages_recvd,
2027 	      remote_thruput,
2028 	      remote_cpu_utilization,	/* remote cpu */
2029 	      remote_service_demand);	/* remote service demand */
2030       break;
2031     }
2032   }
2033   else {
2034     /* The tester did not wish to measure service demand. */
2035     switch (verbosity) {
2036     case 0:
2037       fprintf(where,
2038 	      tput_fmt_0,
2039 	      local_thruput);
2040       break;
2041     case 1:
2042       fprintf(where,
2043 	      tput_fmt_1,		/* the format string */
2044 	      lsw_size, 		/* local sendbuf size */
2045 	      send_size,		/* how large were the sends */
2046 	      elapsed_time, 		/* how long did it take */
2047 	      messages_sent,
2048 	      failed_sends,
2049 	      local_thruput,
2050 	      rrw_size, 		/* remote recvbuf size */
2051 	      elapsed_time,
2052 	      messages_recvd,
2053 	      remote_thruput
2054 	      );
2055       break;
2056     }
2057   }
2058 }
2059 
2060 int
recv_dlpi_cl_stream()2061   recv_dlpi_cl_stream()
2062 {
2063 
2064   char  *message;
2065   int	data_descriptor;
2066   int	len;
2067   char	*message_ptr;
2068   char  rctl_data[BUFSIZ];
2069   struct strbuf recv_message;
2070   struct strbuf rctl_message;
2071   int flags = 0;
2072   /* these are to make reading some of the DLPI control messages easier */
2073   dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
2074   dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
2075 
2076   int	bytes_received = 0;
2077   float	elapsed_time;
2078 
2079   int	message_size;
2080   int	messages_recvd = 0;
2081   int	measure_cpu;
2082 
2083   struct	dlpi_cl_stream_request_struct	*dlpi_cl_stream_request;
2084   struct	dlpi_cl_stream_response_struct	*dlpi_cl_stream_response;
2085   struct	dlpi_cl_stream_results_struct	*dlpi_cl_stream_results;
2086 
2087   dlpi_cl_stream_request	= (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
2088   dlpi_cl_stream_response	= (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
2089   dlpi_cl_stream_results	= (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
2090 
2091   if (debug) {
2092     fprintf(where,"netserver: recv_dlpi_cl_stream: entered...\n");
2093     fflush(where);
2094   }
2095 
2096   /* We want to set-up the listen descriptor with all the desired */
2097   /* parameters and then let the initiator know that all is ready. If */
2098   /* socket size defaults are to be used, then the initiator will have */
2099   /* sent us 0's. If the socket sizes cannot be changed, then we will */
2100   /* send-back what they are. If that information cannot be determined, */
2101   /* then we send-back -1's for the sizes. If things go wrong for any */
2102   /* reason, we will drop back ten yards and punt. */
2103 
2104   /* If anything goes wrong, we want the remote to know about it. It */
2105   /* would be best if the error that the remote reports to the user is */
2106   /* the actual error we encountered, rather than some bogus unexpected */
2107   /* response type message. */
2108 
2109   if (debug > 1) {
2110     fprintf(where,"recv_dlpi_cl_stream: setting the response type...\n");
2111     fflush(where);
2112   }
2113 
2114   netperf_response.content.response_type = DLPI_CL_STREAM_RESPONSE;
2115 
2116   if (debug > 2) {
2117     fprintf(where,"recv_dlpi_cl_stream: the response type is set...\n");
2118     fflush(where);
2119   }
2120 
2121   /* set-up the data buffer with the requested alignment and offset */
2122   message = (char *)malloc(DATABUFFERLEN);
2123   if (message == NULL) {
2124     printf("malloc(%d) failed!\n", DATABUFFERLEN);
2125     exit(1);
2126   }
2127 
2128   /* We now alter the message_ptr variable to be at the desired */
2129   /* alignment with the desired offset. */
2130 
2131   if (debug > 1) {
2132     fprintf(where,"recv_dlpi_cl_stream: requested alignment of %d\n",
2133 	    dlpi_cl_stream_request->recv_alignment);
2134     fflush(where);
2135   }
2136 
2137   message_ptr = ALIGN_BUFFER(message, dlpi_cl_stream_request->recv_alignment, dlpi_cl_stream_request->recv_offset);
2138 
2139   if (dlpi_cl_stream_request->message_size > 0) {
2140     recv_message.maxlen = dlpi_cl_stream_request->message_size;
2141   }
2142   else {
2143     recv_message.maxlen = 4096;
2144   }
2145   recv_message.len    = 0;
2146   recv_message.buf    = message_ptr;
2147 
2148   rctl_message.maxlen = BUFSIZ;
2149   rctl_message.len    = 0;
2150   rctl_message.buf    = rctl_data;
2151 
2152   if (debug > 1) {
2153     fprintf(where,
2154 	    "recv_dlpi_cl_stream: receive alignment and offset set...\n");
2155     fflush(where);
2156   }
2157 
2158   if (debug > 1) {
2159     fprintf(where,"recv_dlpi_cl_stream: grabbing a descriptor...\n");
2160     fflush(where);
2161   }
2162 
2163 #ifdef __alpha
2164 
2165   /* ok - even on a DEC box, strings are strings. I din't really want */
2166   /* to ntohl the words of a string. since I don't want to teach the */
2167   /* send_ and recv_ _request and _response routines about the types, */
2168   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2169   /* solution would be to use XDR, but I am still leary of being able */
2170   /* to find XDR libs on all platforms I want running netperf. raj */
2171   {
2172     int *charword;
2173     int *initword;
2174     int *lastword;
2175 
2176     initword = (int *) dlpi_cl_stream_request->dlpi_device;
2177     lastword = initword + ((dlpi_cl_stream_request->dev_name_len + 3) / 4);
2178 
2179     for (charword = initword;
2180 	 charword < lastword;
2181 	 charword++) {
2182 
2183       *charword = htonl(*charword);
2184     }
2185   }
2186 #endif /* __alpha */
2187 
2188   data_descriptor = dl_open(dlpi_cl_stream_request->dlpi_device,
2189 			    dlpi_cl_stream_request->ppa);
2190   if (data_descriptor < 0) {
2191     netperf_response.content.serv_errno = errno;
2192     send_response();
2193     exit(1);
2194   }
2195 
2196   /* The initiator may have wished-us to modify the window */
2197   /* sizes. We should give it a shot. If he didn't ask us to change the */
2198   /* sizes, we should let him know what sizes were in use at this end. */
2199   /* If none of this code is compiled-in, then we will tell the */
2200   /* initiator that we were unable to play with the sizes by */
2201   /* setting the size in the response to -1. */
2202 
2203 #ifdef DL_HP_SET_LOCAL_WIN_REQ
2204 
2205   if (dlpi_cl_stream_request->recv_win_size) {
2206     dlpi_cl_stream_response->recv_win_size	= -1;
2207   }
2208 
2209 #else /* the system won't let us play with the buffers */
2210 
2211   dlpi_cl_stream_response->recv_win_size	= -1;
2212 
2213 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
2214 
2215   dlpi_cl_stream_response->test_length = dlpi_cl_stream_request->test_length;
2216 
2217   /* bind the sap and retrieve the dlsap assigned by the system  */
2218   dlpi_cl_stream_response->station_addr_len = 14; /* arbitrary */
2219   if (dl_bind(data_descriptor,
2220 	      dlpi_cl_stream_request->sap,
2221 	      DL_CLDLS,
2222 	      (char *)dlpi_cl_stream_response->station_addr,
2223 	      &dlpi_cl_stream_response->station_addr_len) != 0) {
2224     fprintf(where,"send_dlpi_cl_stream: bind failure\n");
2225     fflush(where);
2226     exit(1);
2227   }
2228 
2229   netperf_response.content.serv_errno   = 0;
2230 
2231   /* But wait, there's more. If the initiator wanted cpu measurements, */
2232   /* then we must call the calibrate routine, which will return the max */
2233   /* rate back to the initiator. If the CPU was not to be measured, or */
2234   /* something went wrong with the calibration, we will return a -1 to */
2235   /* the initiator. */
2236 
2237   dlpi_cl_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
2238   if (dlpi_cl_stream_request->measure_cpu) {
2239     /* We will pass the rate into the calibration routine. If the */
2240     /* user did not specify one, it will be 0.0, and we will do a */
2241     /* "real" calibration. Otherwise, all it will really do is */
2242     /* store it away... */
2243     dlpi_cl_stream_response->measure_cpu = 1;
2244     dlpi_cl_stream_response->cpu_rate = calibrate_local_cpu(dlpi_cl_stream_request->cpu_rate);
2245   }
2246 
2247   message_size	= dlpi_cl_stream_request->message_size;
2248   test_time	= dlpi_cl_stream_request->test_length;
2249 
2250   send_response();
2251 
2252   /* Now it's time to start receiving data on the connection. We will */
2253   /* first grab the apropriate counters and then start grabbing. */
2254 
2255   cpu_start(dlpi_cl_stream_request->measure_cpu);
2256 
2257   /* The loop will exit when the timer pops, or if we happen to recv a */
2258   /* message of less than send_size bytes... */
2259 
2260   times_up = 0;
2261   start_timer(test_time + PAD_TIME);
2262 
2263   if (debug) {
2264     fprintf(where,"recv_dlpi_cl_stream: about to enter inner sanctum.\n");
2265     fflush(where);
2266   }
2267 
2268   while (!times_up) {
2269     if((getmsg(data_descriptor,
2270 	       &rctl_message,
2271 	       &recv_message,
2272 	       &flags) != 0) ||
2273        (data_ind->dl_primitive != DL_UNITDATA_IND)) {
2274       if (errno == EINTR) {
2275 	/* Again, we have likely hit test-end time */
2276 	break;
2277       }
2278       fprintf(where,
2279 	      "dlpi_recv_cl_stream: getmsg failure: errno %d primitive 0x%x\n",
2280 	      errno,
2281 	      data_ind->dl_primitive);
2282       fflush(where);
2283       netperf_response.content.serv_errno = 996;
2284       send_response();
2285       exit(1);
2286     }
2287     messages_recvd++;
2288   }
2289 
2290   if (debug) {
2291     fprintf(where,"recv_dlpi_cl_stream: got %d messages.\n",messages_recvd);
2292     fflush(where);
2293   }
2294 
2295 
2296   /* The loop now exits due timer or < send_size bytes received. */
2297 
2298   cpu_stop(dlpi_cl_stream_request->measure_cpu,&elapsed_time);
2299 
2300   if (times_up) {
2301     /* we ended on a timer, subtract the PAD_TIME */
2302     elapsed_time -= (float)PAD_TIME;
2303   }
2304   else {
2305     stop_timer();
2306   }
2307 
2308   if (debug) {
2309     fprintf(where,"recv_dlpi_cl_stream: test ended in %f seconds.\n",elapsed_time);
2310     fflush(where);
2311   }
2312 
2313 
2314   /* We will count the "off" message */
2315   bytes_received = (messages_recvd * message_size) + len;
2316 
2317   /* send the results to the sender			*/
2318 
2319   if (debug) {
2320     fprintf(where,
2321 	    "recv_dlpi_cl_stream: got %d bytes\n",
2322 	    bytes_received);
2323     fflush(where);
2324   }
2325 
2326   netperf_response.content.response_type		= DLPI_CL_STREAM_RESULTS;
2327   dlpi_cl_stream_results->bytes_received	= bytes_received;
2328   dlpi_cl_stream_results->messages_recvd	= messages_recvd;
2329   dlpi_cl_stream_results->elapsed_time	= elapsed_time;
2330   if (dlpi_cl_stream_request->measure_cpu) {
2331     dlpi_cl_stream_results->cpu_util	= calc_cpu_util(elapsed_time);
2332   }
2333   else {
2334     dlpi_cl_stream_results->cpu_util	= -1.0;
2335   }
2336 
2337   if (debug > 1) {
2338     fprintf(where,
2339 	    "recv_dlpi_cl_stream: test complete, sending results.\n");
2340     fflush(where);
2341   }
2342 
2343   send_response();
2344 
2345 }
2346 
send_dlpi_cl_rr(char remote_host[])2347 int send_dlpi_cl_rr(char remote_host[])
2348 {
2349 
2350   char *tput_title = "\
2351 Local /Remote\n\
2352 Window Size   Request  Resp.   Elapsed  Trans.\n\
2353 Send   Recv   Size     Size    Time     Rate         \n\
2354 frames frames bytes    bytes   secs.    per sec   \n\n";
2355 
2356   char *tput_fmt_0 =
2357     "%7.2f\n";
2358 
2359   char *tput_fmt_1_line_1 = "\
2360 %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
2361   char *tput_fmt_1_line_2 = "\
2362 %-6d %-6d\n";
2363 
2364   char *cpu_title = "\
2365 Local /Remote\n\
2366 Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
2367 Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
2368 frames frames bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Tr\n\n";
2369 
2370   char *cpu_fmt_0 =
2371     "%6.3f\n";
2372 
2373   char *cpu_fmt_1_line_1 = "\
2374 %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
2375 
2376   char *cpu_fmt_1_line_2 = "\
2377 %-6d %-6d\n";
2378 
2379   char *ksink_fmt = "\
2380 Alignment      Offset\n\
2381 Local  Remote  Local  Remote\n\
2382 Send   Recv    Send   Recv\n\
2383 %5d  %5d   %5d  %5d\n";
2384 
2385 
2386   float			elapsed_time;
2387 
2388   int   dlsap_len;
2389   int   flags = 0;
2390   char	*send_message_ptr;
2391   char	*recv_message_ptr;
2392   char	*temp_message_ptr;
2393   char  sctl_data[BUFSIZ];
2394   char  rctl_data[BUFSIZ];
2395   char  dlsap[BUFSIZ];
2396   struct strbuf send_message;
2397   struct strbuf recv_message;
2398   struct strbuf sctl_message;
2399   struct strbuf rctl_message;
2400 
2401   /* these are to make reading some of the DLPI control messages easier */
2402   dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
2403   dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
2404   dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
2405 
2406   int	nummessages;
2407   int	send_descriptor;
2408   int	trans_remaining;
2409   int	bytes_xferd;
2410 
2411   float	local_cpu_utilization;
2412   float	local_service_demand;
2413   float	remote_cpu_utilization;
2414   float	remote_service_demand;
2415   double thruput;
2416 
2417 #ifdef WANT_INTERVALS
2418   /* timing stuff */
2419 #define	MAX_KEPT_TIMES	1024
2420   int	time_index = 0;
2421   int	unused_buckets;
2422   int	kept_times[MAX_KEPT_TIMES];
2423   int	sleep_usecs;
2424   unsigned	int	total_times=0;
2425   struct	timezone	dummy_zone;
2426   struct	timeval		send_time;
2427   struct	timeval		recv_time;
2428   struct	timeval		sleep_timeval;
2429 #endif /* WANT_INTERVALS */
2430 
2431   struct	dlpi_cl_rr_request_struct	*dlpi_cl_rr_request;
2432   struct	dlpi_cl_rr_response_struct	*dlpi_cl_rr_response;
2433   struct	dlpi_cl_rr_results_struct	*dlpi_cl_rr_result;
2434 
2435   dlpi_cl_rr_request	=
2436     (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
2437   dlpi_cl_rr_response	=
2438     (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
2439   dlpi_cl_rr_result	=
2440     (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
2441 
2442   /* we want to zero out the times, so we can detect unused entries. */
2443 #ifdef WANT_INTERVALS
2444   time_index = 0;
2445   while (time_index < MAX_KEPT_TIMES) {
2446     kept_times[time_index] = 0;
2447     time_index += 1;
2448   }
2449   time_index = 0;
2450 #endif /* WANT_INTERVALS */
2451 
2452   if (print_headers) {
2453     fprintf(where,"DLPI CL REQUEST/RESPONSE TEST\n");
2454     if (local_cpu_usage || remote_cpu_usage)
2455       fprintf(where,cpu_title,format_units());
2456     else
2457       fprintf(where,tput_title,format_units());
2458   }
2459 
2460   /* initialize a few counters */
2461 
2462   nummessages	=	0;
2463   bytes_xferd	=	0;
2464   times_up 	= 	0;
2465 
2466   /* set-up the data buffer with the requested alignment and offset */
2467   temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
2468   if (temp_message_ptr == NULL) {
2469     printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET);
2470     exit(1);
2471   }
2472   send_message_ptr = (char *)(( (long)temp_message_ptr +
2473 			       (long) local_send_align - 1) &
2474 			      ~((long) local_send_align - 1));
2475   send_message_ptr = send_message_ptr + local_send_offset;
2476   send_message.maxlen = req_size;
2477   send_message.len    = req_size;
2478   send_message.buf    = send_message_ptr;
2479 
2480   temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
2481   if (temp_message_ptr == NULL) {
2482     printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET);
2483     exit(1);
2484   }
2485   recv_message_ptr = (char *)(( (long)temp_message_ptr +
2486 			       (long) local_recv_align - 1) &
2487 			      ~((long) local_recv_align - 1));
2488   recv_message_ptr = recv_message_ptr + local_recv_offset;
2489   recv_message.maxlen = rsp_size;
2490   recv_message.len    = 0;
2491   recv_message.buf    = recv_message_ptr;
2492 
2493   sctl_message.maxlen = BUFSIZ;
2494   sctl_message.len    = 0;
2495   sctl_message.buf    = sctl_data;
2496 
2497   rctl_message.maxlen = BUFSIZ;
2498   rctl_message.len    = 0;
2499   rctl_message.buf    = rctl_data;
2500 
2501   /* lets get ourselves a file descriptor */
2502 
2503   send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
2504   if (send_descriptor < 0){
2505     perror("netperf: send_dlpi_cl_rr: dlpi cl rr send descriptor");
2506     exit(1);
2507   }
2508 
2509   if (debug) {
2510     fprintf(where,"send_dlpi_cl_rr: send_descriptor obtained...\n");
2511   }
2512 
2513   /* bind the sap to the descriptor and get the dlsap */
2514   dlsap_len = BUFSIZ;
2515   if (dl_bind(send_descriptor,
2516 	      dlpi_sap,
2517 	      DL_CLDLS,
2518 	      dlsap,
2519 	      &dlsap_len) != 0) {
2520     fprintf(where,"send_dlpi_cl_rr: bind failure\n");
2521     fflush(where);
2522     exit(1);
2523   }
2524 
2525   /* Modify the local socket size. If the user has not requested that */
2526   /* the socket buffers be altered, we will try to find-out what their */
2527   /* values are. If we cannot touch the socket buffer in any way, we */
2528   /* will set the values to -1 to indicate that.  The receive socket */
2529   /* must have enough space to hold addressing information so += a */
2530   /* sizeof struct sockaddr_in to it. */
2531 
2532   /* this is actually nothing code, and should be replaced with the */
2533   /* alalagous calls in the STREAM test where the window size is set */
2534   /* with the HP DLPI Extension. raj 8/94 */
2535 #ifdef SO_SNDBUF
2536   if (lsw_size > 0) {
2537     if (debug > 1) {
2538       fprintf(where,"netperf: send_dlpi_cl_rr: local window size altered from system default...\n");
2539       fprintf(where,"                          window: %d\n",lsw_size);
2540     }
2541   }
2542   if (lrw_size > 0) {
2543     if (debug > 1) {
2544       fprintf(where,"netperf: send_dlpi_cl_rr: remote window size altered from system default...\n");
2545       fprintf(where,"                          remote: %d\n",lrw_size);
2546     }
2547   }
2548 
2549 
2550   /* Now, we will find-out what the size actually became, and report */
2551   /* that back to the user. If the call fails, we will just report a -1 */
2552   /* back to the initiator for the recv buffer size. */
2553 
2554   if (debug) {
2555     fprintf(where,"netperf: send_dlpi_cl_rr: socket sizes determined...\n");
2556     fprintf(where,"         send: %d recv: %d\n",lsw_size,lrw_size);
2557   }
2558 
2559 #else /* SO_SNDBUF */
2560 
2561   lsw_size = -1;
2562   lrw_size = -1;
2563 
2564 #endif /* SO_SNDBUF */
2565 
2566   /* If the user has requested cpu utilization measurements, we must */
2567   /* calibrate the cpu(s). We will perform this task within the tests */
2568   /* themselves. If the user has specified the cpu rate, then */
2569   /* calibrate_local_cpu will return rather quickly as it will have */
2570   /* nothing to do. If local_cpu_rate is zero, then we will go through */
2571   /* all the "normal" calibration stuff and return the rate back. If */
2572   /* there is no idle counter in the kernel idle loop, the */
2573   /* local_cpu_rate will be set to -1. */
2574 
2575   if (local_cpu_usage) {
2576     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2577   }
2578 
2579   /* Tell the remote end to do a listen. The server alters the socket */
2580   /* paramters on the other side at this point, hence the reason for */
2581   /* all the values being passed in the setup message. If the user did */
2582   /* not specify any of the parameters, they will be passed as 0, which */
2583   /* will indicate to the remote that no changes beyond the system's */
2584   /* default should be used. Alignment is the exception, it will */
2585   /* default to 8, which will be no alignment alterations. */
2586 
2587   netperf_request.content.request_type	        =	DO_DLPI_CL_RR;
2588   dlpi_cl_rr_request->recv_win_size	=	rrw_size;
2589   dlpi_cl_rr_request->send_win_size	=	rsw_size;
2590   dlpi_cl_rr_request->recv_alignment	=	remote_recv_align;
2591   dlpi_cl_rr_request->recv_offset	=	remote_recv_offset;
2592   dlpi_cl_rr_request->send_alignment	=	remote_send_align;
2593   dlpi_cl_rr_request->send_offset	=	remote_send_offset;
2594   dlpi_cl_rr_request->request_size	=	req_size;
2595   dlpi_cl_rr_request->response_size	=	rsp_size;
2596   dlpi_cl_rr_request->measure_cpu	=	remote_cpu_usage;
2597   dlpi_cl_rr_request->cpu_rate	        =	remote_cpu_rate;
2598   dlpi_cl_rr_request->ppa               =       rem_ppa;
2599   dlpi_cl_rr_request->sap               =       dlpi_sap;
2600   dlpi_cl_rr_request->dev_name_len      =       strlen(rem_dlpi_device);
2601   strcpy(dlpi_cl_rr_request->dlpi_device,
2602 	 rem_dlpi_device);
2603 
2604 #ifdef __alpha
2605 
2606   /* ok - even on a DEC box, strings are strings. I din't really want */
2607   /* to ntohl the words of a string. since I don't want to teach the */
2608   /* send_ and recv_ _request and _response routines about the types, */
2609   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2610   /* solution would be to use XDR, but I am still leary of being able */
2611   /* to find XDR libs on all platforms I want running netperf. raj */
2612   {
2613     int *charword;
2614     int *initword;
2615     int *lastword;
2616 
2617     initword = (int *) dlpi_cl_rr_request->dlpi_device;
2618     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
2619 
2620     for (charword = initword;
2621 	 charword < lastword;
2622 	 charword++) {
2623 
2624       *charword = ntohl(*charword);
2625     }
2626   }
2627 #endif /* __alpha */
2628 
2629   if (test_time) {
2630     dlpi_cl_rr_request->test_length	=	test_time;
2631   }
2632   else {
2633     dlpi_cl_rr_request->test_length	=	test_trans * -1;
2634   }
2635 
2636   if (debug > 1) {
2637     fprintf(where,"netperf: send_dlpi_cl_rr: requesting DLPI CL request/response test\n");
2638   }
2639 
2640   send_request();
2641 
2642   /* The response from the remote will contain all of the relevant 	*/
2643   /* socket parameters for this test type. We will put them back into 	*/
2644   /* the variables here so they can be displayed if desired.  The	*/
2645   /* remote will have calibrated CPU if necessary, and will have done	*/
2646   /* all the needed set-up we will have calibrated the cpu locally	*/
2647   /* before sending the request, and will grab the counter value right	*/
2648   /* after the connect returns. The remote will grab the counter right	*/
2649   /* after the accept call. This saves the hassle of extra messages	*/
2650   /* being sent for the tests.                                          */
2651 
2652   recv_response();
2653 
2654   if (!netperf_response.content.serv_errno) {
2655     if (debug)
2656       fprintf(where,"remote listen done.\n");
2657     rrw_size	=	dlpi_cl_rr_response->recv_win_size;
2658     rsw_size	=	dlpi_cl_rr_response->send_win_size;
2659     remote_cpu_usage=	dlpi_cl_rr_response->measure_cpu;
2660     remote_cpu_rate = 	dlpi_cl_rr_response->cpu_rate;
2661 
2662     /* set-up the destination addressing control info */
2663     data_req->dl_primitive = DL_UNITDATA_REQ;
2664     bcopy((char *)(dlpi_cl_rr_response->station_addr),
2665 	  ((char *)data_req + sizeof(dl_unitdata_req_t)),
2666 	  dlpi_cl_rr_response->station_addr_len);
2667     data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
2668     data_req->dl_dest_addr_length = dlpi_cl_rr_response->station_addr_len;
2669     /* there is a dl_priority structure too, but I am ignoring it for */
2670     /* the time being. */
2671     sctl_message.len = sizeof(dl_unitdata_req_t) +
2672       data_req->dl_dest_addr_length;
2673     /* famous last words - some DLPI providers get unhappy if the
2674        priority stuff is not initialized.  fix from Nicolas Thomas. */
2675     data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
2676     data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
2677 
2678   }
2679   else {
2680     Set_errno(netperf_response.content.serv_errno);
2681     perror("netperf: remote error");
2682     exit(1);
2683   }
2684 
2685   /* Data Socket set-up is finished. If there were problems, either the */
2686   /* connect would have failed, or the previous response would have */
2687   /* indicated a problem. I failed to see the value of the extra */
2688   /* message after the accept on the remote. If it failed, we'll see it */
2689   /* here. If it didn't, we might as well start pumping data. */
2690 
2691   /* Set-up the test end conditions. For a request/response test, they */
2692   /* can be either time or transaction based. */
2693 
2694   if (test_time) {
2695     /* The user wanted to end the test after a period of time. */
2696     times_up = 0;
2697     trans_remaining = 0;
2698     start_timer(test_time);
2699   }
2700   else {
2701     /* The tester wanted to send a number of bytes. */
2702     trans_remaining = test_bytes;
2703     times_up = 1;
2704   }
2705 
2706   /* The cpu_start routine will grab the current time and possibly */
2707   /* value of the idle counter for later use in measuring cpu */
2708   /* utilization and/or service demand and thruput. */
2709 
2710   cpu_start(local_cpu_usage);
2711 
2712   /* We use an "OR" to control test execution. When the test is */
2713   /* controlled by time, the byte count check will always return false. */
2714   /* When the test is controlled by byte count, the time test will */
2715   /* always return false. When the test is finished, the whole */
2716   /* expression will go false and we will stop sending data. I think I */
2717   /* just arbitrarily decrement trans_remaining for the timed test, but */
2718   /* will not do that just yet... One other question is whether or not */
2719   /* the send buffer and the receive buffer should be the same buffer. */
2720   while ((!times_up) || (trans_remaining > 0)) {
2721     /* send the request */
2722 #ifdef WANT_INTERVALS
2723     gettimeofday(&send_time,&dummy_zone);
2724 #endif /* WANT_INTERVALS */
2725     if(putmsg(send_descriptor,
2726 	      &sctl_message,
2727 	      &send_message,
2728 	      0) != 0) {
2729       if (errno == EINTR) {
2730 	/* We likely hit */
2731 	/* test-end time. */
2732 	break;
2733       }
2734       /* there is more we could do here, but it can wait */
2735       perror("send_dlpi_cl_rr: data send error");
2736       exit(1);
2737     }
2738 
2739     /* receive the response. at some point, we will need to handle */
2740     /* sending responses which are greater than the datalink MTU. we */
2741     /* may also want to add some DLPI error checking, but for now we */
2742     /* will ignore that and just let errors stop the test with little */
2743     /* indication of what might actually be wrong. */
2744 
2745     if((getmsg(send_descriptor,
2746 	       &rctl_message,
2747 	       &recv_message,
2748 	       &flags) != 0) ||
2749        (data_ind->dl_primitive != DL_UNITDATA_IND)) {
2750       if (errno == EINTR) {
2751 	/* Again, we have likely hit test-end time */
2752 	break;
2753       }
2754       fprintf(where,
2755 	      "send_dlpi_cl_rr: recv error: errno %d primitive 0x%x\n",
2756 	      errno,
2757 	      data_ind->dl_primitive);
2758       fflush(where);
2759       exit(1);
2760     }
2761 #ifdef WANT_INTERVALS
2762     gettimeofday(&recv_time,&dummy_zone);
2763 
2764     /* now we do some arithmatic on the two timevals */
2765     if (recv_time.tv_usec < send_time.tv_usec) {
2766       /* we wrapped around a second */
2767       recv_time.tv_usec += 1000000;
2768       recv_time.tv_sec  -= 1;
2769     }
2770 
2771     /* and store it away */
2772     kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000;
2773     kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec);
2774 
2775     /* at this point, we may wish to sleep for some period of */
2776     /* time, so we see how long that last transaction just took, */
2777     /* and sleep for the difference of that and the interval. We */
2778     /* will not sleep if the time would be less than a */
2779     /* millisecond.  */
2780     if (interval_usecs > 0) {
2781       sleep_usecs = interval_usecs - kept_times[time_index];
2782       if (sleep_usecs > 1000) {
2783 	/* we sleep */
2784 	sleep_timeval.tv_sec = sleep_usecs / 1000000;
2785 	sleep_timeval.tv_usec = sleep_usecs % 1000000;
2786 	select(0,
2787 	       0,
2788 	       0,
2789 	       0,
2790 	       &sleep_timeval);
2791       }
2792     }
2793 
2794     /* now up the time index */
2795     time_index = (time_index +1)%MAX_KEPT_TIMES;
2796 #endif /* WANT_INTERVALS */
2797     nummessages++;
2798     if (trans_remaining) {
2799       trans_remaining--;
2800     }
2801 
2802     if (debug > 3) {
2803       fprintf(where,"Transaction %d completed\n",nummessages);
2804       fflush(where);
2805     }
2806 
2807   }
2808 
2809   /* this call will always give us the elapsed time for the test, and */
2810   /* will also store-away the necessaries for cpu utilization */
2811 
2812   cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being measured? */
2813   /* how long did we really run? */
2814 
2815   /* Get the statistics from the remote end. The remote will have */
2816   /* calculated service demand and all those interesting things. If it */
2817   /* wasn't supposed to care, it will return obvious values. */
2818 
2819   recv_response();
2820   if (!netperf_response.content.serv_errno) {
2821     if (debug)
2822       fprintf(where,"remote results obtained\n");
2823   }
2824   else {
2825     Set_errno(netperf_response.content.serv_errno);
2826     perror("netperf: remote error");
2827 
2828     exit(1);
2829   }
2830 
2831   /* We now calculate what our thruput was for the test. In the future, */
2832   /* we may want to include a calculation of the thruput measured by */
2833   /* the remote, but it should be the case that for a UDP stream test, */
2834   /* that the two numbers should be *very* close... We calculate */
2835   /* bytes_sent regardless of the way the test length was controlled. */
2836   /* If it was time, we needed to, and if it was by bytes, the user may */
2837   /* have specified a number of bytes that wasn't a multiple of the */
2838   /* send_size, so we really didn't send what he asked for ;-) We use */
2839 
2840   bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
2841   thruput		= calc_thruput(bytes_xferd);
2842 
2843   if (local_cpu_usage || remote_cpu_usage) {
2844     /* We must now do a little math for service demand and cpu */
2845     /* utilization for the system(s) */
2846     /* Of course, some of the information might be bogus because */
2847     /* there was no idle counter in the kernel(s). We need to make */
2848     /* a note of this for the user's benefit...*/
2849     if (local_cpu_usage) {
2850       if (local_cpu_rate == 0.0) {
2851 	fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
2852 	fprintf(where,"Local CPU usage numbers based on process information only!\n");
2853 	fflush(where);
2854       }
2855       local_cpu_utilization = calc_cpu_util(0.0);
2856       /* since calc_service demand is doing ms/Kunit we will */
2857       /* multiply the number of transaction by 1024 to get */
2858       /* "good" numbers */
2859       local_service_demand  = calc_service_demand((double) nummessages*1024,
2860 						  0.0,
2861 						  0.0,
2862 						  0);
2863     }
2864     else {
2865       local_cpu_utilization	= -1.0;
2866       local_service_demand	= -1.0;
2867     }
2868 
2869     if (remote_cpu_usage) {
2870       if (remote_cpu_rate == 0.0) {
2871 	fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!\n");
2872 	fprintf(where,"Remote CPU usage numbers based on process information only!\n");
2873 	fflush(where);
2874       }
2875       remote_cpu_utilization = dlpi_cl_rr_result->cpu_util;
2876       /* since calc_service demand is doing ms/Kunit we will */
2877       /* multiply the number of transaction by 1024 to get */
2878       /* "good" numbers */
2879       remote_service_demand  = calc_service_demand((double) nummessages*1024,
2880 						   0.0,
2881 						   remote_cpu_utilization,
2882 						   dlpi_cl_rr_result->num_cpus);
2883     }
2884     else {
2885       remote_cpu_utilization = -1.0;
2886       remote_service_demand  = -1.0;
2887     }
2888 
2889     /* We are now ready to print all the information. If the user */
2890     /* has specified zero-level verbosity, we will just print the */
2891     /* local service demand, or the remote service demand. If the */
2892     /* user has requested verbosity level 1, he will get the basic */
2893     /* "streamperf" numbers. If the user has specified a verbosity */
2894     /* of greater than 1, we will display a veritable plethora of */
2895     /* background information from outside of this block as it it */
2896     /* not cpu_measurement specific...  */
2897 
2898     switch (verbosity) {
2899     case 0:
2900       if (local_cpu_usage) {
2901 	fprintf(where,
2902 		cpu_fmt_0,
2903 		local_service_demand);
2904       }
2905       else {
2906 	fprintf(where,
2907 		cpu_fmt_0,
2908 		remote_service_demand);
2909       }
2910       break;
2911     case 1:
2912     case 2:
2913       fprintf(where,
2914 	      cpu_fmt_1_line_1,		/* the format string */
2915 	      lsw_size,		/* local sendbuf size */
2916 	      lrw_size,
2917 	      req_size,		/* how large were the requests */
2918 	      rsp_size,		/* guess */
2919 	      elapsed_time,		/* how long was the test */
2920 	      nummessages/elapsed_time,
2921 	      local_cpu_utilization,	/* local cpu */
2922 	      remote_cpu_utilization,	/* remote cpu */
2923 	      local_service_demand,	/* local service demand */
2924 	      remote_service_demand);	/* remote service demand */
2925       fprintf(where,
2926 	      cpu_fmt_1_line_2,
2927 	      rsw_size,
2928 	      rrw_size);
2929       break;
2930     }
2931   }
2932   else {
2933     /* The tester did not wish to measure service demand. */
2934     switch (verbosity) {
2935     case 0:
2936       fprintf(where,
2937 	      tput_fmt_0,
2938 	      nummessages/elapsed_time);
2939       break;
2940     case 1:
2941     case 2:
2942       fprintf(where,
2943 	      tput_fmt_1_line_1,	/* the format string */
2944 	      lsw_size,
2945 	      lrw_size,
2946 	      req_size,		/* how large were the requests */
2947 	      rsp_size,		/* how large were the responses */
2948 	      elapsed_time, 		/* how long did it take */
2949 	      nummessages/elapsed_time);
2950       fprintf(where,
2951 	      tput_fmt_1_line_2,
2952 	      rsw_size, 		/* remote recvbuf size */
2953 	      rrw_size);
2954 
2955       break;
2956     }
2957   }
2958 
2959   /* it would be a good thing to include information about some of the */
2960   /* other parameters that may have been set for this test, but at the */
2961   /* moment, I do not wish to figure-out all the  formatting, so I will */
2962   /* just put this comment here to help remind me that it is something */
2963   /* that should be done at a later time. */
2964 
2965   if (verbosity > 1) {
2966     /* The user wanted to know it all, so we will give it to him. */
2967     /* This information will include as much as we can find about */
2968     /* UDP statistics, the alignments of the sends and receives */
2969     /* and all that sort of rot... */
2970 
2971 #ifdef WANT_INTERVALS
2972     kept_times[MAX_KEPT_TIMES] = 0;
2973     time_index = 0;
2974     while (time_index < MAX_KEPT_TIMES) {
2975       if (kept_times[time_index] > 0) {
2976 	total_times += kept_times[time_index];
2977       }
2978       else
2979 	unused_buckets++;
2980       time_index += 1;
2981     }
2982     total_times /= (MAX_KEPT_TIMES-unused_buckets);
2983     fprintf(where,
2984 	    "Average response time %d usecs\n",
2985 	    total_times);
2986 #endif
2987   }
2988 }
2989 
2990 int
recv_dlpi_cl_rr()2991   recv_dlpi_cl_rr()
2992 {
2993 
2994   char  *message;
2995   int	data_descriptor;
2996   int   flags = 0;
2997   int	measure_cpu;
2998 
2999   char	*recv_message_ptr;
3000   char	*send_message_ptr;
3001   char  sctl_data[BUFSIZ];
3002   char  rctl_data[BUFSIZ];
3003   char  dlsap[BUFSIZ];
3004   struct strbuf send_message;
3005   struct strbuf recv_message;
3006   struct strbuf sctl_message;
3007   struct strbuf rctl_message;
3008 
3009   /* these are to make reading some of the DLPI control messages easier */
3010   dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
3011   dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
3012   dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
3013 
3014   int	trans_received;
3015   int	trans_remaining;
3016   float	elapsed_time;
3017 
3018   struct	dlpi_cl_rr_request_struct	*dlpi_cl_rr_request;
3019   struct	dlpi_cl_rr_response_struct	*dlpi_cl_rr_response;
3020   struct	dlpi_cl_rr_results_struct	*dlpi_cl_rr_results;
3021 
3022   dlpi_cl_rr_request  =
3023     (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
3024   dlpi_cl_rr_response =
3025     (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
3026   dlpi_cl_rr_results  =
3027     (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
3028 
3029   if (debug) {
3030     fprintf(where,"netserver: recv_dlpi_cl_rr: entered...\n");
3031     fflush(where);
3032   }
3033 
3034   /* We want to set-up the listen descriptor with all the desired */
3035   /* parameters and then let the initiator know that all is ready. If */
3036   /* socket size defaults are to be used, then the initiator will have */
3037   /* sent us 0's. If the descriptor sizes cannot be changed, then we will */
3038   /* send-back what they are. If that information cannot be determined, */
3039   /* then we send-back -1's for the sizes. If things go wrong for any */
3040   /* reason, we will drop back ten yards and punt. */
3041 
3042   /* If anything goes wrong, we want the remote to know about it. It */
3043   /* would be best if the error that the remote reports to the user is */
3044   /* the actual error we encountered, rather than some bogus unexpected */
3045   /* response type message. */
3046 
3047   if (debug) {
3048     fprintf(where,"recv_dlpi_cl_rr: setting the response type...\n");
3049     fflush(where);
3050   }
3051 
3052   netperf_response.content.response_type = DLPI_CL_RR_RESPONSE;
3053 
3054   if (debug) {
3055     fprintf(where,"recv_dlpi_cl_rr: the response type is set...\n");
3056     fflush(where);
3057   }
3058 
3059   /* set-up the data buffer with the requested alignment and offset */
3060   message = (char *)malloc(DATABUFFERLEN);
3061   if (message == NULL) {
3062     printf("malloc(%d) failed!\n", DATABUFFERLEN);
3063     exit(1);
3064   }
3065 
3066   /* We now alter the message_ptr variables to be at the desired */
3067   /* alignments with the desired offsets. */
3068 
3069   if (debug) {
3070     fprintf(where,
3071 	    "recv_dlpi_cl_rr: requested recv alignment of %d offset %d\n",
3072 	    dlpi_cl_rr_request->recv_alignment,
3073 	    dlpi_cl_rr_request->recv_offset);
3074     fprintf(where,
3075 	    "recv_dlpi_cl_rr: requested send alignment of %d offset %d\n",
3076 	    dlpi_cl_rr_request->send_alignment,
3077 	    dlpi_cl_rr_request->send_offset);
3078     fflush(where);
3079   }
3080 
3081   recv_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->recv_alignment, dlpi_cl_rr_request->recv_offset);
3082   recv_message.maxlen = dlpi_cl_rr_request->request_size;
3083   recv_message.len    = 0;
3084   recv_message.buf    = recv_message_ptr;
3085 
3086   send_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->send_alignment, dlpi_cl_rr_request->send_offset);
3087   send_message.maxlen = dlpi_cl_rr_request->response_size;
3088   send_message.len    = dlpi_cl_rr_request->response_size;
3089   send_message.buf    = send_message_ptr;
3090 
3091   sctl_message.maxlen = BUFSIZ;
3092   sctl_message.len    = 0;
3093   sctl_message.buf    = sctl_data;
3094 
3095   rctl_message.maxlen = BUFSIZ;
3096   rctl_message.len    = 0;
3097   rctl_message.buf    = rctl_data;
3098 
3099   if (debug) {
3100     fprintf(where,"recv_dlpi_cl_rr: receive alignment and offset set...\n");
3101     fprintf(where,"recv_dlpi_cl_rr: grabbing a socket...\n");
3102     fflush(where);
3103   }
3104 
3105 
3106 #ifdef __alpha
3107 
3108   /* ok - even on a DEC box, strings are strings. I din't really want */
3109   /* to ntohl the words of a string. since I don't want to teach the */
3110   /* send_ and recv_ _request and _response routines about the types, */
3111   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3112   /* solution would be to use XDR, but I am still leary of being able */
3113   /* to find XDR libs on all platforms I want running netperf. raj */
3114   {
3115     int *charword;
3116     int *initword;
3117     int *lastword;
3118 
3119     initword = (int *) dlpi_cl_rr_request->dlpi_device;
3120     lastword = initword + ((dlpi_cl_rr_request->dev_name_len + 3) / 4);
3121 
3122     for (charword = initword;
3123 	 charword < lastword;
3124 	 charword++) {
3125 
3126       *charword = htonl(*charword);
3127     }
3128   }
3129 #endif /* __alpha */
3130 
3131   data_descriptor = dl_open(dlpi_cl_rr_request->dlpi_device,
3132 			    dlpi_cl_rr_request->ppa);
3133   if (data_descriptor < 0) {
3134     netperf_response.content.serv_errno = errno;
3135     send_response();
3136     exit(1);
3137   }
3138 
3139 
3140   /* The initiator may have wished-us to modify the window */
3141   /* sizes. We should give it a shot. If he didn't ask us to change the */
3142   /* sizes, we should let him know what sizes were in use at this end. */
3143   /* If none of this code is compiled-in, then we will tell the */
3144   /* initiator that we were unable to play with the sizes by */
3145   /* setting the size in the response to -1. */
3146 
3147 #ifdef DL_HP_SET_LOCAL_WIN_REQ
3148 
3149   if (dlpi_cl_rr_request->recv_win_size) {
3150   }
3151 
3152   if (dlpi_cl_rr_request->send_win_size) {
3153   }
3154 
3155   /* Now, we will find-out what the sizes actually became, and report */
3156   /* them back to the user. If the calls fail, we will just report a -1 */
3157   /* back to the initiator for the buffer size. */
3158 
3159 #else /* the system won't let us play with the buffers */
3160 
3161   dlpi_cl_rr_response->recv_win_size	= -1;
3162   dlpi_cl_rr_response->send_win_size	= -1;
3163 
3164 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
3165 
3166   /* bind the sap and retrieve the dlsap assigned by the system  */
3167   dlpi_cl_rr_response->station_addr_len = 14; /* arbitrary */
3168   if (dl_bind(data_descriptor,
3169 	      dlpi_cl_rr_request->sap,
3170 	      DL_CLDLS,
3171 	      (char *)dlpi_cl_rr_response->station_addr,
3172 	      &dlpi_cl_rr_response->station_addr_len) != 0) {
3173     fprintf(where,"send_dlpi_cl_rr: bind failure\n");
3174     fflush(where);
3175     exit(1);
3176   }
3177 
3178   netperf_response.content.serv_errno   = 0;
3179 
3180   /* But wait, there's more. If the initiator wanted cpu measurements, */
3181   /* then we must call the calibrate routine, which will return the max */
3182   /* rate back to the initiator. If the CPU was not to be measured, or */
3183   /* something went wrong with the calibration, we will return a 0.0 to */
3184   /* the initiator. */
3185 
3186   dlpi_cl_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
3187   if (dlpi_cl_rr_request->measure_cpu) {
3188     dlpi_cl_rr_response->measure_cpu = 1;
3189     dlpi_cl_rr_response->cpu_rate = calibrate_local_cpu(dlpi_cl_rr_request->cpu_rate);
3190   }
3191 
3192   send_response();
3193 
3194   /* Now it's time to start receiving data on the connection. We will */
3195   /* first grab the apropriate counters and then start receiving. */
3196 
3197   cpu_start(dlpi_cl_rr_request->measure_cpu);
3198 
3199   if (dlpi_cl_rr_request->test_length > 0) {
3200     times_up = 0;
3201     trans_remaining = 0;
3202     start_timer(dlpi_cl_rr_request->test_length + PAD_TIME);
3203   }
3204 else {
3205   times_up = 1;
3206   trans_remaining = dlpi_cl_rr_request->test_length * -1;
3207 }
3208 
3209   while ((!times_up) || (trans_remaining > 0)) {
3210 
3211     /* receive the request from the other side. at some point we need */
3212     /* to handle "logical" requests and responses which are larger */
3213     /* than the data link MTU */
3214 
3215     if((getmsg(data_descriptor,
3216 	       &rctl_message,
3217 	       &recv_message,
3218 	       &flags) != 0) ||
3219        (data_ind->dl_primitive != DL_UNITDATA_IND)) {
3220       if (errno == EINTR) {
3221 	/* Again, we have likely hit test-end time */
3222 	break;
3223       }
3224       fprintf(where,
3225 	      "dlpi_recv_cl_rr: getmsg failure: errno %d primitive 0x%x\n",
3226 	      errno,
3227 	      data_ind->dl_primitive);
3228       fprintf(where,
3229 	      "                 recevied %u transactions\n",
3230 	      trans_received);
3231       fflush(where);
3232       netperf_response.content.serv_errno = 995;
3233       send_response();
3234       exit(1);
3235     }
3236 
3237     /* Now, send the response to the remote. first copy the dlsap */
3238     /* information from the receive to the sending control message */
3239 
3240     data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
3241     bcopy((char *)data_ind + data_ind->dl_src_addr_offset,
3242 	  (char *)data_req + data_req->dl_dest_addr_offset,
3243 	  data_ind->dl_src_addr_length);
3244     data_req->dl_dest_addr_length = data_ind->dl_src_addr_length;
3245     data_req->dl_primitive = DL_UNITDATA_REQ;
3246     /* be sure to initialize the priority fields. fix from Nicholas
3247        Thomas */
3248     data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
3249     data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
3250 
3251     sctl_message.len = sizeof(dl_unitdata_req_t) +
3252       data_ind->dl_src_addr_length;
3253     if(putmsg(data_descriptor,
3254 	      &sctl_message,
3255 	      &send_message,
3256 	      0) != 0) {
3257       if (errno == EINTR) {
3258 	/* We likely hit */
3259 	/* test-end time. */
3260 	break;
3261       }
3262       /* there is more we could do here, but it can wait */
3263       fprintf(where,
3264 	      "dlpi_recv_cl_rr: putmsg failure: errno %d\n",
3265 	      errno);
3266       fflush(where);
3267       netperf_response.content.serv_errno = 993;
3268       send_response();
3269       exit(1);
3270     }
3271 
3272     trans_received++;
3273     if (trans_remaining) {
3274       trans_remaining--;
3275     }
3276 
3277     if (debug) {
3278       fprintf(where,
3279 	      "recv_dlpi_cl_rr: Transaction %d complete.\n",
3280 	      trans_received);
3281       fflush(where);
3282     }
3283 
3284   }
3285 
3286 
3287   /* The loop now exits due to timeout or transaction count being */
3288   /* reached */
3289 
3290   cpu_stop(dlpi_cl_rr_request->measure_cpu,&elapsed_time);
3291 
3292   if (times_up) {
3293     /* we ended the test by time, which was at least 2 seconds */
3294     /* longer than we wanted to run. so, we want to subtract */
3295     /* PAD_TIME from the elapsed_time. */
3296     elapsed_time -= PAD_TIME;
3297   }
3298   /* send the results to the sender			*/
3299 
3300   if (debug) {
3301     fprintf(where,
3302 	    "recv_dlpi_cl_rr: got %d transactions\n",
3303 	    trans_received);
3304     fflush(where);
3305   }
3306 
3307   dlpi_cl_rr_results->bytes_received	= (trans_received *
3308 					   (dlpi_cl_rr_request->request_size +
3309 					    dlpi_cl_rr_request->response_size));
3310   dlpi_cl_rr_results->trans_received	= trans_received;
3311   dlpi_cl_rr_results->elapsed_time	= elapsed_time;
3312   if (dlpi_cl_rr_request->measure_cpu) {
3313     dlpi_cl_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
3314   }
3315 
3316   if (debug) {
3317     fprintf(where,
3318 	    "recv_dlpi_cl_rr: test complete, sending results.\n");
3319     fflush(where);
3320   }
3321 
3322   send_response();
3323 
3324 }
3325 
3326 int
recv_dlpi_co_rr()3327   recv_dlpi_co_rr()
3328 {
3329 
3330   char  *message;
3331   SOCKET	s_listen,data_descriptor;
3332 
3333   int	measure_cpu;
3334 
3335   int   flags = 0;
3336   char	*recv_message_ptr;
3337   char	*send_message_ptr;
3338   struct strbuf send_message;
3339   struct strbuf recv_message;
3340 
3341   int	trans_received;
3342   int	trans_remaining;
3343   int	request_bytes_remaining;
3344   int	timed_out = 0;
3345   float	elapsed_time;
3346 
3347   struct	dlpi_co_rr_request_struct	*dlpi_co_rr_request;
3348   struct	dlpi_co_rr_response_struct	*dlpi_co_rr_response;
3349   struct	dlpi_co_rr_results_struct	*dlpi_co_rr_results;
3350 
3351   dlpi_co_rr_request	= (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
3352   dlpi_co_rr_response	= (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
3353   dlpi_co_rr_results	= (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
3354 
3355   if (debug) {
3356     fprintf(where,"netserver: recv_dlpi_co_rr: entered...\n");
3357     fflush(where);
3358   }
3359 
3360   /* We want to set-up the listen socket with all the desired */
3361   /* parameters and then let the initiator know that all is ready. If */
3362   /* socket size defaults are to be used, then the initiator will have */
3363   /* sent us 0's. If the socket sizes cannot be changed, then we will */
3364   /* send-back what they are. If that information cannot be determined, */
3365   /* then we send-back -1's for the sizes. If things go wrong for any */
3366   /* reason, we will drop back ten yards and punt. */
3367 
3368   /* If anything goes wrong, we want the remote to know about it. It */
3369   /* would be best if the error that the remote reports to the user is */
3370   /* the actual error we encountered, rather than some bogus unexpected */
3371   /* response type message. */
3372 
3373   if (debug) {
3374     fprintf(where,"recv_dlpi_co_rr: setting the response type...\n");
3375     fflush(where);
3376   }
3377 
3378   netperf_response.content.response_type = DLPI_CO_RR_RESPONSE;
3379 
3380   if (debug) {
3381     fprintf(where,"recv_dlpi_co_rr: the response type is set...\n");
3382     fflush(where);
3383   }
3384 
3385   /* set-up the data buffer with the requested alignment and offset */
3386   message = (char *)malloc(DATABUFFERLEN);
3387   if (message == NULL) {
3388     printf("malloc(%d) failed!\n", DATABUFFERLEN);
3389     exit(1);
3390   }
3391 
3392   /* We now alter the message_ptr variables to be at the desired */
3393   /* alignments with the desired offsets. */
3394 
3395   if (debug) {
3396     fprintf(where,
3397 	    "recv_dlpi_co_rr: requested recv alignment of %d offset %d\n",
3398 	    dlpi_co_rr_request->recv_alignment,
3399 	    dlpi_co_rr_request->recv_offset);
3400     fprintf(where,
3401 	    "recv_dlpi_co_rr: requested send alignment of %d offset %d\n",
3402 	    dlpi_co_rr_request->send_alignment,
3403 	    dlpi_co_rr_request->send_offset);
3404     fflush(where);
3405   }
3406 
3407   recv_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->recv_alignment, dlpi_co_rr_request->recv_offset);
3408   recv_message.maxlen = dlpi_co_rr_request->request_size;
3409   recv_message.len    = 0;
3410   recv_message.buf    = recv_message_ptr;
3411 
3412   send_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->send_alignment, dlpi_co_rr_request->send_offset);
3413   send_message.maxlen = dlpi_co_rr_request->response_size;
3414   send_message.len    = dlpi_co_rr_request->response_size;
3415   send_message.buf    = send_message_ptr;
3416 
3417   if (debug) {
3418     fprintf(where,"recv_dlpi_co_rr: receive alignment and offset set...\n");
3419     fprintf(where,"recv_dlpi_co_rr: send_message.buf %x .len %d .maxlen %d\n",
3420 	    send_message.buf,send_message.len,send_message.maxlen);
3421     fprintf(where,"recv_dlpi_co_rr: recv_message.buf %x .len %d .maxlen %d\n",
3422 	    recv_message.buf,recv_message.len,recv_message.maxlen);
3423     fflush(where);
3424   }
3425 
3426   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
3427   /* can put in OUR values !-) At some point, we may want to nail this */
3428   /* socket to a particular network-level address, but for now, */
3429   /* INADDR_ANY should be just fine. */
3430 
3431   /* Grab a socket to listen on, and then listen on it. */
3432 
3433   if (debug) {
3434     fprintf(where,"recv_dlpi_co_rr: grabbing a socket...\n");
3435     fflush(where);
3436   }
3437 
3438   /* lets grab a file descriptor for a particular link */
3439 
3440 #ifdef __alpha
3441 
3442   /* ok - even on a DEC box, strings are strings. I din't really want */
3443   /* to ntohl the words of a string. since I don't want to teach the */
3444   /* send_ and recv_ _request and _response routines about the types, */
3445   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3446   /* solution would be to use XDR, but I am still leary of being able */
3447   /* to find XDR libs on all platforms I want running netperf. raj */
3448   {
3449     int *charword;
3450     int *initword;
3451     int *lastword;
3452 
3453     initword = (int *) dlpi_co_rr_request->dlpi_device;
3454     lastword = initword + ((dlpi_co_rr_request->dev_name_len + 3) / 4);
3455 
3456     for (charword = initword;
3457 	 charword < lastword;
3458 	 charword++) {
3459 
3460       *charword = htonl(*charword);
3461     }
3462   }
3463 #endif /* __alpha */
3464 
3465   if ((data_descriptor = dl_open(dlpi_co_rr_request->dlpi_device,
3466 				 dlpi_co_rr_request->ppa)) < 0) {
3467     netperf_response.content.serv_errno = errno;
3468     send_response();
3469     exit(1);
3470   }
3471 
3472   /* bind the file descriptor to a sap and get the resultant dlsap */
3473   dlpi_co_rr_response->station_addr_len = 14; /*arbitrary needs fixing */
3474   if (dl_bind(data_descriptor,
3475               dlpi_co_rr_request->sap,
3476               DL_CODLS,
3477               (char *)dlpi_co_rr_response->station_addr,
3478               &dlpi_co_rr_response->station_addr_len) != 0) {
3479     netperf_response.content.serv_errno = errno;
3480     send_response();
3481     exit(1);
3482   }
3483 
3484   /* The initiator may have wished-us to modify the socket buffer */
3485   /* sizes. We should give it a shot. If he didn't ask us to change the */
3486   /* sizes, we should let him know what sizes were in use at this end. */
3487   /* If none of this code is compiled-in, then we will tell the */
3488   /* initiator that we were unable to play with the socket buffer by */
3489   /* setting the size in the response to -1. */
3490 
3491 #ifdef DL_HP_SET_LOCAL_WIN_REQ
3492 
3493   if (dlpi_co_rr_request->recv_win_size) {
3494     /* SMOP */
3495   }
3496 
3497   if (dlpi_co_rr_request->send_win_size) {
3498     /* SMOP */
3499   }
3500 
3501   /* Now, we will find-out what the sizes actually became, and report */
3502   /* them back to the user. If the calls fail, we will just report a -1 */
3503   /* back to the initiator for the buffer size. */
3504 
3505 #else /* the system won't let us play with the buffers */
3506 
3507   dlpi_co_rr_response->recv_win_size	= -1;
3508   dlpi_co_rr_response->send_win_size	= -1;
3509 
3510 #endif /* DL_HP_SET_LOCAL_WIN_REQ */
3511 
3512   /* we may have been requested to enable the copy avoidance features. */
3513   /* can we actually do this with DLPI, the world wonders */
3514 
3515   if (dlpi_co_rr_request->so_rcvavoid) {
3516 #ifdef SO_RCV_COPYAVOID
3517     dlpi_co_rr_response->so_rcvavoid = 0;
3518 #else
3519     /* it wasn't compiled in... */
3520     dlpi_co_rr_response->so_rcvavoid = 0;
3521 #endif
3522   }
3523 
3524   if (dlpi_co_rr_request->so_sndavoid) {
3525 #ifdef SO_SND_COPYAVOID
3526     dlpi_co_rr_response->so_sndavoid = 0;
3527 #else
3528     /* it wasn't compiled in... */
3529     dlpi_co_rr_response->so_sndavoid = 0;
3530 #endif
3531   }
3532 
3533   netperf_response.content.serv_errno   = 0;
3534 
3535   /* But wait, there's more. If the initiator wanted cpu measurements, */
3536   /* then we must call the calibrate routine, which will return the max */
3537   /* rate back to the initiator. If the CPU was not to be measured, or */
3538   /* something went wrong with the calibration, we will return a 0.0 to */
3539   /* the initiator. */
3540 
3541   dlpi_co_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
3542   if (dlpi_co_rr_request->measure_cpu) {
3543     dlpi_co_rr_response->measure_cpu = 1;
3544     dlpi_co_rr_response->cpu_rate = calibrate_local_cpu(dlpi_co_rr_request->cpu_rate);
3545   }
3546 
3547   send_response();
3548 
3549   /* accept a connection on this file descriptor. at some point, */
3550   /* dl_accept will "do the right thing" with the last two parms, but */
3551   /* for now it ignores them, so we will pass zeros. */
3552 
3553   if(dl_accept(data_descriptor, 0, 0) != 0) {
3554     fprintf(where,
3555 	    "recv_dlpi_co_rr: error in accept, errno %d\n",
3556 	    errno);
3557     fflush(where);
3558     netperf_response.content.serv_errno = errno;
3559     send_response();
3560     exit(1);
3561   }
3562 
3563   if (debug) {
3564     fprintf(where,
3565 	    "recv_dlpi_co_rr: accept completes on the data connection.\n");
3566     fflush(where);
3567   }
3568 
3569   /* Now it's time to start receiving data on the connection. We will */
3570   /* first grab the apropriate counters and then start grabbing. */
3571 
3572   cpu_start(dlpi_co_rr_request->measure_cpu);
3573 
3574   /* The loop will exit when the sender does a shutdown, which will */
3575   /* return a length of zero   */
3576 
3577   if (dlpi_co_rr_request->test_length > 0) {
3578     times_up = 0;
3579     trans_remaining = 0;
3580     start_timer(dlpi_co_rr_request->test_length + PAD_TIME);
3581   }
3582 else {
3583   times_up = 1;
3584   trans_remaining = dlpi_co_rr_request->test_length * -1;
3585 }
3586 
3587   while ((!times_up) || (trans_remaining > 0)) {
3588     request_bytes_remaining	= dlpi_co_rr_request->request_size;
3589 
3590     /* receive the request from the other side. there needs to be some */
3591     /* more login in place for handling messages larger than link mtu, */
3592     /* but that can wait for later */
3593     while(request_bytes_remaining > 0) {
3594       if((getmsg(data_descriptor,
3595 		 0,
3596 		 &recv_message,
3597 		 &flags)) < 0) {
3598 	if (errno == EINTR) {
3599 	  /* the timer popped */
3600 	  timed_out = 1;
3601 	  break;
3602 	}
3603 
3604         if (debug) {
3605 	  fprintf(where,"failed getmsg call errno %d\n",errno);
3606 	  fprintf(where,"recv_message.len %d\n",recv_message.len);
3607 	  fprintf(where,"send_message.len %d\n",send_message.len);
3608 	  fflush(where);
3609         }
3610 
3611 	netperf_response.content.serv_errno = errno;
3612 	send_response();
3613 	exit(1);
3614       }
3615       else {
3616 	request_bytes_remaining -= recv_message.len;
3617       }
3618     }
3619 
3620     if (timed_out) {
3621       /* we hit the end of the test based on time - lets bail out of */
3622       /* here now... */
3623       break;
3624     }
3625 
3626     if (debug) {
3627       fprintf(where,"recv_message.len %d\n",recv_message.len);
3628       fprintf(where,"send_message.len %d\n",send_message.len);
3629       fflush(where);
3630     }
3631 
3632     /* Now, send the response to the remote */
3633     if((putmsg(data_descriptor,
3634 	       0,
3635 	       &send_message,
3636 	       0)) != 0) {
3637       if (errno == EINTR) {
3638 	/* the test timer has popped */
3639 	timed_out = 1;
3640 	break;
3641       }
3642       netperf_response.content.serv_errno = 994;
3643       send_response();
3644       exit(1);
3645     }
3646 
3647     trans_received++;
3648     if (trans_remaining) {
3649       trans_remaining--;
3650     }
3651 
3652     if (debug) {
3653       fprintf(where,
3654 	      "recv_dlpi_co_rr: Transaction %d complete\n",
3655 	      trans_received);
3656       fflush(where);
3657     }
3658   }
3659 
3660 
3661   /* The loop now exits due to timeout or transaction count being */
3662   /* reached */
3663 
3664   cpu_stop(dlpi_co_rr_request->measure_cpu,&elapsed_time);
3665 
3666   if (timed_out) {
3667     /* we ended the test by time, which was at least 2 seconds */
3668     /* longer than we wanted to run. so, we want to subtract */
3669     /* PAD_TIME from the elapsed_time. */
3670     elapsed_time -= PAD_TIME;
3671   }
3672   /* send the results to the sender			*/
3673 
3674   if (debug) {
3675     fprintf(where,
3676 	    "recv_dlpi_co_rr: got %d transactions\n",
3677 	    trans_received);
3678     fflush(where);
3679   }
3680 
3681   dlpi_co_rr_results->bytes_received	= (trans_received *
3682 					   (dlpi_co_rr_request->request_size +
3683 					    dlpi_co_rr_request->response_size));
3684   dlpi_co_rr_results->trans_received	= trans_received;
3685   dlpi_co_rr_results->elapsed_time	= elapsed_time;
3686   if (dlpi_co_rr_request->measure_cpu) {
3687     dlpi_co_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
3688   }
3689 
3690   if (debug) {
3691     fprintf(where,
3692 	    "recv_dlpi_co_rr: test complete, sending results.\n");
3693     fflush(where);
3694   }
3695 
3696   send_response();
3697 
3698 }
3699 
3700 /* this routine will display the usage string for the DLPI tests */
3701 void
print_dlpi_usage()3702   print_dlpi_usage()
3703 
3704 {
3705   fwrite(dlpi_usage, sizeof(char), strlen(dlpi_usage), stdout);
3706 }
3707 
3708 
3709 /* this routine will scan the command line for DLPI test arguments */
3710 void
scan_dlpi_args(int argc,char * argv[])3711   scan_dlpi_args(int argc, char *argv[])
3712 {
3713   extern int	optind, opterrs;  /* index of first unused arg 	*/
3714   extern char	*optarg;	  /* pointer to option string	*/
3715 
3716   int		c;
3717 
3718   char	arg1[BUFSIZ],  /* argument holders		*/
3719   arg2[BUFSIZ];
3720 
3721   if (no_control) {
3722     fprintf(where,
3723 	    "The DLPI tests do not know how to run with no control connection\n");
3724     exit(-1);
3725   }
3726 
3727   /* Go through all the command line arguments and break them */
3728   /* out. For those options that take two parms, specifying only */
3729   /* the first will set both to that value. Specifying only the */
3730   /* second will leave the first untouched. To change only the */
3731   /* first, use the form first, (see the routine break_args.. */
3732 
3733 #define DLPI_ARGS "D:hM:m:p:r:s:W:w:"
3734 
3735   while ((c= getopt(argc, argv, DLPI_ARGS)) != EOF) {
3736     switch (c) {
3737     case '?':
3738     case 'h':
3739       print_dlpi_usage();
3740       exit(1);
3741     case 'D':
3742       /* set the dlpi device file name(s) */
3743       break_args(optarg,arg1,arg2);
3744       if (arg1[0])
3745 	strcpy(loc_dlpi_device,arg1);
3746       if (arg2[0])
3747 	strcpy(rem_dlpi_device,arg2);
3748       break;
3749     case 'm':
3750       /* set the send size */
3751       send_size = atoi(optarg);
3752       break;
3753     case 'M':
3754       /* set the recv size */
3755       recv_size = atoi(optarg);
3756       break;
3757     case 'p':
3758       /* set the local/remote ppa */
3759       break_args(optarg,arg1,arg2);
3760       if (arg1[0])
3761 	loc_ppa = atoi(arg1);
3762       if (arg2[0])
3763 	rem_ppa = atoi(arg2);
3764       break;
3765     case 'r':
3766       /* set the request/response sizes */
3767       break_args(optarg,arg1,arg2);
3768       if (arg1[0])
3769 	req_size = atoi(arg1);
3770       if (arg2[0])
3771 	rsp_size = atoi(arg2);
3772       break;
3773     case 's':
3774       /* set the 802.2 sap for the test */
3775       dlpi_sap = atoi(optarg);
3776       break;
3777     case 'w':
3778       /* set local window sizes */
3779       break_args(optarg,arg1,arg2);
3780       if (arg1[0])
3781 	lsw_size = atoi(arg1);
3782       if (arg2[0])
3783 	lrw_size = atoi(arg2);
3784       break;
3785     case 'W':
3786       /* set remote window sizes */
3787       break_args(optarg,arg1,arg2);
3788       if (arg1[0])
3789 	rsw_size = atoi(arg1);
3790       if (arg2[0])
3791 	rrw_size = atoi(arg2);
3792       break;
3793     };
3794   }
3795 }
3796 
3797 
3798 #endif /* WANT_DLPI */
3799