/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/priv_names.h>
#include <inet/proto_set.h>
#include <inet/ipclassifier.h>
#define RDS_DEVMINOR 0
#define RDS_DPRINTF2 0 &&
typedef struct rdsahdr_s {
} rdsha_t;
int rdsdebug;
/* Hint not protected by any lock */
/* global configuration variables */
int rds_open_transport_driver();
int rds_close_transport_driver();
#define RDS_CURRENT_PORT_QUOTA() \
static int
{
int ret;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
rds_dev_info = devi;
RDS_DEVMINOR, DDI_PSEUDO, 0);
if (ret != DDI_SUCCESS) {
return (ret);
}
return (DDI_SUCCESS);
}
static int
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
if (rds_dev_info != NULL) {
*result = (void *)rds_dev_info;
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
error = DDI_SUCCESS;
break;
default:
break;
}
return (error);
}
/*ARGSUSED*/
static int
{
int ret;
if (is_system_labeled()) {
/*
* RDS socket is not supported on labeled systems
*/
return (ESOCKTNOSUPPORT);
}
/* Open the transport driver if IB HW is present */
if (rds_transport_handle == NULL) {
if (ret != 0) {
/* Transport driver failed to load */
return (ret);
}
}
return (EINVAL);
}
/* Reopen not supported */
return (0);
}
return (0);
}
q->q_hiwat = rds_recv_hiwat;
q->q_lowat = rds_recv_lowat;
qprocson(q);
/* Set the Stream head watermarks */
return (0);
}
static int
{
qprocsoff(q);
/*
* NPORT should be decremented only if this socket was previously
* bound to an RDS port.
*/
}
/* close the transport driver if this is the last socket */
if (RDS_GET_NPORT() == 1) {
(void) rds_close_transport_driver();
}
/*
* We set the flags without holding a lock as this is
* just a hint for the fanout lookup to skip this rds.
* We dont free the struct until it's out of the hash and
* the ref count goes down.
*/
}
return (0);
}
/*
* Add a new message to the socket
*/
int
{
int error = 0;
return (error);
}
/* Allocate a message block for the T_UNITDATA_IND structure. */
return (ENOMEM);
}
/* check port quota */
if (RDS_GET_RXPKTS_PEND() > rds_rx_pkts_pending_hwm) {
/* this may result in stalling the port */
}
}
/*
* canputnext() check is done after putnext as the protocol does
* not allow dropping any received packet.
*/
}
return (error);
}
/* Default structure copied into T_INFO_ACK messages */
65535, /* TSDU_size. Excl. headers */
T_INVALID, /* ETSU_size. rds does not support expedited data. */
T_INVALID, /* CDATA_size. rds does not support connect data. */
T_INVALID, /* DDATA_size. rds does not support disconnect data. */
sizeof (sin_t), /* ADDR_size. */
0, /* OPT_size - not initialized here */
65535, /* TIDU_size. Excl. headers */
T_CLTS, /* SERV_type. rds supports connection-less. */
TS_UNBND, /* CURRENT_state. This is set from rds_state. */
};
static in_port_t
{
if (port < rds_smallest_port)
return (port);
}
/* This routine creates a T_ERROR_ACK message and passes it upstream. */
static void
{
}
static void
{
return;
}
}
static void
{
/* Create a T_INFO_ACK message. */
return;
}
/*
* NO locking protection here as sockfs will only send down
* one bind operation at a time.
*/
static void
{
int count;
return;
}
/*
* We don't allow multiple binds
*/
return;
}
switch (tbr->ADDR_length) {
case sizeof (sin_t): /* Complete IPv4 address */
sizeof (sin_t));
return;
}
return;
}
return;
}
/*
* verify that the address is hosted on IB
* only exception is the loopback address.
*/
return;
}
break;
default: /* Invalid request */
return;
}
/*
* TPI only sends down T_BIND_REQ for AF_INET and AF_INET6
* since RDS socket is of type AF_INET_OFFLOAD a O_T_BIND_REQ
* will be sent down. Treat O_T_BIND_REQ as T_BIND_REQ
*/
if (requested_port == 0) {
/*
* If the application passed in zero for the port number, it
* doesn't care which port number we bind to. Get one in the
* valid range.
*/
}
count = 0;
for (;;) {
/*
* Walk through the list of rds streams bound to
* requested port with the same IP address.
*/
continue;
break;
}
/*
* No other stream has this IP address
* and port number. We can use it.
*/
break;
}
if (requested_port != 0) {
/*
* We get here only when requested port
* is bound (and only first of the for()
* loop iteration).
*
* The semantics of this bind request
* require it to fail so we return from
* the routine (and exit the loop).
*
*/
return;
}
/*
* We've tried every possible port number and
* there are none available, so send an error
* to the user.
*/
return;
}
}
/*
* Copy the source address into our rds structure.
*/
/*
* reset the next port if we choose the port
*/
if (requested_port == 0) {
}
/* Reset the message type in preparation for shipping it back. */
/* Increment the number of ports and set the port quota */
}
static void
{
case M_DATA:
/* Not connected */
return;
case M_PROTO:
case M_PCPROTO:
sizeof (t_scalar_t)) {
return;
}
case T_CAPABILITY_REQ:
rds_capability_req(q, mp);
return;
case T_INFO_REQ:
rds_info_req(q, mp);
return;
case O_T_BIND_REQ:
case T_BIND_REQ:
return;
case T_SVR4_OPTMGMT_REQ:
case T_OPTMGMT_REQ:
/*
* All Solaris components should pass a db_credp
* for this TPI message, hence we ASSERT.
* But in case there is some other M_PROTO that looks
* like a TPI message sent by some other kernel
* component, we check and return an error.
*/
return;
}
} else {
}
return;
case T_CONN_REQ:
/*
* We should not receive T_CONN_REQ as sockfs only
* and type == SOCK_DGRAM/SOCK_RAW. For all others
* it simply calls soisconnected. see sotpi_connect()
* for details.
*/
/* FALLTHRU */
default:
}
break;
case M_FLUSH:
break;
case M_IOCTL:
break;
case M_IOCDATA:
/* IOCTL continuation following copyin or copyout. */
/*
* The copy operation failed. mi_copy_state already
* cleaned up, so we're out of here.
*/
return;
}
/*
* If we just completed a copy in, continue processing
* in rds_ioctl_copyin_done. If it was a copy out, we call
* mi_copyout again. If there is nothing more to copy out,
* it will complete the IOCTL.
*/
rds_ioctl_copyin_done(q, mp);
else
mi_copyout(q, mp);
return;
default:
}
}
static int
{
case M_PROTO:
case M_PCPROTO:
sizeof (struct T_unitdata_req)) {
== T_UNITDATA_REQ) {
/*
* We should never come here for T_UNITDATA_REQ
*/
}
}
/* FALLTHRU */
default:
rds_wput_other(q, mp);
return (0);
}
}
static int
{
int ret = 0;
/* Handle UNITDATA_REQ messages here */
/* If a port has not been bound to the stream, fail. */
return (EPROTO);
}
return (EPROTO);
}
/*
* No options allowed
*/
if (tudr->OPT_length != 0) {
goto done;
}
ret = EDESTADDRREQ;
goto done;
}
ret = EDESTADDRREQ;
goto done;
}
/* Extract port and ipaddr */
ret = EDESTADDRREQ;
goto done;
}
if (ret != 0) {
/* ENOMEM is actually EWOULDBLOCK */
goto done;
}
}
done:
return (ret);
}
/*
* Make sure we dont return EINVAL and EWOULDBLOCK as it has
* special meanings for the synchronous streams (rwnext()).
* We should return ENOMEM which is changed to EWOULDBLOCK by kstrputmsg()
*/
static int
{
int error = 0;
case M_PROTO:
case M_PCPROTO:
sizeof (struct T_unitdata_req)) {
/* Detect valid T_UNITDATA_REQ here */
== T_UNITDATA_REQ)
break;
}
/* FALLTHRU */
default:
/*
* Uio error of some sort, so just return the error.
*/
goto done;
}
rds_wput_other(q, mp);
return (0);
}
done:
return (error);
}
static void
{
/* update the port quota to the current level */
(void) proto_set_rx_hiwat(q, NULL,
}
/* No more messages in the q, unstall the socket */
}
int
{
if (rds_transport_handle != NULL) {
}
return (0);
}
int
{
int ret = 0;
if (rds_transport_handle != NULL) {
/*
* Someone beat us to it.
*/
goto done;
}
if (ibt_hw_is_present() == 0) {
goto done;
}
goto done;
}
if (ret != 0) {
goto done;
}
if (ret != 0) {
}
done:
return (ret);
}
};
};
};
};
/*
* Module linkage information for the kernel.
*/
};
&modldrv,
};
int
_init(void)
{
int ret;
rds_init();
if (ret != 0)
goto done;
if (ret != 0)
done:
return (ret);
}
int
_fini(void)
{
int ret;
if (ret != 0) {
return (ret);
}
rds_fini();
return (0);
}
int
{
}