/*
* 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.
*/
/* Copyright (c) 1990 Mentat Inc. */
#include <sys/sysmacros.h>
#include <inet/proto_set.h>
/*
* NOTE: Whenever anything is allocated by mi_alloc or mi_alloc_sleep (below),
* the size of the requested allocation is increased by one word. This extra
* word is used to store the size of the object being allocated, and is located
* at the beginning of the allocated block. The pointer returned to the caller
* is a pointer to the *second* word in the newly-allocated block. The IP
* module of mdb is aware of this, and will need to be changed if this
* allocation strategy is changed.
*/
/* Timer block states. */
/*
*/
typedef struct mtb_s {
int mtb_state;
static int mi_timer_fire(MTBP);
/* ARGSUSED1 */
void *
{
return (ptr + 1);
}
return (NULL);
}
/* ARGSUSED1 */
void *
{
return (ptr + 1);
}
int
{
return (0);
}
void
{
if (!mi_o)
return;
mi_o--;
/* Not in list */
return;
}
/* Free minor number */
/* Unlink from list */
/* If list now empty free the list head */
}
}
void
{
if (!mi_o)
return;
mi_o--;
}
/*
* mi_copyin - takes care of transparent or non-transparent ioctl for the
* calling function so that they have to deal with just M_IOCDATA type
* and not worry about M_COPYIN.
*
* mi_copyin checks to see if the ioctl is transparent or non transparent.
* In case of a non_transparent ioctl, it packs the data into a M_IOCDATA
* message and puts it back onto the current queue for further processing.
* In case of transparent ioctl, it sends a M_COPYIN message up to the
* streamhead so that a M_IOCDATA with the information comes back down.
*/
void
{
int err;
/* A transparent ioctl. Send a M_COPYIN message to the streamhead. */
return;
}
/*
* A non-transparent ioctl. Need to convert into M_IOCDATA message.
*
* We allocate a 0 byte message block and put its address in
* cp_private. It also makes the b_prev field = 1 and b_next
* field = MI_COPY_IN for this 0 byte block. This is done to
* maintain compatibility with old code in mi_copy_state
* (which removes the empty block).
*/
if (err != 0)
goto err_ret;
goto err_ret;
}
/*
* Temporarily insert mp1 between the M_IOCTL and M_DATA blocks so
* that we can use the MI_COPY_COUNT & MI_COPY_DIRECTION macros.
*/
/*
* Leave a pointer to the 0 byte block in cp_private field for
* future use by the mi_copy_* routines.
*/
return;
}
}
/*
* Allows transparent IOCTLs to have multiple copyins. This is needed
* for some variable-length structures, where the total size is only known
* after the first part is copied in. Rather than setting MI_COPY_COUNT to
* 1, as in mi_coypin(), it is simply incremented here. This value can
* then be checked in the returned IOCBLK.
*
* As this deals with copyins that follow the initial copyin, the byte
* offset into the user buffer from which copying should begin must be
* passed in in the offset parameter.
*
* Unlike mi_coypin(), this function expects to be passed an mblk chain
* headed by an M_IOCBLK, as that's the chain that will be in use for
* copies after the first one (copies where n != 1).
*/
void
{
MI_COPY_COUNT(mp)++;
}
void
{
return;
}
/* Check completion of previous copyout operation. */
return;
}
return;
}
/* Set up for first copyout. */
} else {
++MI_COPY_COUNT(mp);
}
/* Find message preceding last. */
;
else
}
{
if (free_on_error) {
}
return (NULL);
}
}
MI_COPY_COUNT(mp) = 0;
/* Make sure it looks clean to mi_copyout. */
}
if (free_on_error)
return (NULL);
}
return (mp1);
}
void
{
if (!mp)
return;
return;
}
}
}
}
int
{
if (mp1) {
return (-1);
}
}
return (-1);
}
return (MI_COPY_STATE(mp));
}
void
{
if (!ptr)
return;
}
static int
{
int base;
int ch;
int count;
char *cp1;
int digits;
char *fcp;
long val;
if (!fmt)
return (-1);
count = 0;
while (*fmt) {
continue;
}
if (*fmt == '0') {
fmt++;
if (!*fmt)
break;
} else
base = 0;
digits *= 10;
}
if (!*fmt)
break;
if (*fmt == 'l') {
fmt++;
}
if (!*fmt)
break;
}
switch (ch) {
case 'c':
continue;
case 'd':
base = 10;
break;
case 'm': /* Print out memory, 2 hex chars per byte */
if (is_long)
else {
else
}
if (!fcp) {
} else {
while (digits--) {
}
}
continue;
case 'o':
base = 8;
break;
case 'p':
/* FALLTHRU */
case 'x':
base = 16;
break;
case 's':
if (is_long)
else {
else
}
if (!fcp)
fcp = (char *)"(NULL)";
while (*fcp) {
break;
}
while (digits > 0) {
digits--;
}
continue;
case 'u':
base = 10;
break;
default:
return (count);
}
if (is_long)
else
if (val < 0) {
}
} else {
if (is_long)
else
}
*--fmt = '\0';
do {
break;
if (zero_filled) {
*--fmt = '0';
digits--;
}
}
while (*fmt)
}
return (count);
}
/* PRINTFLIKE2 */
int
{
if (mp) {
(char *)mp);
if (count != -1)
}
return (count);
}
/* PRINTFLIKE2 */
int
{
if (mp) {
(char *)mp);
if (count != -1)
}
return (count);
}
int
{
if (!mp)
return (0);
}
return (1);
}
{
return (NULL);
}
/*
* Clients can choose to have both module instances and device instances
* in the same list. Return the first device instance in the list.
*/
{
if (mi_op->mi_o_isdev)
}
return (NULL);
}
{
return (NULL);
}
/*
* Clients can choose to have both module instances and device instances
* in the same list. Return the next device instance in the list.
*/
{
if (mi_op->mi_o_isdev)
}
return (NULL);
}
/*
* Self clone the device
* XXX - should we still support clone device
*/
/* ARGSUSED4 */
int
{
int error;
return (0);
if (error != 0) {
}
return (error);
}
{
return (NULL);
mi_o++;
}
{
return (NULL);
return (NULL);
mi_o++;
}
/*
* MODOPEN means just link in without respect of mi_o_dev.
* A NULL devp can be used to create a detached instance
* Otherwise self-clone the device.
*/
/* ARGSUSED3 */
int
{
char *head_name;
} else {
(void *)mi_headp);
}
/* Setup doubly linked list */
}
mi_o--;
/*
* Set device number to MAXMIN + incrementing number.
*/
/* check for wraparound */
}
/* Detached open */
return (EBUSY);
}
else
if (devp)
return (0);
}
uint8_t *
{
if (!mp)
return (NULL);
return (NULL);
}
uint8_t *
{
return (param);
break;
}
}
return (NULL);
}
int
{
if (buf) {
(char *)&buf);
if (count != -1)
}
return (count);
}
/* Used to count without writing data */
/* ARGSUSED1 */
static int
{
(*cpp)++;
return (1);
}
int
{
(*cpp)++;
return (1);
}
int
{
if (!cp2[-1])
return (0);
}
}
{
while (*cp != '\0')
cp++;
}
int
{
char *cp;
short mid;
int ret;
short sid;
sid = 0;
mid = 0;
if (q != NULL) {
}
/* Find out how many bytes we need and allocate if necesary */
return (-1);
}
if (count != -1)
else
alloc_buf[0] = '\0';
return (ret);
}
long
{
const char *cp;
int digits;
long value;
cp++;
if (is_negative)
cp++;
if (base == 0) {
base = 10;
if (*cp == '0') {
base = 8;
cp++;
base = 16;
cp++;
}
}
}
value = 0;
else
break;
break;
}
/* Note: we cast away const here deliberately */
if (is_negative)
return (value);
}
/*
* mi_timer mechanism.
*
* Each timer is represented by a timer mblk and a (streams) queue. When the
* timer fires the timer mblk will be put on the associated streams queue
* so that the streams module can process the timer even in its service
* procedure.
*
* The interface consists of 4 entry points:
* mi_timer_alloc - create a timer mblk
* mi_timer_free - free a timer mblk
* mi_timer - start, restart, stop, or move the
* timer to a different queue
* mi_timer_valid - called by streams module to verify that
* the timer did indeed fire.
*/
/*
* Start, restart, stop, or move the timer to a new queue.
* If "tim" is -2 the timer is moved to a different queue.
* If "tim" is -1 the timer is stopped.
* Otherwise, the timer is stopped if it is already running, and
* set to fire tim milliseconds from now.
*/
void
{
int state;
return;
if (tim >= 0) {
if (state == TB_RUNNING) {
/* Message has already been putq */
/* mi_timer_valid will start timer */
return;
}
if (state == TB_CANCELLED) {
/* mi_timer_valid will start timer */
return;
}
if (state == TB_RESCHED) {
/* mi_timer_valid will start timer */
return;
}
}
return;
}
switch (tim) {
case -1:
break;
case -2:
mi_timer_move(q, mp);
break;
}
}
/*
* Allocate an M_PCSIG timer message. The space between db_base and
* b_rptr is used by the mi_timer mechanism, and after b_rptr there are
* "size" bytes that the caller can use for its own purposes.
*
* Note that db_type has to be a priority message since otherwise
* the putq will not cause the service procedure to run when
* there is flow control.
*/
{
return (mp);
}
return (NULL);
}
/*
* timeout() callback function.
* Put the message on the current queue.
* If the timer is stopped or moved to a different queue after
* it has fired then mi_timer() and mi_timer_valid() will clean
* things up.
*/
static int
{
}
/*
* Logically free a timer mblk (that might have a pending timeout().)
* If the timer has fired and the mblk has been put on the queue then
* mi_timer_valid will free the mblk.
*/
void
{
int state;
return;
if (state == TB_RUNNING) {
/* Message has already been putq */
/* mi_timer_valid will free the mblk */
return;
}
/* Message has already been putq */
/* mi_timer_valid will free the mblk */
return;
}
}
/*
* Called from mi_timer(,,-2)
*/
void
{
return;
/*
* Need to untimeout and restart to make
* sure that the mblk is not about to be putq on the old queue
* by mi_timer_fire.
*/
/*
* Message has already been putq. Move from old queue
* to new queue.
*/
return;
}
/*
* Message is already sitting on queue. Move to new queue.
*/
} else
}
/*
* Called from mi_timer(,,-1)
*/
void
{
int state;
return;
if (state == TB_RUNNING) {
/* Message has already been putq */
} else {
}
} else if (state == TB_RESCHED) {
}
}
/*
* The user of the mi_timer mechanism is required to call mi_timer_valid() for
* each M_PCSIG message processed in the service procedures.
* mi_timer_valid will return "true" if the timer actually did fire.
*/
{
int state;
return (B_FALSE);
if (state != TB_RUNNING) {
if (state == TB_TO_BE_FREED) {
/*
* mi_timer_free was called after the message
* was putq'ed.
*/
return (B_FALSE);
}
if (state == TB_CANCELLED) {
/* The timer was stopped after the mblk was putq'ed */
return (B_FALSE);
}
if (state == TB_RESCHED) {
/*
* The timer was stopped and then restarted after
* the mblk was putq'ed.
* mtb_time_left contains the number of ticks that
* the timer was restarted with.
*/
return (B_FALSE);
}
}
return (B_TRUE);
}
static void
{
/*
* This code is used more than just for unitdata ind
* (also for T_CONN_IND and T_CONN_CON) and
* relies on correct functioning on the happy
* coincidence that the address and option buffers
* are isomorphic in terms of offset from start of data
* structure
*/
if (addr_length > 0) {
}
if (opt_length > 0) {
}
}
{
}
return (mp);
}
{
}
return (mp);
}
{
NULL) {
if (dst_length > 0) {
}
}
return (mp);
}
{
}
return (mp);
}
/*
* Allocate and fill in a TPI err ack packet using the 'mp' passed in
* for the 'error_prim' context as well as sacrifice.
*/
{
if (!mp)
return (NULL);
}
return (mp);
}
{
if (!mp)
return (NULL);
}
return (mp);
}
{
return (mi_tpi_ok_ack_alloc_extra(mp, 0));
}
mi_tpi_ordrel_ind(void)
{
}
return (mp);
}
static MBLKP
{
}
return (mp);
}
{
}
return (mp);
}
{
return (ptr);
}
{
return (ptr);
}