/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4 1.8 */
/*
* This module establishes a unique connection on
* a STREAMS-based pipe.
*/
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/fstyp.h>
#include <sys/stropts.h>
#include <sys/stream.h>
#include <sys/strsubr.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/fs/fifonode.h>
#include <sys/debug.h>
#include <sys/ddi.h>
/*
* This is the loadable module wrapper.
*/
#include <sys/conf.h>
#include <sys/modctl.h>
extern struct streamtab conninfo;
static struct fmodsw fsw = {
"connld",
&conninfo,
D_NEW | D_MP
};
/*
* Module linkage information for the kernel.
*/
static struct modlstrmod modlstrmod = {
&mod_strmodops, "Streams-based pipes", &fsw
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlstrmod, NULL
};
int
_init()
{
return (mod_install(&modlinkage));
}
int
_fini()
{
return (mod_remove(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
/*
* Define local and external routines.
*/
int connopen(queue_t *, dev_t *, int, int, cred_t *);
int connclose(queue_t *, int, cred_t *);
int connput(queue_t *, mblk_t *);
/*
* Define STREAMS header information.
*/
static struct module_info conn_info = {
1003,
"connld",
0,
INFPSZ,
STRHIGH,
STRLOW
};
static struct qinit connrinit = {
connput,
NULL,
connopen,
connclose,
NULL,
&conn_info,
NULL
};
static struct qinit connwinit = {
connput,
NULL,
NULL,
NULL,
NULL,
&conn_info,
NULL
};
struct streamtab conninfo = {
&connrinit,
&connwinit
};
/*
* For each invocation of connopen(), create a new pipe. One end of the pipe
* is sent to the process on the other end of this STREAM. The vnode for
* the other end is returned to the open() system call as the vnode for
* the opened object.
*
* On the first invocation of connopen(), a flag is set and the routine
* returns 0, since the first open corresponds to the pushing of the module.
*/
/*ARGSUSED*/
int
connopen(queue_t *rqp, dev_t *devp, int flag, int sflag, cred_t *crp)
{
int error = 0;
vnode_t *streamvp;
fifonode_t *streamfnp;
if ((streamvp = strq2vp(rqp)) == NULL) {
return (EINVAL);
}
/*
* CONNLD is only allowed to be pushed onto a "pipe" that has both
* of its ends open.
*/
if (streamvp->v_type != VFIFO) {
error = EINVAL;
goto out;
}
streamfnp = VTOF(streamvp);
if (!(streamfnp->fn_flag & ISPIPE) ||
streamfnp->fn_dest->fn_open == 0) {
error = EPIPE;
goto out;
}
/*
* If this is the first time CONNLD was opened while on this stream,
* it is being pushed. Therefore, set a flag and return 0.
*/
if (rqp->q_ptr == 0) {
if (streamfnp->fn_flag & FIFOCONNLD) {
error = ENXIO;
goto out;
}
rqp->q_ptr = (caddr_t)1;
streamfnp->fn_flag |= FIFOCONNLD;
qprocson(rqp);
}
out:
VN_RELE(streamvp);
return (error);
}
/*ARGSUSED*/
int
connclose(queue_t *q, int cflag, cred_t *crp)
{
vnode_t *streamvp;
fifonode_t *streamfnp;
qprocsoff(q);
streamvp = strq2vp(q);
ASSERT(streamvp != NULL);
ASSERT(streamvp->v_type == VFIFO);
streamfnp = VTOF(streamvp);
streamfnp->fn_flag &= ~FIFOCONNLD;
VN_RELE(streamvp);
return (0);
}
/*
* Use same put procedure for write and read queues.
*/
int
connput(queue_t *q, mblk_t *bp)
{
putnext(q, bp);
return (0);
}