The Connection Management Module (CMM) provides
an interface that allows any ATM module to exchange configuration and management
information with application processes without the usual need for kernel modifications
and new
/dev
nodes.
The Module Management Interface (MMI)
is the standard operating system
ioctl
interface, but it
allows applications to communicate with specific ATM modules directly through
the CMM.
See
ioctl
(2)
for more information.
To exchange information with any ATM module, applications must open
the
/dev/atm_cmm
device and issue
ioctl
system calls.
The
ioctl
commands are executed either by
the CMM directly or passed to a selected ATM module.
The ATM module transfers
all data associated with the
ioctl
commands to and from
user space; the MMI always has a user context since it is executed as part
of a system call.
New ATM modules can define their own
ioctl
commands
independently since commands are routed only to a module selected by using
an
ioctl
call.
Modules can also define their own structures
and protocols for exchanging data with applications since interpretation of
the
ioctl
data argument is done by agreement between the
module and its application, not by the CMM.
Applications cannot send the CMM any commands other than those commands for establishing MMI paths. Only applications that Compaq has written to manage the ATM subsystem can select the CMM as the target for commands. Also, a module can restrict the establishment of an MMI path through the use of key values that are known only to the module and applications that are allowed to communicate with it. This prevents applications from illegally communicating with ATM modules.
This chapter describes the following:
How to create an MMI command path
How to verify the version of the
ioctl
commands
How to define new MMI
ioctl
commands
The MMI calling conventions
Device driver, signaling, and convergence module interfaces
To send
ioctl
commands to an ATM
module, you must create a path through the CMM to the module.
The following
code fragment shows a routine that creates an MMI path:
#include <sys/atm.h> make_mmi_path(char *name) { int atm_fd; struct atm_mmi_path path; [1] atm_fd = open("/dev/atm_cmm",O_RDWR); [2] if(atm_fd == -1) { perror("open of /dev/atm_cmm"); exit(errno); } path.name = name; path.length = strlen(name); path.key = 0x123456789abcdef; if(ioctl(atm_fd,GIOC_MMI_PATH,&path) == -1) [3] { perror("GIOC_MMI_PATH"); exit(errno); } return atm_fd; }
Declares the
atm_mmi_path
structure.
[Return to example]
Opens the
/dev/atm_cmm
device.
[Return to example]
Issues the
ioctl
call with the
GIOC_MMI_PATH
command.
The argument to the
GIOC_MMI_PATH
command is the name of the module to which the path is to be established;
each module must register with a unique name.
[Return to example]
After the path is created, all subsequent
ioctl
commands
not understood by the CMM are sent to the selected module.
The
/dev/atm_cmm
device has the following restrictions:
You can use this device only for the management and administration of ATM modules, not for transferring data across the network.
Only one application can have the device opened at any time. Multiple accesses to this interface are not permitted.
Only applications with root permissions can open the device.
Since all ATM modules, including the CMM, share a common interface,
an application can inadvertently or deliberately issue an incorrect or damaging
ioctl
call.
To prevent this from occurring, applications can identify
themselves to ATM modules when the MMI path is created so their privilege
to contact the module can be confirmed.
You are not required to implement
this in your module, but you should for added safety.
The application performs extra validation by passing a 64-bit key to the ATM module when the MMI path is created. The ATM module checks this key to verify that it is valid. Since only applications written specifically to communicate with certain modules know the key the module expects, it is more difficult for another module to create the MMI path to the ATM module.
Table 7-1
lists member names of the
atm_mmi_path
structure, with their associated data types, that modules might
reference.
Table 7-1: The atm_mmi_path Structure Members
Member Name | Data Type |
*name |
char |
length |
int |
key |
long |
The
name
member is a pointer to the name of the ATM
module to which the MMI path is to be established.
This name is a standard
NULL-terminated ASCII string that must exactly match the string the module
used when it registered with the CMM.
The
length
member is the length (in bytes) of the
string pointed to by the name member.
This length does not include the NULL
termination.
The
key
member is a value that the application and
the target ATM module agree to use to identify the application to the ATM
module.
Only target ATM modules use this member.
7.2 Verifying the ioctl Version
To verify that the application and the ATM module
agree on the
ioctl
definitions in use, you can use the
global
GIOC_MMI_GETVERSION
command in the application.
This allows the application to provide backward compatibility when changes
in its
ioctl
interface are needed.
The following code fragment
shows how to query a module for its version.
#define VERSION_1 1 #define VERSION_CURRENT 2 get_mmi_version(int atm_fd) { struct atm_mmi_version v; [1] if(ioctl(atm_fd, GIOC_MMI_GETVERSION, &v) == -1) { [2] perror("GIOC_MMI_GETVERSION); return; } switch(v.version) { case VERSION_1: /* Talk to module using old ioctls */
.
.
.
break; case VERSION_CURRENT: /* Talk to module using current ioctls */
.
.
.
break; } }
Declares an
atm_mmi_version
structure.
The
structure contains only a
version
member of the data type
int
.
The values used for MMI versions are agreed upon between the
module and its application.
The CMM does not look at the values passed in
this structure.
[Return to example]
Queries the module for its version.
atm_fd
is associated with an open MMI path that was created in
Section 7.1.
[Return to example]
All MMI
ioctl
commands are in
the "g"
ioctl
group and are named
GIOC_command_name
.
Each
ioctl
command group can contain up to 256 commands; each
ioctl
command encodes the group, the command within the group, the data
transfer direction, and the size of the data to transfer.
The GIOC group
is divided into CMM-specific commands (with a range of 0 to 127, inclusive)
and module commands (with a range of 128 to 255, inclusive).
The CMM does
not interpret commands in the module command range.
Also, modules are not
passed commands in the CMM command range.
As a rule, the module and application program must agree on the command
number and the format of the command data passed as the third argument to
the ATM
ioctl
system calls for a module.
You do this with
a module-specific header file in which the commands and structures are defined.
This header file should include
sys/ioctl.h
, which contains
the macros used to define
ioctl
commands.
To define a new
ioctl
command, you need the following
pieces of information:
The direction of any data transfer between the application and the ATM module (input from the application, output to the application, or both). This determines which macro to use for command definition (_IOR, _IOW, or _IORW).
The definition of the data structures to be passed between
the application and the ATM module as the argument to the command.
This, along
with the transfer direction information, controls how much data the kernel
will move between user space and the kernel when the
ioctl
is processed.
The number of the command (between 128 and 255).
Once you know this information, you can define a new
ioctl
command.
For example, suppose an application needs to pass information
contained in a single longword and receive information from the ATM module
in the same word.
You would define the command as follows:
#define GIOC_NEW_CMD _IOWR('g',128,sizeof(long))
Note that the "g" must be in lowercase.
Using this example, the application executes the following call to send the new command to the ATM module:
long arg = some_value; int atm_fd; atm_fd = make_mmi_path("module name"); if(ioctl(atm_fd, GIOC_NEW_CMD, &arg) == -1) { perror("GIOC_NEW_CMD"); exit(errno); } printf("GIOC_NEW_CMD returned %ld0", arg);
An
ioctl
system call can copy only fixed-size data directly addressed by
the argument.
If a command requires the exchange of variable size data, the
argument to the
ioctl
system call must be a fixed size
structure that contains pointers to and lengths of variable size data in the
application's memory space.
The ATM module is responsible for copying data
from or to this memory when processing the command; the kernel
ioctl
call copies the contents of the structure.
7.4 Using MMI Calling Conventions
All modules that provide an MMI routine must adhere to the following rules when handling arguments from the CMM:
All MMI routines are called while in a system call context with no external locks held. This means that the MMI routines can block, if necessary, provided they do not hold simple locks while blocking.
All MMI routines must return
ESUCCESS
to
indicate successful completion of the operation or a error number to indicate
the type of error that occurred.
MMI modules can use the
retval
pointer to provide a nonzero return value to the calling program.
This value
is the return value from the
ioctl
when the MMI function
returns
ESUCCESS
to the CMM.
This follows the normal Tru64 UNIX
ioctl
processing conventions.
MMI routines are required to process only their own commands and
one global command: the
GIOC_MMI_PATH
command.
This command
instructs the MMI function to verify that it is willing to accept the establishment
of an MMI path from the CMM as requested by an application program.
The argument
to this command is a pointer to an
atm_mmi_path
structure
that the MMI function will evaluate.
Convergence modules can optionally process the
GIOC_MMI_GETVERSION
global command.
This enables the application to verify that it
and the ATM module implement the same
ioctl
interface.
The MMI routine should verify that the key provided in the
atm_mmi_path
structure is correct, but might also verify the specified
module name.
This is redundant since the CMM already verifies the module
name.
If the key or module name provided is acceptable, the MMI function returns
ESUCCESS
, otherwise, it returns
ENXIO
.
The MMI function is informed only when MMI paths are established, not when they are destroyed.
See
Appendix A
for information on the
xxx_mmi
function.
7.5 Using the Device Driver MMI
When an ATM device driver registers with the CMM, it provides the CMM with the address of the following management functions:
The internal management function that the CMM uses to manage driver resources and VCs. Only the CMM uses this interface; it is not available through the MMI. This function is not allowed to block at any time.
The
xxx_mmi
function.
This function receives only MMI commands through the
ioctl
system call from an application that has been written specifically
to manage the device driver.
The standard ATM interface defines no generic driver management through
the MMI.
If a device driver does not need to process MMI commands, it should
set this argument in the
atm_cmm_register_dd
routine to NULL.
The device driver's MMI function is passed the following arguments when called:
The device driver's module handle, which the device driver module provided the CMM at registration time
The
ioctl
command and data value
The MMI function is permitted to block, if necessary, at any time and
has access to the user context of the calling application.
7.6 Using the Signaling Module MMI
The signaling module MMI is similar to the convergence module and device driver MMIs. The signaling module is passed the following arguments when called:
The signaling module handle, which the signaling module provided the CMM at registration time. The signaling module can use this value in any way it chooses. The CMM does not modify this value.
The
ioctl
command and data value.
7.7 Using the Convergence Module MMI
When a convergence module registers with the CMM, it can supply the address of an MMI function to be called when an application creates an MMI path to the convergence module. If a convergence module does not provide an MMI management function, the module writer should register an address of NULL for the MMI management function when the convergence module registers with the CMM.
The convergence module MMI function is passed the following arguments when called:
The convergence module's internal handle, which the convergence module provided to the CMM at registration time. This value is internal to the convergence module; the CMM does not modify this value.
The
ioctl
command and data value.