HP OpenVMS I/O User’s Reference Manual: OpenVMS Version 8.4 > Chapter 9 Local Area Network (LAN) Device Drivers
9.8 Application Programming Notes
This section contains information to assist you in writing application
programs that use the LAN device drivers. “Promiscuous Mode” discusses
the additional rules required for application programs that you intend
to run in promiscuous mode. “Local Area Network Programming Examples” describe the Ethernet and 802 sample
programs. 9.8.1 Promiscuous Mode | |
The LAN drivers allow only one port per controller to enable promiscuous
mode (NMA$C_PCLI_PRM specified as NMA$C_STATE_ON). A port running
in promiscuous mode usually places an additional load on the CPU because
the LAN device is configured to deliver all received packets to the
LAN driver regardless of destination address or multicast filtering.
The LAN driver then has deliver the packets to the promiscuous port
as well as a copy to the intended recipient. Table 9-41 details additional rules for ports running in promiscuous mode. Table 9-41 Rules for Promiscuous Mode Operation I/O Function | Rule |
---|
IO$_SETMODE IO$_SETCHAR | It is not necessary
to specify a unique identifier (a protocol type, SAP, or protocol
identifier parameter ID) in the P2 buffer. The port cannot
be running in shared mode. | IO$_WRITE | The user can only transmit
packets in the packet format previously specified with a set mode
QIO when the user was started. The unique identifier for the packet
format must be included in the P5 buffer following the destination
address (see “Write” ). | IO$_READ | The LAN driver completes the promiscuous user's
read requests with Ethernet, 802, and 802 extended packets. Because
any packet format can be used to complete a read request, the P5 parameter
(if specified) must be at least 20 bytes in length (21 bytes for FDDI
with RFC turned on). All Ethernet format packets are processed
as if they have no size field specified after the protocol type. Therefore,
Ethernet packets are always returned with 46 to 1500 bytes of data.
If the Ethernet packet contains a size field, it is returned as part
of the user data in the first word of the P1 buffer. The
promiscuous user should use the information returned in the P5 buffer
to determine the packet format. If the application program first filled
the P5 buffer with zeros, the program can determine the format of
the packet received by scanning the P5 buffer after the read request
is completed. |
9.8.2 Local Area Network Programming Examples | |
The MACRO program LANETH.MAR (Example 9-2 shows the typical use of
QIO functions in driver operations such as establishing the protocol
type, starting the port, and transmitting and receiving data. The
program sends a LOOPBACK packet and waits for the packet to be returned. The HP C program
LAN802E.C (Example 9-3 ) shows
how to initialize an 802E port and how to send and receive packets
on that port. This program sends a LOOPBACK packet and waits for the
packet to be returned. Example 9-2 LANETH.MAR Local Area Network Programming Example |
.TITLE LAN SAMPLE TEST PROGRAM
.IDENT /X03/
.PSECT RWDATA,WRT,NOEXE,PAGE
; This LAN test program sends a MOP loopback message to the Loopback Assistant
; Multicast address and waits for a response. The program uses the LAN device
; EWA0. To use a different device, change the device name in the program or
; define the desired lan device as EWA0.
;
* To build on VAX, Alpha, I64:
; $ MACRO/OBJECT=LANETH/LIST=LANETH SYS$LIBRARY:ARCH_DEFS.MAR+SYS$DISK:[]LANETH
; $ LINK LANETH
;
; To run:
; $ RUN LANETH
.LIBRARY "SYS$LIBRARY:LIB.MLB"
$IODEF ; Define I/O functions and modifiers
$NMADEF ; Define Network Management parameters
; Setmode parameter buffer and descriptor. Since the loopback protocol does
; not include a length word following the protocol type, we have to explicitly
; turn off padding since the default is on.
SETPARM:
.WORD NMA$C_PCLIFMT ; Packet format
.LONG NMA$C_LIFM_ETH ; Ethernet
.WORD NMA$C_PCLI_PTY ; Protocol type
.LONG ^X0090 ; Loopback
.WORD NMA$C_PCLI_PAD ; Padding
.LONG NMA$C_STATE_OFF ; Off
SETPARMLEN = .-SETPARM
SETPARMDSC:
.LONG SETPARMLEN
.ADDRESS SETPARM
; Sensemode parameter buffer and descriptor. This is used to get our physical
; address to put into the loopback message.
SENSEBUF:
.BLKB 512
SENSELEN=.-SENSEBUF
SENSEDSC:
.LONG SENSELEN
.ADDRESS SENSEBUF
; P2 transmit data buffer.
XMTBUF: .WORD 00 ; Skip count
.WORD 02 ; Forward request
FORW: .BLKB 6 ; Forward address
.WORD 01 ; Reply request
.WORD 00
XMTBUFLEN = .-XMTBUF ; Size of transmit buffer
; P5 transmit destination address, the Loopback Assistant Multicast Address.
XMTP5: .BYTE ^XCF,0,0,0,0,0
; P2 receive data buffer.
RCVBUF: .BLKB 512
RCVBUFLEN = .-RCVBUF ; Size of receive buffer
; P5 receive header buffer.
RCVP5:
RCVDA: .BLKB 6
RCVSA: .BLKB 6
RCVPTY: .BLKB 2
; Messages used to display status of this program.
GMSG: .ASCID "Successful test"
LMSG: .ASCID "No response"
EMSG: .ASCID "Error occurred while running test"
DMSG: .ASCID "LAN device not found"
; Miscellaneous data.
IOSB: .BLKQ 1 ; I/O status block
DEVCHAN:.BLKL 1 ; Returned port number
LANDSC: .ASCID 'EWA0' ; Device to use for test
;*************************************************************************
;
; Start of code
;
;*************************************************************************
.PSECT CODE,EXE,NOWRT,PAGE
.ENTRY START,^M<>
; Assign a port to the LAN device.
$ASSIGN_S DEVNAM=LANDSC,CHAN=DEVCHAN
BLBS R0,10$ ; Branch if succeeded
MOVAL DMSG,R9 ; Get address of error message
BRW EXIT ; Print message and exit
; Set up the port's characteristics.
10$: MOVAL EMSG,R9 ; Assume error message address
$QIOW_S FUNC=#<IO$_SETMODE!IO$M_CTRL!IO$M_STARTUP>,-
CHAN=DEVCHAN,IOSB=IOSB,-
P2=#SETPARMDSC
BLBC R0,20$ ; Branch if failed
MOVZWL IOSB,R0 ; Get status from IOSB
BLBS R0,30$ ; Branch if succeeded
20$: BRW EXIT ; Print message and exit
; Issue the SENSEMODE QIO to get our physical address for the loopback
; message.
30$: $QIOW_S FUNC=#<IO$_SENSEMODE!IO$M_CTRL>,-
CHAN=DEVCHAN,IOSB=IOSB,-
P2=#SENSEDSC
BLBC R0,20$ ; Branch if failed
MOVZWL IOSB,R0 ; Get status from IOSB
BLBC R0,20$ ; Branch if failed
; Locate the PHA parameter in the SENSEMODE buffer and copy it into the
; LOOPBACK transmit message. The PHA parameter is a string parameter.
MOVAB SENSEBUF,R0 ; Start at beginning of buffer
40$: BBS #^XC,(R0),50$ ; Branch if a string parameter
ADDL #6,R0 ; Skip over longword parameter
BRB 40$ ; Check next parameter
50$: BICW3 #^XF000,(R0)+,R1 ; Get type field less flag bits
CMPW R1,#NMA$C_PCLI_PHA ; Is this the PHA parameter?
BEQL 60$ ; Branch if so
ADDW (R0)+,R0 ; Skip over string parameter
BRW 40$ ; Check next parameter
.IF NOT_DEFINED VAX
.DISABLE FLAGGING
.ENDC
60$: MOVL 2(R0),FORW ; Copy our address to the loopback
MOVW 6(R0),FORW+4 ; packet we are about to transmit
.IF NOT_DEFINED VAX
.ENABLE FLAGGING
.ENDC
; Transmit the loopback message.
$QIOW_S FUNC=#IO$_WRITEVBLK,CHAN=DEVCHAN,IOSB=IOSB,-
P1=XMTBUF,P2=#XMTBUFLEN,P5=#XMTP5
BLBC R0,70$ ; Branch if failed
MOVZWL IOSB,R0 ; Get status from IOSB
BLBS R0,80$ ; Branch if succeeded
70$: BRW EXIT ; Print message and exit
; Look for a response. We use the NOW function modifier on the READ so that
; we don't hang here waiting forever if there is no response. If there is no
; response in 1000 receive attempts, we declare no response status.
80$: MOVL #1000,R2 ; Check 1000 times
90$: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,CHAN=DEVCHAN,IOSB=IOSB,-
P1=RCVBUF,P2=#RCVBUFLEN,P5=#RCVP5
BLBC R0,EXIT ; Branch if failed
MOVZWL IOSB,R0 ; Get status from IOSB
BLBS R0,100$ ; Branch if succeeded
CMPL R0,#SS$_ENDOFFILE ; Was there just no message available?
BNEQ EXIT ; Branch if failed
SOBGTR R2,90$ ; Try again
; No response in 1000 attempts.
MOVAL LMSG,R9 ; Get address of lost message
BRW EXIT ; Print message and exit
; Received a message.
100$: MOVAL GMSG,R9 ; Get address of success message
; The test is done. Call LIB$PUT_OUTPUT to display the test status.
EXIT: PUSHL R9 ; P1 = Address of message to print
CALLS #1,G^LIB$PUT_OUTPUT ; Print the message
$EXIT_S ; Exit
.END START
|
|
Example 9-3 LAN802.C Local Area Network Programming Example |
/*************************************************************
* LAN Sample Test Program
*
* This LAN test program sends a MOP loopback message to the Loopback Assistant
* Multicast address and waits for a response. The program uses the LAN device
* EWA0. To use a different device, change the device name in the program or
* define the desired lan device as EWA0.
*
* To build on VAX:
* $ CC LAN802E
* $ LINK LAN802E,SYS$INPUT:/OPT
* SYS$SHARE:VAXCRTL.EXE/SHARE
*
* Note: NMADEF.H must be supplied containing definitions for:
*
* #define NMA$C_PCLIFMT 2770
* #define NMA$C_PCLI_PID 2774
* #define NMA$C_PCLI_PHA 2820
* #define NMA$C_LIFM_802E 0
*
* To build on Alpha, I64:
* $ CC LAN802E+SYS$LIBRARY:SYS$LIB_C.TLB/LIB
* $ LINK LAN802E
*
* To run:
* $ RUN LAN802E
*************************************************************/
#include <ctype> /* Character type classification macros/routines */
#include <descrip> /* For VMS descriptor manipulation */
#include <iodef> /* I/O function code definitions */
#include "nmadef.h" /* LAN parameter definitions */
#include <ssdef> /* System service return status code definitions */
#include <starlet> /* System library routine prototypes */
#include <stdio> /* ANSI C Standard Input/Output */
#include <stdlib> /* General utilities */
#include <string> /* String handling */
#include <stsdef> /* VMS status code definitions */
#define $SUCCESS(status) (((status) & STS$M_SUCCESS) == SS$_NORMAL)
#define $FAIL(status) (((status) & STS$M_SUCCESS) != SS$_NORMAL)
#pragma nomember_alignment
struct parm_802e
{
short pcli_fmt; /* Format - 802E */
int fmt_value;
short pcli_pid; /* Protocol ID - 08-00-2B-90-00 */
short pid_length;
char pid_value[5];
} setparm_802e = {NMA$C_PCLIFMT, NMA$C_LIFM_802E,
NMA$C_PCLI_PID, 5, 8,0,0x2B,0x90,0};
struct setparmdsc
{
int parm_len;
void *parm_buffer;
};
struct setparmdsc setparmdsc_loop = {
sizeof(setparm_802e),&setparm_802e};
struct p5_param /* P5 Receive header buffer */
{
unsigned char da[6];
unsigned char sa[6];
char misc[20];
};
struct iosb /* IOSB structure */
{
short w_err; /* Completion status */
short w_xfer_size; /* Transfer size */
short w_addl; /* Additional status */
short w_misc; /* Miscellaneous */
};
struct ascid /* Device descriptor for assign */
{
short w_len;
short w_info;
char *a_string;
} devdsc = {4,0,"EWA0"};
struct iosb qio_iosb; /* IOSB structure */
struct p5_param rcv_param; /* Receive header structure */
struct p5_param xmt_param = { /* Transmit header structure */
0xCF,0,0,0,0,0};
char rcv_buffer[512]; /* Receive buffer */
char xmt_buffer[20] = { /* Transmit buffer */
0,0, /* Skip count */
2,0, /* Forward request */
0,0,0,0,0,0, /* Forward address */
1,0, /* Reply request */
0,0};
char sense_buffer[512]; /* Sensemode buffer */
struct setparmdsc sensedsc_loop = {sizeof(sense_buffer),sense_buffer};
/*
* MAIN
*/
main(int argc, char *argv[])
{
int i, j; /* Scratch */
int chan; /* Channel assigned */
int status; /* Return status */
/*
* Start a channel.
*/
status = sys$assign(&devdsc,&chan,0,0);
if ($FAIL(status)) exit(status);
status = sys$qiow(0,chan,IO$_SETMODE|IO$M_CTRL|IO$M_STARTUP,&qio_iosb,0,0,0,&setparmdsc_loop,0,0,0,0);
if ($SUCCESS(status)) status = qio_iosb.w_err;
if ($FAIL(status)) {
printf("IOSB addl status = %04X %04X\n",qio_iosb.w_addl,qio_iosb.w_misc);
exit(status);
}
/*
* Issue the SENSEMODE QIO to get our physical address for the loopback message.
*/
status = sys$qiow(0,chan,IO$_SENSEMODE|IO$M_CTRL,&qio_iosb,0,0,0,&sensedsc_loop,0,0,0,0);
if ($SUCCESS(status)) status = qio_iosb.w_err;
if ($FAIL(status)) {
printf("IOSB addl status = %04X %04X\n",qio_iosb.w_addl,qio_iosb.w_misc);
exit(status);
}
/*
* Locate the PHA parameter in the SENSEMODE buffer and copy it into the
* LOOPBACK transmit message. The PHA parameter is a string parameter.
*/
j = 0;
while (j < sizeof(sense_buffer)) {
i = (sense_buffer[j] + (sense_buffer[j+1] << 8));
if (0x1000 & i) {
if ((i & 0xFFF) == NMA$C_PCLI_PHA) {
memcpy(&xmt_buffer[4],&sense_buffer[j+4],6);
break;
}
j += (sense_buffer[j+2] + (sense_buffer[j+3] << 8)) + 4;
} else
j += 6; /* Skip over longword parameter */
}
/*
* Transmit the loopback message.
*/
status = sys$qiow(0,chan,IO$_WRITEVBLK,&qio_iosb,0,0,&xmt_buffer[0],
sizeof(xmt_buffer),0,0,&xmt_param,0);
if ($SUCCESS(status)) status = qio_iosb.w_err;
if ($FAIL(status)) {
printf("IOSB addl status = %04X %04X (on transmit)\n",
qio_iosb.w_addl,qio_iosb.w_misc);
exit(status);
}
/*
* Look for a response. We use the NOW function modifier on the READ so that
* we don't hang here waiting forever if there is no response. If there is no
* response in 1000 receive attempts, we declare no response status.
*/
for (i=0;i<1000;i++) {
status = sys$qio(0,chan,IO$_READVBLK|IO$M_NOW,&qio_iosb,0,0,&rcv_buffer[0],
sizeof(rcv_buffer),0,0,rcv_param,0);
if ($SUCCESS(status)) status = qio_iosb.w_err;
if ($SUCCESS(status)) break;
}
if ($SUCCESS(status))
printf("Successful test\n");
else
printf("No response\n");
}
|
|
|