dld_proto.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Data-Link Driver
*/
#include <sys/sysmacros.h>
#include <sys/dld_impl.h>
static void proto_poll_disable(dld_str_t *);
uint_t);
#define DL_SOLARIS 0x100
/*
*/
typedef struct proto_req_info {
const char *pri_txt;
static proto_req_info_t proto_ri[] = {
proto_req },
proto_req },
proto_req },
proto_req },
proto_req },
};
static proto_req_info_t proto_sri[] = {
};
#define DL_ACK_PENDING(state) \
((state) == DL_ATTACH_PENDING || \
(state) == DL_DETACH_PENDING || \
(state) == DL_BIND_PENDING || \
(state) == DL_UNBIND_PENDING)
/*
* Process a DLPI protocol message. (Only ever called from put(9e)).
*/
void
{
union DL_primitives *udlp;
return;
}
/*
* Select the correct jump table.
*/
if (prim & DL_SOLARIS) {
/*
* Entries in the 'solaris extensions' jump table
* have an extra bit in the primitive value. Clear it
* to do the lookup.
*/
prim &= ~DL_SOLARIS;
/*
* Check the primitive is in range.
*/
if (prim >= PROTO_SRI_COUNT)
goto unsupported;
/*
* Grab the jump table entry.
*/
/*
* OR the cleared bit back in to make the primitive valid
* again.
*/
prim |= DL_SOLARIS;
} else {
/*
* Check the primitive is in range.
*/
if (prim >= PROTO_RI_COUNT)
goto unsupported;
/*
* Grab the jump table entry.
*/
}
/*
* If this primitive causes the data-link channel used by this
* object to become active, then we need to notify dls. Note that
* if we're already passive by having succesfully processed a
* DL_PASSIVE_REQ, then active primitives do not cause us to become
* active.
*/
return;
}
}
/*
* Check whether we need, and whether we have, exclusive access to
* the stream.
*/
if (prip->pri_needexcl) {
/*
* We only have shared access and we need exclusive access.
*/
/*
* Process via qwriter(9f).
*/
return;
}
if (success)
else
}
return;
}
/*
* Called via qwriter(9f).
*/
static void
{
union DL_primitives *udlp;
/*
* Select the correct jump table.
*/
if (prim & DL_SOLARIS) {
/*
* Entries in the 'solaris extensions' jump table
* have an extra bit in the primitive value. Clear it
* to do the lookup.
*/
prim &= ~DL_SOLARIS;
/*
* Grab the jump table entry.
*/
/*
* OR the cleared bit back in to make the primitive valid
* again.
*/
prim |= DL_SOLARIS;
} else {
/*
* Grab the jump table entry.
*/
}
if (success)
else
}
}
/*
* DL_INFO_REQ
*/
/*ARGSUSED*/
static boolean_t
{
return (B_TRUE);
}
/*
* DL_ATTACH_REQ
*/
static boolean_t
{
int err;
return (B_FALSE);
}
return (B_FALSE);
}
return (B_FALSE);
}
return (err == 0);
}
/*
* DL_DETACH_REQ
*/
/*ARGSUSED*/
static boolean_t
{
return (B_FALSE);
}
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* DL_BIND_REQ
*/
static boolean_t
{
int err;
return (B_FALSE);
}
return (B_FALSE);
}
if (dlp->dl_xidtest_flg != 0) {
return (B_FALSE);
}
return (B_FALSE);
}
/*
* Set the receive callback.
*/
/*
* Bind the channel such that it can receive packets.
*/
return (err == 0);
}
/*
* DL_UNBIND_REQ
*/
/*ARGSUSED*/
static boolean_t
{
return (B_FALSE);
}
return (B_FALSE);
}
/*
* Flush any remaining packets scheduled for transmission.
*/
/*
* Reset the M_DATA handler.
*/
/*
* Unbind the channel to stop packets being received.
*/
/*
* Disable polling mode, if it is enabled.
*/
/*
* Clear the receive callback.
*/
/*
* Set the mode back to the default (unitdata).
*/
return (B_TRUE);
}
/*
* DL_PROMISCON_REQ
*/
static boolean_t
{
int err;
return (B_FALSE);
}
return (B_FALSE);
}
case DL_PROMISC_SAP:
break;
case DL_PROMISC_MULTI:
break;
case DL_PROMISC_PHYS:
break;
default:
0);
return (B_FALSE);
}
/*
* Adjust channel promiscuity.
*/
return (err == 0);
}
/*
* DL_PROMISCOFF_REQ
*/
static boolean_t
{
int err;
return (B_FALSE);
}
return (B_FALSE);
}
case DL_PROMISC_SAP:
goto notenab;
break;
case DL_PROMISC_MULTI:
goto notenab;
break;
case DL_PROMISC_PHYS:
goto notenab;
break;
default:
0);
return (B_FALSE);
}
/*
* Adjust channel promiscuity.
*/
return (err == 0);
return (B_FALSE);
}
/*
* DL_ENABMULTI_REQ
*/
static boolean_t
{
int err;
return (B_FALSE);
}
return (B_FALSE);
}
return (err == 0);
}
/*
* DL_DISABMULTI_REQ
*/
static boolean_t
{
int err;
return (B_FALSE);
}
return (B_FALSE);
}
return (err == 0);
}
/*
* DL_PHYS_ADDR_REQ
*/
static boolean_t
{
return (B_FALSE);
}
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* DL_SET_PHYS_ADDR_REQ
*/
static boolean_t
{
int err;
0);
return (B_FALSE);
}
0);
return (B_FALSE);
}
return (err == 0);
}
/*
* DL_UDQOS_REQ
*/
static boolean_t
{
return (B_FALSE);
}
return (B_FALSE);
}
selp->dl_priority < 0) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* DL_CAPABILITY_REQ
*/
/*ARGSUSED*/
static boolean_t
{
0);
return (B_FALSE);
}
return (B_FALSE);
}
/*
* This request is overloaded. If there are no requested capabilities
* then we just want to acknowledge with all the capabilities we
* support. Otherwise we enable the set of capabilities requested.
*/
if (dlp->dl_sub_length == 0) {
return (B_TRUE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* DL_NOTIFY_REQ
*/
static boolean_t
{
0);
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* DL_UINTDATA_REQ
*/
static boolean_t
{
return (B_FALSE);
}
return (B_FALSE);
}
return (B_FALSE);
}
goto badaddr;
/*
* Check the length of the packet and the block types.
*/
size = 0;
goto baddata;
}
goto baddata;
/*
* Build a packet header.
*/
goto badaddr;
/*
* We no longer need the M_PROTO header, so free it.
*/
/*
* Transfer the checksum offload information if it is present.
*/
&flags);
0);
/*
* Link the payload onto the new header.
*/
/*
* If something is already queued then we must queue to avoid
* re-ordering.
*/
return (B_TRUE);
}
/*
* Attempt to transmit the packet.
*/
noenable(q);
}
}
return (B_TRUE);
return (B_FALSE);
return (B_FALSE);
}
/*
* DL_PASSIVE_REQ
*/
/* ARGSUSED */
static boolean_t
{
/*
* If we've already become active by issuing an active primitive,
* then it's too late to try to become passive.
*/
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Catch-all handler.
*/
static boolean_t
{
return (B_FALSE);
}
typedef struct dl_info_ack_wrapper {
#define NEG(x) -(x)
/*
* DL_INFO_ACK
*/
static void
{
/*
* Swap the request message for one large enough to contain the
* wrapper structure defined above.
*/
return;
/*
* Set up the sub-structure pointers.
*/
/*
* This driver supports only version 2 connectionless DLPI provider
* nodes.
*/
/*
* Set the style of the provider from the dld_node_t structure
* representing the dev_t that was opened.
*/
/*
* Set the current DLPI state.
*/
/*
* Gratuitously set the media type. This is because the Cisco VPN 3000
* module assumes that the media type is known prior to DL_ATTACH_REQ
* being completed.
*/
/*
* If the stream is not at least attached then we're done.
*/
goto done;
/*
* Set the media type (properly this time).
*/
/*
* Set the DLSAP length. We only support 16 bit values and they
* appear after the MAC address portion of DLSAP addresses.
*/
sap_length = sizeof (uint16_t);
/*
* Set the minimum and maximum payload sizes.
*/
ASSERT(addr_length != 0);
/*
* Copy in the media broadcast address.
*/
/*
* We only support QoS information for VLAN interfaces.
*/
/*
* Specify the supported range of priorities.
*/
/*
* Specify the current priority (which can be changed by
* the DL_UDQOS_REQ primitive).
*/
} else {
/*
* Shorten the buffer to lose the unused QoS information
* structures. This is to work around a bug in the Cisco VPN
* 3000 module.
*/
}
/*
* The stream is bound. Therefore we can formulate a valid
* DLSAP address.
*/
}
done:
dlp->dl_qos_range_length != 0));
dlp->dl_brdcst_addr_length != 0));
}
/*
*/
static void
{
int dl_err;
if (err != 0)
goto failed;
return;
switch (err) {
case ENOENT:
err = 0;
break;
default:
break;
}
}
/*
* DL_OK_ACK
*/
static void
{
}
/*
*/
static void
{
int dl_err;
if (err != 0)
goto failed;
/*
* Copy in MAC address.
*/
/*
* Copy in the DLSAP.
*/
addr_length += sizeof (uint16_t);
0);
return;
switch (err) {
case EINVAL:
dl_err = DL_BADADDR;
err = 0;
break;
default:
break;
}
}
/*
* DL_OK_ACK
*/
static void
{
}
/*
*/
static void
{
if (err != 0)
goto failed;
return;
}
/*
*/
static void
{
if (err != 0)
goto failed;
return;
}
/*
*/
static void
{
int dl_err;
if (err != 0)
goto failed;
return;
switch (err) {
case EINVAL:
dl_err = DL_BADADDR;
err = 0;
break;
case ENOSPC:
dl_err = DL_TOOMANY;
err = 0;
break;
default:
break;
}
}
/*
*/
static void
{
int dl_err;
if (err != 0)
goto failed;
return;
switch (err) {
case EINVAL:
dl_err = DL_BADADDR;
err = 0;
break;
case ENOENT:
dl_err = DL_NOTENAB;
err = 0;
break;
default:
break;
}
}
/*
* DL_PHYS_ADDR_ACK
*/
static void
{
/*
* Copy in the address.
*/
}
/*
*/
static void
{
int dl_err;
if (err != 0)
goto failed;
return;
switch (err) {
case EINVAL:
dl_err = DL_BADADDR;
err = 0;
break;
default:
break;
}
}
/*
* DL_OK_ACK
*/
static void
{
}
static void
{
if (!dsp->ds_polling)
return;
/*
* It should be impossible to enable raw mode if polling is turned on.
*/
/*
* Reset the resource_add callback.
*/
/*
* Set receive function back to default.
*/
/*
* Note that polling is disabled.
*/
}
static boolean_t
{
/*
* We cannot enable polling if raw mode
* has been enabled.
*/
return (B_FALSE);
/*
* Register resources.
*/
(void *)pollp->poll_rx_handle);
/*
* Set the receive function.
*/
(void *)pollp->poll_rx_handle);
/*
* Note that polling is enabled. This prevents further DLIOCHDRINFO
* ioctls from overwriting the receive function pointer.
*/
return (B_TRUE);
}
/*
*/
static void
{
/*
* Initially assume no capabilities.
*/
subsize = 0;
/*
* Check if polling can be enabled on this interface.
* If advertising DL_CAPAB_POLL has not been explicitly disabled
* then reserve space for that capability.
*/
if (poll_cap) {
subsize += sizeof (dl_capability_sub_t) +
sizeof (dl_capab_poll_t);
}
/*
* If the MAC interface supports checksum offload then reserve
* space for the DL_CAPAB_HCKSUM capability.
*/
subsize += sizeof (dl_capability_sub_t) +
sizeof (dl_capab_hcksum_t);
}
/*
* If DL_CAPAB_ZEROCOPY has not be explicitly disabled then
* reserve space for it.
*/
if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
subsize += sizeof (dl_capability_sub_t) +
sizeof (dl_capab_zerocopy_t);
}
/*
* If there are no capabilities to advertise, send a DL_ERROR_ACK.
*/
if (subsize == 0) {
0);
return;
}
return;
/*
* IP polling interface.
*/
if (poll_cap) {
/*
* Attempt to disable just in case this is a re-negotiation.
*/
ptr += sizeof (dl_capability_sub_t);
ptr += sizeof (dl_capab_poll_t);
}
/*
*/
if (cksum != 0) {
ptr += sizeof (dl_capability_sub_t);
ptr += sizeof (dl_capab_hcksum_t);
}
/*
* Zero copy
*/
if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
ptr += sizeof (dl_capability_sub_t);
ptr += sizeof (dl_capab_zerocopy_t);
}
}
/*
*/
static void
{
/*
* Walk the list of capabilities to be enabled.
*/
DL_BADPRIM, 0);
return;
}
/*
*/
case DL_CAPAB_HCKSUM: {
/*
* Copy for alignment.
*/
break;
}
/*
* IP polling interface.
*/
case DL_CAPAB_POLL: {
/*
* Copy for alignment.
*/
switch (poll.poll_flags) {
default:
/*FALLTHRU*/
case POLL_DISABLE:
break;
case POLL_ENABLE:
/*
* Make sure polling is disabled.
*/
/*
* Now attempt enable it.
*/
break;
break;
}
break;
}
default:
break;
}
}
}
/*
* DL_NOTIFY_ACK
*/
static void
{
/*
* Cache the notifications that are being enabled.
*/
/*
* The ACK carries all notifications regardless of which set is
* being enabled.
*/
/*
* Solicit DL_NOTIFY_IND messages for each enabled notification.
*/
if (dsp->ds_notifications != 0)
}