Use muxAddrResFuncAdd( ) to register an address resolution function for an interface-type/protocol pair. You must call muxAddrResFuncAdd( ) before calling the protocol's protocolAttach( ) routine. If the driver registers itself as an Ethernet driver, you do not need to call muxAddrResFuncAdd( ) because VxWorks automatically assigns arpresolve( ) to registered Ethernet devices.
STATUS muxAddrResFuncAdd
(
long ifType, /* interface type from m2Lib.h, or driver type */
long protocol, /* protocol from RFC 1700, or service type */
FUNCPTR addrResFunc /* the function being added */
)
|
|
|||||||||||||||||||
int xxxResolvRtn
(
FUNCPTR ipArpCallBackRtn,
struct mbuf * pMbuf,
struct sockaddr * dstIpAddr,
struct ifnet * ifp,
struct rtentry * rt,
char * dstBuff
)
In addition, your xxxResolvRtn( ) must return one upon success, which indicates that dstIpAddr has been updated with the necessary data-link layer information and that the IP sublayer output function can transmit the packet.
Your xxxResolvRtn( ) must return zero if it cannot resolve the address immediately. In the default arpresolve( ) implementation, resolving the address immediately means arpresolve( ) was able to find the address in its table of results from previous ARP requests. Returning zero indicates that the table did not contain the information but that the packet has been stored and that an ARP request has been queued.
If the ARP request times out, the packet is dropped. If the ARP request completes successfully, processing that event updates the local ARP table and resubmits the packet to the IP sublayer's output function for transmission. This time, the arpresolve( ) call will return one.
What is essential to note here is that arpresolve( ) did not wait for the ARP request to complete before returning. If you replace the default arpresolve( ) function, you must make sure your function returns as soon as possible and that it never blocks. Otherwise, you block the IP sublayer from transmitting other packets out through the interface for which this packet was queued. You must also make sure that your arpresolve( ) function takes responsibility for the packet if it returns zero.
An address resolution function designed for use with the VxWorks IP sublayer implementation must conform strictly to expectations of that sublayer. The function that you register with muxAddrResFuncAdd( ) must be of the form:
int xxxResolvRtn
(
FUNCPTR aCallBackRtn,
struct mbuf * pMbuf,
struct sockaddr * dstIpAddr,
struct ifnet * ifp,
struct rtentry * rt,
char * dstBuff
)
In addition, your xxxResolvRtn( ) must not block, and it must return with a function value of zero or one, where one indicates desIpAddr contains the resolved address and zero indicates that it does not. If your address resolution function returns a zero, it should take responsibility for the packet.
Within your xxxResolvRtn( ), you will likely implement an address resolution table or some equally speedy mechanism that lets you reuse address resolution information discovered previously. If your speedy address resolution mechanism fails, you should queue the work to an address resolution protocol and return zero. As a prototype for your function that queues the work, consider:
int resolveIPaddress
(
FUNCPTR pCallback, /* a retransmit callback function */
M_BLK_ID pIPPacket, /* the IP packet */
struct sockaddr pIPAddress, /* the IP address */
void * passthru1, /* reserved for internal use */
void * passthru2 /* reserved for internal use */
char * pBuffer, /* pre-allocated, up to 128 bytes */
)
This function would supply the address resolution protocol with the information needed to perform the address resolution as well as the packet destined for that address. If the address resolution succeeds, the function would add that information to its table (or equivalent), and then use pCallback to submit the packet (with its original parameters) to the IP layer output function for transmission. This time, your xxxResolvRtn( ) replacement function should be able to return with the address resolution information.
Use muxAddrResFuncDel( ) to undo the assignment of an address resolution function to an interface-type/protocol pair.
STATUS muxAddrResFuncDel
(
long ifType, /* media interface type from m2Lib.h */
long protocol, /* protocol type, for instance from RFC 1700 */
)
Use muxAddrResFuncGet( ) to retrieve a pointer to the address resolution function registered to the specified interface-type/protocol pair.
FUNCPTR muxAddrResFuncGet
(
long ifType, /* interface type from m2Lib.h, or driver type*/
long protocol /* protocol from RFC 1700, or service type */
)
Use muxAddressForm( ) to form a frame with a link-layer address. A network service needs this function when working with ENDs, which are frame-oriented, but not with NPT drivers, which are packet oriented.
When given the source and destination addressing information (through pSrcAddr and pDstAddr), this function returns an mBlk that points to an assembled link-level header, and prepends this header to the mBlk chain pointed to by pMblk. Note that the pDstAddr.mBlkHdr.reserved field should be set to the network protocol type.
M_BLK_ID muxAddressForm
(
void * pCookie, /* the cookie returned by muxBind() */
M_BLK_ID pMblk, /* pointer to the packet being reformed */
M_BLK_ID pSrcAddr, /* pointer to the mBlk with the source address */
M_BLK_ID pDstAddr, /* pointer to the mBlk with the dest address */
)
You can use muxBind( ) to bind a network service to an END. However, it is often better to use muxTkBind( ), which works with both ENDs and NPT drivers.
void * muxBind
(
char * pName, /* interface name, for example, ln, ei,... */
int unit, /* unit number */
BOOL (* stackENDRcvRtn)(void *, long, M_BLK_ID, LL_HDR_INFO *, void *),
STATUS (* stackENDShutdownRtn)(void *, void *),
STATUS (* stackENDRestartRtn)(void *, void *),
void (* stackENDErrorRtn)(END_OBJ *, END_ERR *, void *),
long type, /* protocol type, from RFC1700 or user-defined */
char * pProtoName, /* string name for protocol */
void * pSpare /* identifies the binding instance */
)
Use muxDevExists( ) to test whether a given device has already been loaded into the network stack. As input, it expects the name and unit number of the device to be tested.
BOOL muxDevExists
(
char * pName, /* string containing a device name (ln, ei, ...)*/
int unit /* unit number */
)
Use muxDevLoad( ) to load a network driver into the MUX. Internally, muxDevLoad( ) calls the driver's endLoad( ) or nptLoad( ). After the device is loaded, you must call muxDevStart( ) to start the device.
The pInitString argument passes directly into the endLoad( ) or nptLoad( ) function. Likewise, the pBSP argument is passed along to the driver, which may or may not use it. This argument can be used to pass in tables of BSP-specific functions that the driver can use.
void * muxDevLoad
(
int unit, /* unit number of device */
END_OBJ * (* endLoad)(char *, void *), /* driver's load function */
char * pInitString, /* init string for driver */
BOOL loaning, /* unused */
void * pBSP /* BSP-specific */
)
Use muxDevStart( ) to start a device after you have successfully loaded the device using muxDevLoad( ). Internally, muxDevStart( ) activates the network interfaces for a device by calling the drivers endStart( ) routine.
STATUS muxDevStart
(
void * pCookie /* the cookie returned from muxDevLoad() */
)
Use muxDevStop( ) to stop the specified driver. Internally, muxDevStop( ) calls the endStop( ) or nptStop( ) routine registered for the driver.
STATUS muxDevStop
(
void * pCookie /* the cookie returned from muxDevLoad() */
)
Use muxDevUnload( ) to unload a device from the MUX. Unloading a device closes any network connections made through the device.
To notify protocols that the device is unloading, muxDevUnload( ) calls the stackShutdownRtn( ) function for each protocol bound to the device (internally, the stackShutdownRtn( ) should call muxUnbind( ) to detach from the device).
To free device-internal resources, muxDevUnload( ) calls the endUnload( ) or nptUnload( ) function that the device registered with the MUX.
STATUS muxDevUnload
(
char * pName, /* the name of the device, for example, ln or ei */
int unit /* the unit number */
)
Drivers use muxError( ) to report an error to a network service that is bound to it through the MUX. You can find predefined errors in end.h. This function is passed two arguments: the END object that identifies the device that is issuing the error and a pointer to an END_ERR structure (see B.3.2 END_ERR, p.287).
void muxError
(
void * pEnd, /* END object pointer returned by end/nptLoad() */
END_ERR * pError /* error structure */
}
Use muxIoctl( ) to access the ioctl services that network interfaces have registered with the MUX. Typical uses of muxIoctl( ) include starting, stopping, or resetting a network interface, or adding or configuring MAC and network addresses.
STATUS muxIoctl
(
void * pCookie, /* returned by muxTkBind() */
int cmd, /* ioctl command */
caddr_t data /* data needed to carry out the command */
)
Use muxMCastAddrAdd( ) to add an address to the table of multicast addresses maintained for a device. It expects two arguments: a cookie that was returned when muxTkBind( ) was used to bind to the device, and a string containing the address to be added.
STATUS muxMCastAddrAdd
(
void * pCookie, /* returned by muxTkBind() */
char * pAddress /* address to add to the table */
)
Use muxMCastAddrDel( ) to remove an address from the table of multicast addresses maintained for a device. It expects two arguments: a cookie that was returned when muxTkBind( ) was used to bind to the device, and a string containing the address to be removed.
STATUS muxMCastAddrDel
(
void * pCookie, /* returned by muxTkBind() */
char * pAddress /* address to delete from the table */
)
This function returns OK , if successful; ERROR, if the device was unable to successfully remove the address (if this is because the device does not support multicasting, errno will be set to ENOTSUP, if this is because the address was not found in the table, errno will be set to EINVAL); ENETDOWN, if the cookie does not represent a valid device.
Use muxMCastAddrGet( ) to retrieve the list of multicast addresses that have been registered for a driver. It expects two arguments: a cookie that was returned when muxTkBind( ) was used to bind to the device, and a pointer to a pre-allocated MULTI_TABLE structure into which the table contents will be written during this function call (see B.3.8 MULTI_TABLE, p.294).
int muxMCastAddrGet
(
void * pCookie, /* returned by muxTkBind() */
MULTI_TABLE * pTable /* structure that will hold retrieved table */
)
Use muxTkBind( ) to bind a network service to a network interface. Before the network service can send and receive packets from the network, it must bind to one or more network drivers through which the packets will be sent and received. To specify these network drivers and bind to them, use the function muxTkBind( ).
In the call to muxTkBind( ) you must provide the following information:
These callback functions are listed in Table B-1 and are described at greater length in 11.3.1 Service Functions Registered Using muxTkBind( ), p.231.
|
|
|||||||||||||||||||
|
|
|||||||||||||||||||
|
|
|||||||||||||||||||
Two additional arguments (pNetSvcInfo and pNetDrvInfo) allow the sublayer to exchange additional information with the network driver, depending on requirements specific to the particular service or driver. The Wind River IP network protocol, for instance, expects a driver to pass up certain information, although it does not pass anything back down. These additional arguments may be especially helpful to those network services and network driver types that are naturally "tightly coupled."
As part of the bind phase, the network service typically retrieve the address resolution and mapping functions for each network interface that is being bound to, storing them in a private data structure allocated by the service.
The muxTkBind( ) function returns a cookie that uniquely represents the binding instance and is used to identify that binding instance in subsequent calls. A return value of NULL indicates that the bind failed.
void * muxTkBind
(
char * pName, /* interface name, for example: ln, ei */
int unit, /* unit number */
BOOL (* stackRcvRtn)(void *, long, M_BLK_ID, void *),
STATUS (* stackShutdownRtn)(void *),
STATUS (* stackRestartRtn)(void *),
void (* stackErrorRtn)(void *, END_ERR *),
long type, /* from RFC1700 or user-defined */
char * pProtoName, /* string name of service */
void * pNetCallBackId, /* returned to svc sublayer during recv */
void * pNetSvcInfo, /* ref to netSrvInfo structure */
void * pNetDrvInfo /* ref to netDrvInfo structure */
)
|
|
|||||||||||||||||||
int muxTkDrvCheck
(
char * pDevName /* the name of the device being checked */
)
A network service sublayer uses muxTkPollReceive( ) to poll a device for incoming data. If no data is available at the time of the call, muxTkPollReceive( ) returns EAGAIN. The pSpare argument points to any optional spare data provided by an NPT driver. In the case of an END, pSpare will always be NULL or point to NULL.
STATUS muxTkPollReceive
(
void * pCookie, /* returned by muxTkBind() */
M_BLK_ID pNBuff, /* a vector of buffers passed to us */
void * pSpare /* a reference to spare data is returned here */
)
Use muxTkPollSend( )is to transmit packets when a driver is in polled-mode. This is the polled-mode equivalent to the interrupt-mode muxTkSend( ). When using muxTkPollSend( ), the driver does not need to call muxAddressForm( ) to complete the packet, nor does it need to prepend an mBlk of type MF_IFADDR containing the destination address. Like muxTkSend( ), this function expects as arguments a cookie identifying the device and a pointer to the mBlk chain containing the data.
STATUS muxTkPollSend
(
void * pCookie, /* returned by muxTkBind()*/
M_BLK_ID pNBuff, /* data to be sent */
char * dstMacAddr, /* destination MAC address */
USHORT netType, /* network service that is calling us */
void * pSpareData /* spare data passed to driver on each send */
)
A driver uses muxTkReceive( ) to pass validated packets up to the MUX.1
The muxTkReceive( ) function forwards the data to the network service sublayer by calling the stackRcvRtn( ) registered for that sublayer.
The MUX strips off the frame header before forwarding the packet to the network service, unless the network service is registered as MUX_PROTO_SNARF or MUX_PROTO_PROMISC, in which case it will receive the complete frame.
STATUS muxTkReceive
(
END_OBJ * pEnd, /* returned by nptLoad() */
M_BLK_ID pMblk, /* the buffer being received */
long netSvcOffset, /* offset to network datagram in the packet */
long netSvcType, /* network service type */
BOOL wrongDstAddr, /* not addressed to this interface */
void * pSpareData /* out-of-band data */
)
STATUS muxTkSend
(
void * pCookie, /* returned by muxTkBind()*/
M_BLK_ID pNBuff, /* data to be sent */
char * dstMacAddr, /* destination MAC address */
USHORT netType, /* network service that is calling us */
void * pSpareData /* spare data passed on each send */
)
The data to be sent should be formed into an mBlk chain (if it is not already in this form). If the sublayer has a registered address resolution function for the service/device interface, it should call this function to determine the destination physical-layer address.
The network service may send fully formed physical layer frames to the device. For an END, this is the required and default behavior, but when sending to a device that uses an NPT driver this requires that you set the M_L2HDR flag in the mBlk header.
The muxTkSend( ) routine may return an error indicating that the driver is out of resources for transmitting the packet. You can use this error to establish a flow control mechanism if desired. The sublayer typically waits to send any more packets until the MUX calls the stackRestartRtn( ) callback function.
This function returns OK, if successful; END_ERR_BLOCK, if the send( ) routine of the driver is temporarily unable to complete the send due to insufficient resources or some other problem; ERROR, if the send( ) routine of the driver fails; or ENETDOWN, if the cookie does not represent a valid device.
A network interface driver uses muxTxRestart( ) to tell a network service that it may resume sending data. That network service is presumed to have paused itself in response to an error returned from a muxTkSend( ) call. A driver can use muxTxRestart( ) to implement flow control.
void muxTxRestart
(
END_OBJ * pEnd /* returned by endLoad() or nptLoad() */
)
A network service uses muxUnbind( ) to disconnect from a device. As input, muxUnbind( ) expects a cookie that identifies the device, the driver type that was passed during the bind, and a pointer to the stack*RcvRtn( ) registered at bind-time.
STATUS muxUnbind
(
void * pCookie, /* returned from muxTkBind() */
long type, /* the device type passed in at bind-time */
FUNCPTR stackRcvRtn /* pointer to the service receive routine */
)
The MUX uses the DEV_OBJ structure to store the name and control structure of your device. The private control structure, held in the pDevice member of this structure, stores information such as memory pool addresses and other essential data. The DEV_OBJ structure is defined in end.h as:
typedef struct dev_obj
{
char name[END_NAME_MAX]; /* device name */
int unit; /* for multiple units */
char description[END_DESC_MAX]; /* text description */
void * pDevice; /* device control structure */
} DEV_OBJ;
typedef struct end_err
{
INT32 errCode; /* Error code */
char * pMesg; /* NULL-terminated error message */
void * pSpare; /* Pointer to user-defined data */
} END_ERR;
The errCode member of the END_ERR structure is 32 bits long. The lower 16 bits are reserved for system error messages, while the upper 16 bits may be used for custom error messages. Table B-2 lists currently defined error codes:
|
|
|||||||||||||||||||
|
|
|||||||||||||||||||
|
|
|||||||||||||||||||
END_OBJ is the head of the structural interface between the MUX and a network interface driver. The driver allocates this structure and initializes some of its elements within its endLoad( ) or nptLoad( ) function. The structure is defined in target/h/end.h and is diagramed in Figure B-1.
The MUX manages some of the elements in this structure, but the driver is responsible for setting and managing others:
STATUS receiveRtn
(
void * pCookie, /* The cookie passed in to endLoad() */
M_BLK_ID pMblk /* The packet, as an mblk chain */
)
|
|
|||||||||||||||||||
typedef struct
{
int query; /* the query */
int queryLen; /* length of expected/returned data */
char queryData[4]; /* 4 byte minimum; 120 byte maximum */
} END_QUERY;
The MUX uses the LL_HDR_INFO structure to keep track of link-level header information associated with packets passed from an END to the MUX and from there up to a protocol. An LL_HDR_INFO structure is passed as an argument to an END's stack receive routine.
typedef struct llHdrInfo
{
int destAddrOffset; /* destination address offset into mBlk */
int destSize; /* size of destination address */
int srcAddrOffset; /* source address offset into mBlk */
int srcSize; /* size of source address */
int ctrlAddrOffset; /* control info offset into mBlk */
int ctrlSize; /* size of control info */
int pktType; /* type of the packet */
int dataOffset; /* offset into mBlk where data starts */
} LL_HDR_INFO;
The M2_INTERFACETBL is still part of the END_OBJ structure for the purpose of backwards-compatibility, but a new structure, the M2_ID structure, has been added that encompasses and enhances the M2_INTERFACETBL structure.
The M2_ID structure referenced in the END_OBJ includes the elements that were found in the M2_INTERFACETBL structure, and extends this with additional elements from RFC 2233 (see Figure B-2).
Use mBlk structures as a vehicle for passing packets between the driver and protocol layers. The mBlk structure is defined in netBufLib.h as:
typedef struct mBlk
{
M_BLK_HDR mBlkHdr; /* block header, pointer to mHdr structure */
M_PKT_HDR mBlkPktHdr; /* packet header, pointer to pktHdr structure */
CL_BLK * pClBlk; /* pointer to cluster block */
} M_BLK;
typedef struct multi_table
{
long len; /* length of table, in bytes */
char * pTable; /* pointer to entries */
} MULTI_TABLE;
The MUX uses this structure to reference the functions implemented for a driver. The NET_FUNCS structure is defined as:
typedef struct net_funcs
{
STATUS (* start)(void *);
STATUS (* stop)(void *);
STATUS (* unload)(void *);
int (* ioctl)(void *, int, caddr_t);
STATUS (* send)(void *, M_BLK_ID);
STATUS (* mCastAddrAdd)(void *, char*);
STATUS (* mCastAddrDel)(void *, char*);
STATUS (* mCastAddrGet)(void *, MULTI_TABLE*);
STATUS (* pollSend)(void *, M_BLK_ID);
STATUS (* pollRcv)(void *, M_BLK_ID);
M_BLK_ID (* formAddress)(M_BLK_ID, M_BLK_ID, M_BLK_ID, BOOL );
STATUS (* packetDataGet)(M_BLK_ID, LL_HDR_INFO *);
STATUS (* addrGet)(M_BLK_ID, M_BLK_ID, M_BLK_ID, M_BLK_ID, M_BLK_ID);
int (* endBind)(void *, void *, void *, long );
} NET_FUNCS;
The driver functions referred to in this structure are described in greater detail elsewhere (see NPT Driver Entry Points Exported to the MUX, p.209 and END Entry Points Exported to the MUX, p.195).
1: This function is registered by the MUX as the receiveRtn in the END_OBJ data structure for the device. The driver should make a call to this reference rather than calling muxTkReceive( ) directly.
2: Typically, this value can be found in the header of the received frame.