Exemplo n.º 1
0
int
osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
	    int nvecs, afs_int32 alength, int istack)
{
    register afs_int32 code;
    int i;
    struct iovec iov[RX_MAXIOVECS];
    struct uio u;
    int haveGlock = ISAFS_GLOCK();

    AFS_STATCNT(osi_NetSend);
    if (nvecs > RX_MAXIOVECS)
	osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);

    for (i = 0; i < nvecs; i++)
	iov[i] = dvec[i];

    u.uio_iov = &iov[0];
    u.uio_iovcnt = nvecs;
    u.uio_offset = 0;
    u.uio_resid = alength;
    u.uio_segflg = UIO_SYSSPACE;
    u.uio_rw = UIO_WRITE;
#ifdef AFS_FBSD50_ENV
    u.uio_td = NULL;
#else
    u.uio_procp = NULL;
#endif

    addr->sin_len = sizeof(struct sockaddr_in);

    if (haveGlock)
	AFS_GUNLOCK();
#if KNET_DEBUG
    printf("+");
#endif
#ifdef AFS_FBSD50_ENV
    code =
	sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0,
	       curthread);
#else
    code =
	sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0, curproc);
#endif
#if KNET_DEBUG
    if (code) {
	if (code == EINVAL)
	    Debugger("afs NetSend busted");
	else
	    printf("z");
    }
#endif
    if (haveGlock)
	AFS_GLOCK();
    return code;
}
Exemplo n.º 2
0
static void
ncp_watchdog(struct ncp_conn *conn) {
	char *buf;
	struct mbuf *m;
	int error, len, flags;
	struct socket *so;
	struct sockaddr *sa;
	struct uio auio;

	sa = NULL;
	while (conn->wdg_so) { /* not a loop */
		so = conn->wdg_so;
		auio.uio_resid = len = 1000000;
		auio.uio_td = curthread;
		flags = MSG_DONTWAIT;
		error = soreceive(so, (struct sockaddr**)&sa, &auio, &m,
		    (struct mbuf**)0, &flags);
		if (error) break;
		len -= auio.uio_resid;
		NCPSDEBUG("got watch dog %d\n",len);
		if (len != 2) break;
		buf = mtod(m, char*);
		if (buf[1] != '?') break;
		buf[1] = 'Y';
		error = sosend(so, (struct sockaddr*)sa, 0, m, 0, 0, curthread);
		NCPSDEBUG("send watch dog %d\n",error);
		break;
	}
	if (sa) free(sa, M_SONAME);
	return;
}
Exemplo n.º 3
0
errno_t xi_sock_send(xi_socket_t so, void *buf, size_t *len, int flags) {
	
#ifdef __KPI_SOCKET__
	struct iovec aio;
	struct msghdr msg;
	
	size_t sentLen = *len;
	errno_t	error;
	
	aio.iov_base = buf;
	aio.iov_len = sentLen;
	bzero(&msg, sizeof(msg));
	msg.msg_iov = (struct iovec *) &aio;
	msg.msg_iovlen = 1;
	
	error = sock_send(so, &msg, flags, &sentLen);
	
#if 1
    if(error)
		DebugPrint(1, false, "xi_sock_send: so = %p, buf_len = %d error = %d\n", so, (int)*len, error);
#endif /* if 0 */     
	
	*len = sentLen;
	
	return error;
#else
	struct iovec aiov;
    struct uio auio = { 0 };
    register struct proc *p = current_proc();
    register int error = 0;
    
    aiov.iov_base = buf;
    aiov.iov_len = *len;
    
    auio.uio_iov = &aiov;
    auio.uio_iovcnt = 1;
    auio.uio_segflg = UIO_SYSSPACE;
    auio.uio_rw = UIO_WRITE;
    auio.uio_procp = p;
    auio.uio_offset = 0;                    /* XXX */
    auio.uio_resid = *len;

//    IOLog("Before: so = %p, buf_len = %d, aiov.iov_len = %d, error = %d, auio.uio_resid = %d\n", so, (int)len, (int)aiov.iov_len, error,auio.uio_resid);
    thread_funnel_set(network_flock, TRUE);

    error = sosend(so, NULL, &auio, NULL, 0, flags);
    
	(void) thread_funnel_set(network_flock, FALSE);

#if 0
    if(error)
        IOLog("After: so = %p, buf_len = %d, aiov.iov_len = %d, error = %d, auio.uio_resid = %d\n", so, (int)*len, (int)aiov.iov_len, error, auio.uio_resid);
#endif /* if 0 */     
   
	*len = *len - auio.uio_resid;
	
	return error;
	
#endif
}
Exemplo n.º 4
0
/*
 * Receive incoming data on our hook.  Send it out the socket.
 */
static int
ng_ksocket_rcvdata(hook_p hook, item_p item)
{
	struct thread *td = curthread;	/* XXX broken */
	const node_p node = NG_HOOK_NODE(hook);
	const priv_p priv = NG_NODE_PRIVATE(node);
	struct socket *const so = priv->so;
	struct sockaddr *sa = NULL;
	int error;
	struct mbuf *m;
	struct sa_tag *stag;

	/* Extract data */
	NGI_GET_M(item, m);
	NG_FREE_ITEM(item);

	/*
	 * Look if socket address is stored in packet tags.
	 * If sockaddr is ours, or provided by a third party (zero id),
	 * then we accept it.
	 */
	if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE,
	    NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) &&
	    (stag->id == NG_NODE_ID(node) || stag->id == 0))
		sa = &stag->sa;

	/* Reset specific mbuf flags to prevent addressing problems. */
	m->m_flags &= ~(M_BCAST|M_MCAST);

	/* Send packet */
	error = sosend(so, sa, 0, m, 0, 0, td);

	return (error);
}
Exemplo n.º 5
0
/* ARGSUSED */
int
soo_write(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
{

	return (sosend((struct socket *)fp->f_data, (struct mbuf *)0,
		uio, (struct mbuf *)0, (struct mbuf *)0, 0));
}
Exemplo n.º 6
0
int
ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
{
	struct thread *td = curthread; /* XXX */
	struct sockaddr *to = 0;
	struct ncp_conn *conn = rqp->nr_conn;
	struct mbuf *m;
	int error, flags=0;

	for (;;) {
		m = m_copym(top, 0, M_COPYALL, M_WAIT);
/*		NCPDDEBUG(m);*/
		error = sosend(so, to, 0, m, 0, flags, td);
		if (error == 0 || error == EINTR || error == ENETDOWN)
			break;
		if (rqp->rexmit == 0) break;
		rqp->rexmit--;
		pause("ncprsn", conn->li.timeout * hz);
		error = ncp_chkintr(conn, td);
		if (error == EINTR) break;
	}
	if (error) {
		log(LOG_INFO, "ncp_send: error %d for server %s", error, conn->li.server);
	}
	return error;
}
/*
 * send data by simply allocating an MBUF packet
 * header and pointing it to our data region.
 *
 * Optionally, the caller may supply 'reference'
 * and 'free' procs. (The latter may call the
 * user back once the networking stack has
 * released the buffer).
 *
 * The callbacks are provided with the 'closure'
 * pointer and the 'buflen' argument.
 */
ssize_t
sendto_nocpy (
		int s,
		const void *buf, size_t buflen,
		int flags,
		const struct sockaddr *toaddr, int tolen,
		void *closure,
		void (*freeproc)(caddr_t, u_int),
		void (*refproc)(caddr_t, u_int)
)
{
	int           error;
	struct socket *so;
	struct mbuf   *to, *m;
	int           ret = -1;

	rtems_bsdnet_semaphore_obtain ();
	if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
		rtems_bsdnet_semaphore_release ();
		return -1;
	}

	error = sockaddrtombuf (&to, toaddr, tolen);
	if (error) {
		errno = error;
		rtems_bsdnet_semaphore_release ();
		return -1;
	}

	MGETHDR(m, M_WAIT, MT_DATA);
	m->m_pkthdr.len   = 0;
	m->m_pkthdr.rcvif =  (struct ifnet *) 0;

	m->m_flags       |= M_EXT;
	m->m_ext.ext_buf  = closure ? closure : (void*)buf;
	m->m_ext.ext_size = buflen;
	/* we _must_ supply non-null procs; otherwise,
	 * the kernel code assumes it's a mbuf cluster
	 */
	m->m_ext.ext_free = freeproc ? freeproc : dummyproc;
	m->m_ext.ext_ref  = refproc  ? refproc  : dummyproc;
	m->m_pkthdr.len  += buflen;
	m->m_len          = buflen;
	m->m_data		  = (void*)buf;

	error = sosend (so, to, NULL, m, NULL, flags);
	if (error) {
		if (/*auio.uio_resid != len &&*/ (error == EINTR || error == EWOULDBLOCK))
			error = 0;
	}
	if (error)
		errno = error;
	else
		ret = buflen;
	if (to)
		m_freem(to);
	rtems_bsdnet_semaphore_release ();
	return (ret);
}
Exemplo n.º 8
0
static bool_t
svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
	struct ct_data *ct;
	XDR xdrs;
	struct mbuf *mrep;
	bool_t stat = TRUE;
	int error;

	/*
	 * Leave space for record mark.
	 */
	mrep = m_gethdr(M_WAITOK, MT_DATA);
	mrep->m_data += sizeof(uint32_t);

	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);

	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if (!xdr_replymsg(&xdrs, msg))
			stat = FALSE;
		else
			xdrmbuf_append(&xdrs, m);
	} else {
		stat = xdr_replymsg(&xdrs, msg);
	}

	if (stat) {
		m_fixhdr(mrep);

		/*
		 * Prepend a record marker containing the reply length.
		 */
		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
		*mtod(mrep, uint32_t *) =
			htonl(0x80000000 | (mrep->m_pkthdr.len
				- sizeof(uint32_t)));
		sx_xlock(&xprt->xp_lock);
		ct = (struct ct_data *)xprt->xp_p2;
		if (ct != NULL)
			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
			    0, curthread);
		else
			error = EPIPE;
		sx_xunlock(&xprt->xp_lock);
		if (!error) {
			stat = TRUE;
		}
	} else {
		m_freem(mrep);
	}

	XDR_DESTROY(&xdrs);

	return (stat);
}
Exemplo n.º 9
0
static bool_t
svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
	XDR xdrs;
	struct mbuf *mrep;
	bool_t stat = TRUE;
	int error, len;

	/*
	 * Leave space for record mark.
	 */
	mrep = m_gethdr(M_WAITOK, MT_DATA);
	mrep->m_data += sizeof(uint32_t);

	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);

	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if (!xdr_replymsg(&xdrs, msg))
			stat = FALSE;
		else
			xdrmbuf_append(&xdrs, m);
	} else {
		stat = xdr_replymsg(&xdrs, msg);
	}

	if (stat) {
		m_fixhdr(mrep);

		/*
		 * Prepend a record marker containing the reply length.
		 */
		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
		len = mrep->m_pkthdr.len;
		*mtod(mrep, uint32_t *) =
			htonl(0x80000000 | (len - sizeof(uint32_t)));
		atomic_add_32(&xprt->xp_snd_cnt, len);
		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
		    0, curthread);
		if (!error) {
			atomic_add_rel_32(&xprt->xp_snt_cnt, len);
			if (seq)
				*seq = xprt->xp_snd_cnt;
			stat = TRUE;
		} else
			atomic_subtract_32(&xprt->xp_snd_cnt, len);
	} else {
		m_freem(mrep);
	}

	XDR_DESTROY(&xdrs);

	return (stat);
}
Exemplo n.º 10
0
static int
kttcp_send(struct thread *td, struct kttcp_io_args *kio)
{
	struct file *fp;
	int error;
	struct timeval t0, t1;
	unsigned long long len = 0;
	struct uio auio;
	struct iovec aiov;

	bzero(&aiov, sizeof(aiov));
	bzero(&auio, sizeof(auio));
	auio.uio_iov = &aiov;
	auio.uio_segflg = UIO_NOCOPY;

	error = fget(td, kio->kio_socket, &fp);
	if (error != 0)
		return error;

	if ((fp->f_flag & FWRITE) == 0) {
		fdrop(fp, td);
		return EBADF;
	}
	if (fp->f_type == DTYPE_SOCKET) {
		len = kio->kio_totalsize;
		microtime(&t0);
		do {
			nbyte =  MIN(len, (unsigned long long)nbyte);
			aiov.iov_len = nbyte;
			auio.uio_resid = nbyte;
			auio.uio_offset = 0;
			error = sosend((struct socket *)fp->f_data, NULL,
				       &auio, NULL, NULL, 0, td);
			len -= auio.uio_offset;
		} while (error == 0 && len != 0);
		microtime(&t1);
	} else
		error = EFTYPE;
	fdrop(fp, td);
	if (error != 0)
		return error;
	timersub(&t1, &t0, &kio->kio_elapsed);

	kio->kio_bytesdone = kio->kio_totalsize - len;

	return 0;
}
Exemplo n.º 11
0
/*
 * Vnode op for write
 */
int
fifo_write(struct vnop_write_args *ap)
{
	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
	int error;

#if DIAGNOSTIC
	if (ap->a_uio->uio_rw != UIO_WRITE)
		panic("fifo_write mode");
#endif
	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL,
		       (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0);
	if (error == 0)
		lock_vnode_and_post(ap->a_vp, 0);

	return (error);
}
Exemplo n.º 12
0
int
osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
	    int nvecs, afs_int32 alength, int istack)
{
    int i, code;
    struct iovec iov[RX_MAXIOVECS];
    struct uio u;
    struct mbuf *nam;
    int haveGlock = ISAFS_GLOCK();

    memset(&u, 0, sizeof(u));
    memset(&iov, 0, sizeof(iov));

    AFS_STATCNT(osi_NetSend);
    if (nvecs > RX_MAXIOVECS)
	osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);

    for (i = 0; i < nvecs; i++)
	iov[i] = dvec[i];

    u.uio_iov = &iov[0];
    u.uio_iovcnt = nvecs;
    u.uio_offset = 0;
    u.uio_resid = alength;
    u.uio_segflg = UIO_SYSSPACE;
    u.uio_rw = UIO_WRITE;
    u.uio_procp = NULL;

    nam = m_get(M_DONTWAIT, MT_SONAME);
    if (!nam)
	return ENOBUFS;
    nam->m_len = addr->sin_len = sizeof(struct sockaddr_in);
    memcpy(mtod(nam, caddr_t), addr, addr->sin_len);

    if (haveGlock)
	AFS_GUNLOCK();
    code = sosend(asocket, nam, &u, NULL, NULL, 0);
    if (haveGlock)
	AFS_GLOCK();
    m_freem(nam);

    return code;
}
Exemplo n.º 13
0
static int
soo_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
    int flags, struct thread *td)
{
	struct socket *so = fp->f_data;
	int error;

#ifdef MAC
	error = mac_socket_check_send(active_cred, so);
	if (error)
		return (error);
#endif
	error = sosend(so, 0, uio, 0, 0, 0, uio->uio_td);
	if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) {
		PROC_LOCK(uio->uio_td->td_proc);
		tdsignal(uio->uio_td, SIGPIPE);
		PROC_UNLOCK(uio->uio_td->td_proc);
	}
	return (error);
}
Exemplo n.º 14
0
/* ARGSUSED */
int
fifo_write(void *v)
{
	struct vop_write_args *ap = v;
	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
	struct proc *p = ap->a_uio->uio_procp;
	int error;

#ifdef DIAGNOSTIC
	if (ap->a_uio->uio_rw != UIO_WRITE)
		panic("fifo_write mode");
#endif
	if (ap->a_ioflag & IO_NDELAY)
		wso->so_state |= SS_NBIO;
	VOP_UNLOCK(ap->a_vp, 0, p);
	error = sosend(wso, NULL, ap->a_uio, NULL, NULL, 0);
	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
	if (ap->a_ioflag & IO_NDELAY)
		wso->so_state &= ~SS_NBIO;
	return (error);
}
Exemplo n.º 15
0
static bool_t
svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr *addr, struct mbuf *m)
{
	XDR xdrs;
	struct mbuf *mrep;
	bool_t stat = TRUE;
	int error;

	MGETHDR(mrep, M_WAIT, MT_DATA);
	mrep->m_len = 0;

	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);

	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if (!xdr_replymsg(&xdrs, msg))
			stat = FALSE;
		else
			xdrmbuf_append(&xdrs, m);
	} else {
		stat = xdr_replymsg(&xdrs, msg);
	}

	if (stat) {
		m_fixhdr(mrep);
		error = sosend(xprt->xp_socket, addr, NULL, mrep, NULL,
		    0, curthread);
		if (!error) {
			stat = TRUE;
		}
	} else {
		m_freem(mrep);
	}

	XDR_DESTROY(&xdrs);
	xprt->xp_p2 = NULL;

	return (stat);
}
Exemplo n.º 16
0
int
bootpc_call(
     struct bootp_packet *call,
     struct bootp_packet *reply,	/* output */
     struct proc *procp)
{
	struct socket *so;
	struct sockaddr_in *sin;
	struct mbuf *m, *nam;
	struct uio auio;
	struct iovec aio;
	int error, rcvflg, timo, secs, len;

	/* Free at end if not null. */
	nam = NULL;

	/*
	 * Create socket and set its recieve timeout.
	 */
	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)))
		goto out;

	m = m_get(M_WAIT, MT_SOOPTS);
	if (m == NULL) {
		error = ENOBUFS;
		goto out;
	} else {
		struct timeval *tv;
		tv = mtod(m, struct timeval *);
		m->m_len = sizeof(*tv);
		tv->tv_sec = 1;
		tv->tv_usec = 0;
		if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
			goto out;
	}

	/*
	 * Enable broadcast.
	 */
	{
		int *on;
		m = m_get(M_WAIT, MT_SOOPTS);
		if (m == NULL) {
			error = ENOBUFS;
			goto out;
		}
		on = mtod(m, int *);
		m->m_len = sizeof(*on);
		*on = 1;
		if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
			goto out;
	}

	/*
	 * Bind the local endpoint to a bootp client port.
	 */
	m = m_getclr(M_WAIT, MT_SONAME);
	sin = mtod(m, struct sockaddr_in *);
	sin->sin_len = m->m_len = sizeof(*sin);
	sin->sin_family = AF_INET;
	sin->sin_addr.s_addr = INADDR_ANY;
	sin->sin_port = htons(IPPORT_BOOTPC);
	error = sobind(so, m);
	m_freem(m);
	if (error) {
		printf("bind failed\n");
		goto out;
	}

	/*
	 * Setup socket address for the server.
	 */
	nam = m_get(M_WAIT, MT_SONAME);
	if (nam == NULL) {
		error = ENOBUFS;
		goto out;
	}
	sin = mtod(nam, struct sockaddr_in *);
	sin-> sin_len = sizeof(*sin);
	sin-> sin_family = AF_INET;
	sin->sin_addr.s_addr = INADDR_BROADCAST;
	sin->sin_port = htons(IPPORT_BOOTPS);

	nam->m_len = sizeof(*sin);

	/*
	 * Send it, repeatedly, until a reply is received,
	 * but delay each re-send by an increasing amount.
	 * If the delay hits the maximum, start complaining.
	 */
	for (timo=1; timo <= MAX_RESEND_DELAY; timo++) {
		/* Send BOOTP request (or re-send). */
		
		aio.iov_base = (caddr_t) call;
		aio.iov_len = sizeof(*call);
		
		auio.uio_iov = &aio;
		auio.uio_iovcnt = 1;
		auio.uio_segflg = UIO_SYSSPACE;
		auio.uio_rw = UIO_WRITE;
		auio.uio_offset = 0;
		auio.uio_resid = sizeof(*call);
		auio.uio_procp = procp;
		error = sosend(so, nam, &auio, NULL, NULL, 0);
		if (error) {
			printf("bootpc_call: sosend: %d\n", error);
                        switch (error) {
                        case  ENOBUFS:             /* No buffer space available */
                        case  ENETUNREACH:         /* Network is unreachable */
                        case  ENETDOWN:            /* Network interface is not configured */
                        case  EHOSTDOWN:           /* Host is down */
                        case  EHOSTUNREACH:        /* Host is unreachable */
                        case  EMSGSIZE:            /* Message too long */
                                /* This is a possibly transient error.
                                   We can still receive replies from previous attempts. */
                                break;
                        default:
                              goto out;
                        }
		}

		/*
		 * Wait for up to timo seconds for a reply.
		 * The socket receive timeout was set to 1 second.
		 */
		secs = timo;
		while (secs > 0) {
			aio.iov_base = (caddr_t) reply;
			aio.iov_len = sizeof(*reply);

			auio.uio_iov = &aio;
			auio.uio_iovcnt = 1;
			auio.uio_segflg = UIO_SYSSPACE;
			auio.uio_rw = UIO_READ;
			auio.uio_offset = 0;
			auio.uio_resid = sizeof(*reply);
			auio.uio_procp = procp;
			
			rcvflg = 0;
			error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg);
			if (error == EWOULDBLOCK) {
				secs--;
				call->secs=htons(ntohs(call->secs)+1);
				continue;
			}
			if (error)
				goto out;
			len = sizeof(*reply) - auio.uio_resid;

			/* Do we have the required number of bytes ? */
			if (len < BOOTP_MIN_LEN)
				continue;

			/* Is it the right reply? */
			if (reply->op != 2)
			  continue;

			if (reply->xid != call->xid)
				continue;

			if (reply->hlen != call->hlen)
			  continue;

			if (bcmp(reply->chaddr,call->chaddr,call->hlen))
			  continue;

			goto gotreply;	/* break two levels */

		} /* while secs */
	} /* send/receive a number of times then return an error */
	{
		uint32_t addr = ntohl(sin->sin_addr.s_addr);
        printf("BOOTP timeout for server %"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32"\n",
               (addr >> 24) & 0xff, (addr >> 16) & 0xff,
               (addr >> 8) & 0xff, addr & 0xff);
	}
	error = ETIMEDOUT;
	goto out;

 gotreply:
 out:
	if (nam) m_freem(nam);
	soclose(so);
	return error;
}
Exemplo n.º 17
0
static void
soaio_process_job(struct socket *so, struct sockbuf *sb, struct kaiocb *job)
{
	struct ucred *td_savedcred;
	struct thread *td;
	struct file *fp;
	struct uio uio;
	struct iovec iov;
	size_t cnt;
	int error, flags;

	SOCKBUF_UNLOCK(sb);
	aio_switch_vmspace(job);
	td = curthread;
	fp = job->fd_file;
retry:
	td_savedcred = td->td_ucred;
	td->td_ucred = job->cred;

	cnt = job->uaiocb.aio_nbytes;
	iov.iov_base = (void *)(uintptr_t)job->uaiocb.aio_buf;
	iov.iov_len = cnt;
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;
	uio.uio_offset = 0;
	uio.uio_resid = cnt;
	uio.uio_segflg = UIO_USERSPACE;
	uio.uio_td = td;
	flags = MSG_NBIO;

	/* TODO: Charge ru_msg* to job. */

	if (sb == &so->so_rcv) {
		uio.uio_rw = UIO_READ;
#ifdef MAC
		error = mac_socket_check_receive(fp->f_cred, so);
		if (error == 0)

#endif
			error = soreceive(so, NULL, &uio, NULL, NULL, &flags);
	} else {
		uio.uio_rw = UIO_WRITE;
#ifdef MAC
		error = mac_socket_check_send(fp->f_cred, so);
		if (error == 0)
#endif
			error = sosend(so, NULL, &uio, NULL, NULL, flags, td);
		if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) {
			PROC_LOCK(job->userproc);
			kern_psignal(job->userproc, SIGPIPE);
			PROC_UNLOCK(job->userproc);
		}
	}

	cnt -= uio.uio_resid;
	td->td_ucred = td_savedcred;

	/* XXX: Not sure if this is needed? */
	if (cnt != 0 && (error == ERESTART || error == EINTR ||
	    error == EWOULDBLOCK))
		error = 0;
	if (error == EWOULDBLOCK) {
		/*
		 * A read() or write() on the socket raced with this
		 * request.  If the socket is now ready, try again.
		 * If it is not, place this request at the head of the
		 * queue to try again when the socket is ready.
		 */
		SOCKBUF_LOCK(sb);		
		empty_results++;
		if (soaio_ready(so, sb)) {
			empty_retries++;
			SOCKBUF_UNLOCK(sb);
			goto retry;
		}

		if (!aio_set_cancel_function(job, soo_aio_cancel)) {
			MPASS(cnt == 0);
			SOCKBUF_UNLOCK(sb);
			aio_cancel(job);
			SOCKBUF_LOCK(sb);
		} else {
			TAILQ_INSERT_HEAD(&sb->sb_aiojobq, job, list);
		}
	} else {
		aio_complete(job, cnt, error);
		SOCKBUF_LOCK(sb);
	}
}
Exemplo n.º 18
0
static void
soaio_process_job(struct socket *so, struct sockbuf *sb, struct kaiocb *job)
{
	struct ucred *td_savedcred;
	struct thread *td;
	struct file *fp;
	struct uio uio;
	struct iovec iov;
	size_t cnt, done;
	long ru_before;
	int error, flags;

	SOCKBUF_UNLOCK(sb);
	aio_switch_vmspace(job);
	td = curthread;
	fp = job->fd_file;
retry:
	td_savedcred = td->td_ucred;
	td->td_ucred = job->cred;

	done = job->aio_done;
	cnt = job->uaiocb.aio_nbytes - done;
	iov.iov_base = (void *)((uintptr_t)job->uaiocb.aio_buf + done);
	iov.iov_len = cnt;
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;
	uio.uio_offset = 0;
	uio.uio_resid = cnt;
	uio.uio_segflg = UIO_USERSPACE;
	uio.uio_td = td;
	flags = MSG_NBIO;

	/*
	 * For resource usage accounting, only count a completed request
	 * as a single message to avoid counting multiple calls to
	 * sosend/soreceive on a blocking socket.
	 */

	if (sb == &so->so_rcv) {
		uio.uio_rw = UIO_READ;
		ru_before = td->td_ru.ru_msgrcv;
#ifdef MAC
		error = mac_socket_check_receive(fp->f_cred, so);
		if (error == 0)

#endif
			error = soreceive(so, NULL, &uio, NULL, NULL, &flags);
		if (td->td_ru.ru_msgrcv != ru_before)
			job->msgrcv = 1;
	} else {
		uio.uio_rw = UIO_WRITE;
		ru_before = td->td_ru.ru_msgsnd;
#ifdef MAC
		error = mac_socket_check_send(fp->f_cred, so);
		if (error == 0)
#endif
			error = sosend(so, NULL, &uio, NULL, NULL, flags, td);
		if (td->td_ru.ru_msgsnd != ru_before)
			job->msgsnd = 1;
		if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) {
			PROC_LOCK(job->userproc);
			kern_psignal(job->userproc, SIGPIPE);
			PROC_UNLOCK(job->userproc);
		}
	}

	done += cnt - uio.uio_resid;
	job->aio_done = done;
	td->td_ucred = td_savedcred;

	if (error == EWOULDBLOCK) {
		/*
		 * The request was either partially completed or not
		 * completed at all due to racing with a read() or
		 * write() on the socket.  If the socket is
		 * non-blocking, return with any partial completion.
		 * If the socket is blocking or if no progress has
		 * been made, requeue this request at the head of the
		 * queue to try again when the socket is ready.
		 */
		MPASS(done != job->uaiocb.aio_nbytes);
		SOCKBUF_LOCK(sb);
		if (done == 0 || !(so->so_state & SS_NBIO)) {
			empty_results++;
			if (soaio_ready(so, sb)) {
				empty_retries++;
				SOCKBUF_UNLOCK(sb);
				goto retry;
			}
			
			if (!aio_set_cancel_function(job, soo_aio_cancel)) {
				SOCKBUF_UNLOCK(sb);
				if (done != 0)
					aio_complete(job, done, 0);
				else
					aio_cancel(job);
				SOCKBUF_LOCK(sb);
			} else {
				TAILQ_INSERT_HEAD(&sb->sb_aiojobq, job, list);
			}
			return;
		}
		SOCKBUF_UNLOCK(sb);
	}		
	if (done != 0 && (error == ERESTART || error == EINTR ||
	    error == EWOULDBLOCK))
		error = 0;
	if (error)
		aio_complete(job, -1, error);
	else
		aio_complete(job, done, 0);
	SOCKBUF_LOCK(sb);
}
Exemplo n.º 19
0
int
osi_NetSend(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
	    int nvecs, afs_int32 alength, int istack)
{
#ifdef AFS_DARWIN80_ENV
    socket_t asocket = (socket_t)so;
    struct msghdr msg;
    size_t slen;
#else
    struct socket *asocket = (struct socket *)so;
    struct uio u;
#endif
    afs_int32 code;
    int i;
    struct iovec iov[RX_MAXIOVECS];
    int haveGlock = ISAFS_GLOCK();

    AFS_STATCNT(osi_NetSend);
    if (nvecs > RX_MAXIOVECS)
	osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);

    for (i = 0; i < nvecs; i++)
	iov[i] = dvec[i];

    addr->sin_len = sizeof(struct sockaddr_in);

    if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
	(afs_termState == AFSOP_STOP_COMPLETE))
	return -1;

    if (haveGlock)
	AFS_GUNLOCK();

#if defined(KERNEL_FUNNEL)
    thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif
#ifdef AFS_DARWIN80_ENV
    memset(&msg, 0, sizeof(struct msghdr));
    msg.msg_name = addr;
    msg.msg_namelen = ((struct sockaddr *)addr)->sa_len;
    msg.msg_iov = &iov[0];
    msg.msg_iovlen = nvecs;
    code = sock_send(asocket, &msg, 0, &slen);
#else
    u.uio_iov = &iov[0];
    u.uio_iovcnt = nvecs;
    u.uio_offset = 0;
    u.uio_resid = alength;
    u.uio_segflg = UIO_SYSSPACE;
    u.uio_rw = UIO_WRITE;
    u.uio_procp = NULL;
    code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0);
#endif

#if defined(KERNEL_FUNNEL)
    thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
#endif
    if (haveGlock)
	AFS_GLOCK();
    return code;
}
Exemplo n.º 20
0
static int
bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
{
	struct socket *so;
	struct sockaddr_in *sin, dst;
	struct uio auio;
	struct sockopt sopt;
	struct iovec aio;
	int error, on, rcvflg, timo, len;
	time_t atimo;
	time_t rtimo;
	struct timeval tv;
	struct bootpc_ifcontext *ifctx;
	int outstanding;
	int gotrootpath;
	int retry;
	const char *s;

	/*
	 * Create socket and set its recieve timeout.
	 */
	error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td);
	if (error != 0)
		goto out0;

	tv.tv_sec = 1;
	tv.tv_usec = 0;
	bzero(&sopt, sizeof(sopt));
	sopt.sopt_dir = SOPT_SET;
	sopt.sopt_level = SOL_SOCKET;
	sopt.sopt_name = SO_RCVTIMEO;
	sopt.sopt_val = &tv;
	sopt.sopt_valsize = sizeof tv;

	error = sosetopt(so, &sopt);
	if (error != 0)
		goto out;

	/*
	 * Enable broadcast.
	 */
	on = 1;
	sopt.sopt_name = SO_BROADCAST;
	sopt.sopt_val = &on;
	sopt.sopt_valsize = sizeof on;

	error = sosetopt(so, &sopt);
	if (error != 0)
		goto out;

	/*
	 * Disable routing.
	 */

	on = 1;
	sopt.sopt_name = SO_DONTROUTE;
	sopt.sopt_val = &on;
	sopt.sopt_valsize = sizeof on;

	error = sosetopt(so, &sopt);
	if (error != 0)
		goto out;

	/*
	 * Bind the local endpoint to a bootp client port.
	 */
	sin = &dst;
	clear_sinaddr(sin);
	sin->sin_port = htons(IPPORT_BOOTPC);
	error = sobind(so, (struct sockaddr *)sin, td);
	if (error != 0) {
		printf("bind failed\n");
		goto out;
	}

	/*
	 * Setup socket address for the server.
	 */
	sin = &dst;
	clear_sinaddr(sin);
	sin->sin_addr.s_addr = INADDR_BROADCAST;
	sin->sin_port = htons(IPPORT_BOOTPS);

	/*
	 * Send it, repeatedly, until a reply is received,
	 * but delay each re-send by an increasing amount.
	 * If the delay hits the maximum, start complaining.
	 */
	timo = 0;
	rtimo = 0;
	for (;;) {

		outstanding = 0;
		gotrootpath = 0;

		for (ifctx = gctx->interfaces;
		     ifctx != NULL;
		     ifctx = ifctx->next) {
			if (bootpc_ifctx_isresolved(ifctx) != 0 &&
			    bootpc_tag(&gctx->tmptag, &ifctx->reply,
				       ifctx->replylen,
				       TAG_ROOT) != NULL)
				gotrootpath = 1;
		}

		for (ifctx = gctx->interfaces;
		     ifctx != NULL;
		     ifctx = ifctx->next) {
			ifctx->outstanding = 0;
			if (bootpc_ifctx_isresolved(ifctx)  != 0 &&
			    gotrootpath != 0) {
				continue;
			}
			if (bootpc_ifctx_isfailed(ifctx) != 0)
				continue;

			outstanding++;
			ifctx->outstanding = 1;

			/* Proceed to next step in DHCP negotiation */
			if ((ifctx->state == IF_DHCP_OFFERED &&
			     ifctx->dhcpquerytype != DHCP_REQUEST) ||
			    (ifctx->state == IF_DHCP_UNRESOLVED &&
			     ifctx->dhcpquerytype != DHCP_DISCOVER) ||
			    (ifctx->state == IF_BOOTP_UNRESOLVED &&
			     ifctx->dhcpquerytype != DHCP_NOMSG)) {
				ifctx->sentmsg = 0;
				bootpc_compose_query(ifctx, gctx, td);
			}

			/* Send BOOTP request (or re-send). */

			if (ifctx->sentmsg == 0) {
				switch(ifctx->dhcpquerytype) {
				case DHCP_DISCOVER:
					s = "DHCP Discover";
					break;
				case DHCP_REQUEST:
					s = "DHCP Request";
					break;
				case DHCP_NOMSG:
				default:
					s = "BOOTP Query";
					break;
				}
				printf("Sending %s packet from "
				       "interface %s (%*D)\n",
				       s,
				       ifctx->ireq.ifr_name,
				       ifctx->sdl->sdl_alen,
				       (unsigned char *) LLADDR(ifctx->sdl),
				       ":");
				ifctx->sentmsg = 1;
			}

			aio.iov_base = (caddr_t) &ifctx->call;
			aio.iov_len = sizeof(ifctx->call);

			auio.uio_iov = &aio;
			auio.uio_iovcnt = 1;
			auio.uio_segflg = UIO_SYSSPACE;
			auio.uio_rw = UIO_WRITE;
			auio.uio_offset = 0;
			auio.uio_resid = sizeof(ifctx->call);
			auio.uio_td = td;

			/* Set netmask to 0.0.0.0 */

			sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
			clear_sinaddr(sin);
			error = ifioctl(ifctx->so, SIOCSIFNETMASK,
					(caddr_t) &ifctx->ireq, td);
			if (error != 0)
				panic("bootpc_call:"
				      "set if netmask, error=%d",
				      error);

			error = sosend(so, (struct sockaddr *) &dst,
				       &auio, NULL, NULL, 0, td);
			if (error != 0) {
				printf("bootpc_call: sosend: %d state %08x\n",
				       error, (int) so->so_state);
			}

			/* XXX: Is this needed ? */
			pause("bootpw", hz/10);

			/* Set netmask to 255.0.0.0 */

			sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
			clear_sinaddr(sin);
			sin->sin_addr.s_addr = htonl(0xff000000u);
			error = ifioctl(ifctx->so, SIOCSIFNETMASK,
					(caddr_t) &ifctx->ireq, td);
			if (error != 0)
				panic("bootpc_call:"
				      "set if netmask, error=%d",
				      error);

		}

		if (outstanding == 0 &&
		    (rtimo == 0 || time_second >= rtimo)) {
			error = 0;
			goto gotreply;
		}

		/* Determine new timeout. */
		if (timo < MAX_RESEND_DELAY)
			timo++;
		else {
			printf("DHCP/BOOTP timeout for server ");
			print_sin_addr(&dst);
			printf("\n");
		}

		/*
		 * Wait for up to timo seconds for a reply.
		 * The socket receive timeout was set to 1 second.
		 */
		atimo = timo + time_second;
		while (time_second < atimo) {
			aio.iov_base = (caddr_t) &gctx->reply;
			aio.iov_len = sizeof(gctx->reply);

			auio.uio_iov = &aio;
			auio.uio_iovcnt = 1;
			auio.uio_segflg = UIO_SYSSPACE;
			auio.uio_rw = UIO_READ;
			auio.uio_offset = 0;
			auio.uio_resid = sizeof(gctx->reply);
			auio.uio_td = td;

			rcvflg = 0;
			error = soreceive(so, NULL, &auio,
					  NULL, NULL, &rcvflg);
			gctx->secs = time_second - gctx->starttime;
			for (ifctx = gctx->interfaces;
			     ifctx != NULL;
			     ifctx = ifctx->next) {
				if (bootpc_ifctx_isresolved(ifctx) != 0 ||
				    bootpc_ifctx_isfailed(ifctx) != 0)
					continue;

				ifctx->call.secs = htons(gctx->secs);
			}
			if (error == EWOULDBLOCK)
				continue;
			if (error != 0)
				goto out;
			len = sizeof(gctx->reply) - auio.uio_resid;

			/* Do we have the required number of bytes ? */
			if (len < BOOTP_MIN_LEN)
				continue;
			gctx->replylen = len;

			/* Is it a reply? */
			if (gctx->reply.op != BOOTP_REPLY)
				continue;

			/* Is this an answer to our query */
			for (ifctx = gctx->interfaces;
			     ifctx != NULL;
			     ifctx = ifctx->next) {
				if (gctx->reply.xid != ifctx->call.xid)
					continue;

				/* Same HW address size ? */
				if (gctx->reply.hlen != ifctx->call.hlen)
					continue;

				/* Correct HW address ? */
				if (bcmp(gctx->reply.chaddr,
					 ifctx->call.chaddr,
					 ifctx->call.hlen) != 0)
					continue;

				break;
			}

			if (ifctx != NULL) {
				s =  bootpc_tag(&gctx->tmptag,
						&gctx->reply,
						gctx->replylen,
						TAG_DHCP_MSGTYPE);
				if (s != NULL) {
					switch (*s) {
					case DHCP_OFFER:
						s = "DHCP Offer";
						break;
					case DHCP_ACK:
						s = "DHCP Ack";
						break;
					default:
						s = "DHCP (unexpected)";
						break;
					}
				} else
					s = "BOOTP Reply";

				printf("Received %s packet"
				       " on %s from ",
				       s,
				       ifctx->ireq.ifr_name);
				print_in_addr(gctx->reply.siaddr);
				if (gctx->reply.giaddr.s_addr !=
				    htonl(INADDR_ANY)) {
					printf(" via ");
					print_in_addr(gctx->reply.giaddr);
				}
				if (bootpc_received(gctx, ifctx) != 0) {
					printf(" (accepted)");
					if (ifctx->outstanding) {
						ifctx->outstanding = 0;
						outstanding--;
					}
					/* Network settle delay */
					if (outstanding == 0)
						atimo = time_second +
							BOOTP_SETTLE_DELAY;
				} else
					printf(" (ignored)");
				if (ifctx->gotrootpath) {
					gotrootpath = 1;
					rtimo = time_second +
						BOOTP_SETTLE_DELAY;
					printf(" (got root path)");
				} else
					printf(" (no root path)");
				printf("\n");
			}
		} /* while secs */
#ifdef BOOTP_TIMEOUT
		if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
			break;
#endif
		/* Force a retry if halfway in DHCP negotiation */
		retry = 0;
		for (ifctx = gctx->interfaces; ifctx != NULL;
		     ifctx = ifctx->next) {
			if (ifctx->state == IF_DHCP_OFFERED) {
				if (ifctx->dhcpquerytype == DHCP_DISCOVER)
					retry = 1;
				else
					ifctx->state = IF_DHCP_UNRESOLVED;
			}
		}

		if (retry != 0)
			continue;

		if (gotrootpath != 0) {
			gctx->gotrootpath = gotrootpath;
			if (rtimo != 0 && time_second >= rtimo)
				break;
		}
	} /* forever send/receive */

	/*
	 * XXX: These are errors of varying seriousness being silently
	 * ignored
	 */

	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
		if (bootpc_ifctx_isresolved(ifctx) == 0) {
			printf("%s timeout for interface %s\n",
			       ifctx->dhcpquerytype != DHCP_NOMSG ?
			       "DHCP" : "BOOTP",
			       ifctx->ireq.ifr_name);
		}
	}
	if (gctx->gotrootpath != 0) {
#if 0
		printf("Got a root path, ignoring remaining timeout\n");
#endif
		error = 0;
		goto out;
	}
#ifndef BOOTP_NFSROOT
	for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
		if (bootpc_ifctx_isresolved(ifctx) != 0) {
			error = 0;
			goto out;
		}
	}
#endif
	error = ETIMEDOUT;
	goto out;

gotreply:
out:
	soclose(so);
out0:
	return error;
}
Exemplo n.º 21
0
static int 
bsd_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    return (sosend((struct socket *)fp->f_data, (struct sockaddr *)0,
                   uio, (struct mbuf *)0, (struct mbuf *)0, 0, 0));
}
Exemplo n.º 22
0
int
t_send(long s, 
   char *   buf,
   int      len, 
   int      flags)
{
   struct socket *   so;
   int   e;       /* error holder */
   int   total_sent  =  0;
   int   maxpkt;
   int   sendlen;
   int   sent;

   so = LONG2SO(s);
#ifdef SOC_CHECK_ALWAYS
   SOC_CHECK(so);
#endif
   if ((so->so_state & SO_IO_OK) != SS_ISCONNECTED)
   {
      so->so_error = EPIPE;
      return SOCKET_ERROR;
   }
   so->so_error = 0;

   /* If this is not a stream socket, assume it is bound and pass to
    * t_sendto() with a null sockaddr
    */
   if (so->so_type != SOCK_STREAM)
      return(t_sendto(s, buf, len, flags, NULL, 0));

   maxpkt = TCP_MSS;
   if(so->so_pcb)
   { 
      struct tcpcb * tp;
      tp = intotcpcb(so->so_pcb);   /* get tcp structure with mss */
      if(tp->t_maxseg)              /* Make sure it's set */
         maxpkt = tp->t_maxseg;
   }

   IN_PROFILER(PF_TCP, PF_ENTRY);       /* measure time in TCP */

   while (len)
   {
      if (len > maxpkt)
         sendlen = maxpkt;  /* take biggest block we can */
      else
         sendlen = len;
      sent = sendlen;

      LOCK_NET_RESOURCE(NET_RESID);
      e = sosend (so, NULL, buf, &sendlen, flags);
      UNLOCK_NET_RESOURCE(NET_RESID);
 
      if (e != 0)  /* sock_sendit failed? */
      {
         /* if we simply ran out of bufs, report back to caller. */
         if ((e == ENOBUFS) || (e == EWOULDBLOCK))
         {
            /* if we actually sent something before running out
             * of buffers, report what we sent; 
             * else, report the error and let the application 
             * retry the call later
             */
            if (total_sent != 0)
            {
               so->so_error = 0;
               break;      /* break out of while(len) loop */
            }
         }
         so->so_error = e;
         return SOCKET_ERROR;
      }
      /* if we can't send anymore, return now */
      if (sendlen != 0)
         break;         /* break out of while(len) loop */

      /* adjust numbers & pointers, and go do next send loop */
      sent -= sendlen;        /* subtract anything that didn't get sent */
      buf += sent;
      len -= sent;
      total_sent += sent;
   }

   IN_PROFILER(PF_TCP, PF_EXIT);        /* measure time in TCP */
   return total_sent;
}
Exemplo n.º 23
0
int
t_sendto (long s, 
   char *   buf,
   int   len, 
   int   flags,
   struct sockaddr * to,
   int   tolen)
{
   struct socket *   so;
   int   sendlen;
   int   err;
   struct mbuf *     name;

   so = LONG2SO(s);
   SOC_CHECK(so);
   so->so_error = 0;

   switch (so->so_type)
   {
   case SOCK_STREAM:
      /* this is a stream socket, so pass this request through
       * t_send() for its large-send support.
       */
      return t_send(s, buf, len, flags);
      /*NOTREACHED*/
   case SOCK_DGRAM:
      /* datagram (UDP) socket -- prepare to check length */
      sendlen = udp_maxalloc();
      break;
#ifdef IP_RAW
   case SOCK_RAW:
      /* raw socket -- prepare to check length */
      sendlen = ip_raw_maxalloc(so->so_options & SO_HDRINCL);
      break;
#endif /* IP_RAW */
   default:
      /* socket has unknown type */
      dtrap();
      so->so_error = EFAULT;
      return SOCKET_ERROR;
      /*NOTREACHED*/
   }

   /* fall through for non-stream sockets: SOCK_DGRAM (UDP) and
    * SOCK_RAW (raw IP)
    */

   /* check length against underlying stack's maximum */
   if (len > sendlen)
   {
      so->so_error = EMSGSIZE;
      return SOCKET_ERROR;
   }

   /* if a sockaddr was passed, wrap it in an mbuf and pas it into the
    * bowels of the BSD code; else assume this is a bound UDP socket
    * and this call came from t_send() below.
    */

   if (to)  /* sockaddr was passed */
   {
      name = sockargs(to, tolen, MT_SONAME);
      if(name == NULL)
      {
         so->so_error = ENOMEM;
         return SOCKET_ERROR;
      }
   }
   else     /* hope user called bind() first... */
      name = NULL;
   
   sendlen = len;

   LOCK_NET_RESOURCE(NET_RESID);

   err = sosend (so, name, buf, &sendlen, flags);

   if (name)
      m_freem(name);

   UNLOCK_NET_RESOURCE(NET_RESID);

   if (err != 0)
   {
      so->so_error = err;
      return SOCKET_ERROR;
   }

   return (len - sendlen);
}
Exemplo n.º 24
0
int
sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
{
	struct file *fp;
	struct uio auio;
	struct iovec *iov;
	int i;
	struct mbuf *to, *control;
	size_t len;
	int error;
#ifdef KTRACE
	struct iovec *ktriov = NULL;
#endif

	to = NULL;

	if ((error = getsock(p->p_fd, s, &fp)) != 0)
		return (error);
	auio.uio_iov = mp->msg_iov;
	auio.uio_iovcnt = mp->msg_iovlen;
	auio.uio_segflg = UIO_USERSPACE;
	auio.uio_rw = UIO_WRITE;
	auio.uio_procp = p;
	auio.uio_offset = 0;			/* XXX */
	auio.uio_resid = 0;
	iov = mp->msg_iov;
	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
		/* Don't allow sum > SSIZE_MAX */
		if (iov->iov_len > SSIZE_MAX ||
		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
			error = EINVAL;
			goto bad;
		}
	}
	if (mp->msg_name) {
		error = sockargs(&to, mp->msg_name, mp->msg_namelen,
		    MT_SONAME);
		if (error)
			goto bad;
#ifdef KTRACE
		if (KTRPOINT(p, KTR_STRUCT))
		 	ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen);
#endif
	}
	if (mp->msg_control) {
		if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) {
			error = EINVAL;
			goto bad;
		}
		error = sockargs(&control, mp->msg_control,
		    mp->msg_controllen, MT_CONTROL);
		if (error)
			goto bad;
	} else
		control = 0;
#ifdef KTRACE
	if (KTRPOINT(p, KTR_GENIO)) {
		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);

		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
		bcopy(auio.uio_iov, ktriov, iovlen);
	}
#endif
	len = auio.uio_resid;
	error = sosend(fp->f_data, to, &auio, NULL, control, flags);
	if (error) {
		if (auio.uio_resid != len && (error == ERESTART ||
		    error == EINTR || error == EWOULDBLOCK))
			error = 0;
		if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0)
			ptsignal(p, SIGPIPE, STHREAD);
	}
	if (error == 0) {
		*retsize = len - auio.uio_resid;
		fp->f_wxfer++;
		fp->f_wbytes += *retsize;
	}
#ifdef KTRACE
	if (ktriov != NULL) {
		if (error == 0)
			ktrgenio(p, s, UIO_WRITE, ktriov, *retsize);
		free(ktriov, M_TEMP);
	}
#endif
bad:
	FRELE(fp, p);
	if (to)
		m_freem(to);
	return (error);
}
Exemplo n.º 25
0
int
isc_sendPDU(isc_session_t *sp, pduq_t *pq)
{
     struct mbuf *mh, **mp;
     pdu_t		*pp = &pq->pdu;
     int		len, error;

     debug_called(8);
     /*
      | mbuf for the iSCSI header
      */
     MGETHDR(mh, MB_TRYWAIT, MT_DATA);
     mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u);
     mh->m_pkthdr.rcvif = NULL;
     MH_ALIGN(mh, sizeof(union ipdu_u));
     bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u));
     mh->m_next = NULL;

     if(sp->hdrDigest)
	  pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
     if(pp->ahs_len) {
          /*
	   | Add any AHS to the iSCSI hdr mbuf
           |  XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN
	   */
          bcopy(pp->ahs, (mh->m_data + mh->m_len), pp->ahs_len);
          mh->m_len += pp->ahs_len;
          mh->m_pkthdr.len += pp->ahs_len;

	  if(sp->hdrDigest)
	       pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
     }
     if(sp->hdrDigest) {
	  debug(2, "hdr_dig=%x", pq->pdu.hdr_dig);
          /*
	   | Add header digest to the iSCSI hdr mbuf
	   | XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN
	   */
          bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int));
          mh->m_len += sizeof(int);
          mh->m_pkthdr.len += sizeof(int);
     }
     mp = &mh->m_next;
     if(pq->pdu.ds) {
          struct mbuf   *md;
          int           off = 0;

          len = pp->ds_len;
	  while(len & 03) // the specs say it must be int alligned
	       len++;
          while(len > 0) {
                int       l;

	       MGET(md, MB_TRYWAIT, MT_DATA);
	       pq->refcnt++;

                l = min(MCLBYTES, len);
	       debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
	       md->m_ext.ext_buf = pq->buf;
	       md->m_ext.ext_free = ext_free;
	       md->m_ext.ext_ref = ext_ref;
	       md->m_ext.ext_arg = pq;
	       md->m_ext.ext_size = l;
	       md->m_flags |= M_EXT;
	       md->m_data = pp->ds + off;
	       md->m_len = l;
	       md->m_next = NULL;
	       mh->m_pkthdr.len += l;
	       *mp = md;
	       mp = &md->m_next;
	       len -= l;
	       off += l;
          }
     }
     if(sp->dataDigest) {
          struct mbuf   *me;

	  pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);

	  MGET(me, MB_TRYWAIT, MT_DATA);
          me->m_len = sizeof(int);
          MH_ALIGN(mh, sizeof(int));
          bcopy(&pp->ds_dig, me->m_data, sizeof(int));
          me->m_next = NULL;
          mh->m_pkthdr.len += sizeof(int);
          *mp = me;
     }
     if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, curthread)) != 0) {
	  sdebug(3, "error=%d", error);
	  return error;
     }
     sp->stats.nsent++;
     getmicrouptime(&sp->stats.t_sent);
     return 0;
}
Exemplo n.º 26
0
/*
 * XXX Liang: timeout for write is not supported yet.
 */
int
libcfs_sock_write (struct socket *sock, void *buffer, int nob, int timeout)
{
        int            rc;
        CFS_DECL_NET_DATA;

        while (nob > 0) {
                struct iovec  iov = {
                        .iov_base = buffer,
                        .iov_len  = nob
                };
                struct  uio suio = {
                        .uio_iov        = &iov,
                        .uio_iovcnt     = 1,
                        .uio_offset     = 0,
                        .uio_resid      = nob,
                        .uio_segflg     = UIO_SYSSPACE,
                        .uio_rw         = UIO_WRITE,
                        .uio_procp      = NULL
                };
                                
                CFS_NET_IN;
                rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, 0);
                CFS_NET_EX;
                                
                if (rc != 0) {
                        if ( suio.uio_resid != nob && ( rc == ERESTART || rc == EINTR ||\
                             rc == EWOULDBLOCK))
                        rc = 0;
                        if ( rc != 0 )
                                return -rc;
                        rc = nob - suio.uio_resid;
                        buffer = ((char *)buffer) + rc;
                        nob = suio.uio_resid;
                        continue;
                }
                break;
        }
        return (0);
}

/*
 * XXX Liang: timeout for read is not supported yet.
 */
int
libcfs_sock_read (struct socket *sock, void *buffer, int nob, int timeout)
{
        int            rc;
        CFS_DECL_NET_DATA;

        while (nob > 0) {
                struct iovec  iov = {
                        .iov_base = buffer,
                        .iov_len  = nob
                };
                struct uio  ruio = {
                        .uio_iov        = &iov,
                        .uio_iovcnt     = 1,
                        .uio_offset     = 0,
                        .uio_resid      = nob,
                        .uio_segflg     = UIO_SYSSPACE,
                        .uio_rw         = UIO_READ,
                        .uio_procp      = NULL
                };
                
                CFS_NET_IN;
                rc = soreceive(sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, (int *)0);
                CFS_NET_EX;
                
                if (rc != 0) {
                        if ( ruio.uio_resid != nob && ( rc == ERESTART || rc == EINTR ||\
                                rc == EWOULDBLOCK))
                                rc = 0;
                        if (rc != 0)
                                return -rc;
                        rc = nob - ruio.uio_resid;
                        buffer = ((char *)buffer) + rc;
                        nob = ruio.uio_resid;
                        continue;
                }
                break;
        }
        return (0);
}

int
libcfs_sock_setbuf (struct socket *sock, int txbufsize, int rxbufsize)
{
        struct sockopt  sopt;
        int             rc = 0;
        int             option;
        CFS_DECL_NET_DATA;

        bzero(&sopt, sizeof sopt);
        sopt.sopt_dir = SOPT_SET;
        sopt.sopt_level = SOL_SOCKET;
        sopt.sopt_val = &option;
        sopt.sopt_valsize = sizeof(option);

        if (txbufsize != 0) {
                option = txbufsize;
                if (option > KSOCK_MAX_BUF)
                        option = KSOCK_MAX_BUF;
        
                sopt.sopt_name = SO_SNDBUF;
                CFS_NET_IN;
                rc = sosetopt(sock, &sopt);
                CFS_NET_EX;
                if (rc != 0) {
                        CERROR ("Can't set send buffer %d: %d\n",
                                option, rc);
                        
                        return -rc;
                }
        }
                
        if (rxbufsize != 0) {
                option = rxbufsize;
                sopt.sopt_name = SO_RCVBUF;
                CFS_NET_IN;
                rc = sosetopt(sock, &sopt);
                CFS_NET_EX;
                if (rc != 0) {
                        CERROR ("Can't set receive buffer %d: %d\n",
                                option, rc);
                        return -rc;
                }
        }
        return 0;
}

int
libcfs_sock_getaddr (struct socket *sock, int remote, __u32 *ip, int *port)
{
        struct sockaddr_in *sin;
        struct sockaddr    *sa = NULL;
        int                rc;
        CFS_DECL_NET_DATA;

        if (remote != 0) {
                CFS_NET_IN;
                rc = sock->so_proto->pr_usrreqs->pru_peeraddr(sock, &sa);
                CFS_NET_EX;

                if (rc != 0) {
                        if (sa) FREE(sa, M_SONAME);
                        CERROR ("Error %d getting sock peer IP\n", rc);
                        return -rc;
                }
        } else {
                CFS_NET_IN;
                rc = sock->so_proto->pr_usrreqs->pru_sockaddr(sock, &sa);
                CFS_NET_EX;
                if (rc != 0) {
                        if (sa) FREE(sa, M_SONAME);
                        CERROR ("Error %d getting sock local IP\n", rc);
                        return -rc;
                }
        }
        if (sa != NULL) {
                sin = (struct sockaddr_in *)sa;
                if (ip != NULL)
                        *ip = ntohl (sin->sin_addr.s_addr);
                if (port != NULL)
                        *port = ntohs (sin->sin_port);
                if (sa) 
                        FREE(sa, M_SONAME);
        }
        return 0;
}

int
libcfs_sock_getbuf (struct socket *sock, int *txbufsize, int *rxbufsize)
{
        struct sockopt  sopt;
        int rc;
        CFS_DECL_NET_DATA;

        bzero(&sopt, sizeof sopt);
        sopt.sopt_dir = SOPT_GET;
        sopt.sopt_level = SOL_SOCKET;

        if (txbufsize != NULL) {
                sopt.sopt_val = txbufsize;
                sopt.sopt_valsize = sizeof(*txbufsize);
                sopt.sopt_name = SO_SNDBUF;
                CFS_NET_IN;
                rc = sogetopt(sock, &sopt);
                CFS_NET_EX;
                if (rc != 0) {
                        CERROR ("Can't get send buffer size: %d\n", rc);
                        return -rc;
                }
        }

        if (rxbufsize != NULL) {
                sopt.sopt_val = rxbufsize;
                sopt.sopt_valsize = sizeof(*rxbufsize);
                sopt.sopt_name = SO_RCVBUF;
                CFS_NET_IN;
                rc = sogetopt(sock, &sopt);
                CFS_NET_EX;
                if (rc != 0) {
                        CERROR ("Can't get receive buffer size: %d\n", rc);
                        return -rc;
                }
        }
        return 0;
}

int
libcfs_sock_connect (struct socket **sockp, int *fatal,
                     __u32 local_ip, int local_port,
                     __u32 peer_ip, int peer_port)
{
        struct sockaddr_in  srvaddr;
        struct socket      *so;
        int                 s;
        int                 rc; 
        CFS_DECL_FUNNEL_DATA;
        
        rc = libcfs_sock_create(sockp, fatal, local_ip, local_port);
        if (rc != 0)
                return rc;
        so = *sockp;
        bzero(&srvaddr, sizeof(srvaddr));
        srvaddr.sin_len = sizeof(struct sockaddr_in);
        srvaddr.sin_family = AF_INET;
        srvaddr.sin_port = htons (peer_port);
        srvaddr.sin_addr.s_addr = htonl (peer_ip);

        CFS_NET_IN;
        rc = soconnect(so, (struct sockaddr *)&srvaddr);
        if (rc != 0) {
                CFS_NET_EX;
                if (rc != EADDRNOTAVAIL && rc != EADDRINUSE)
                        CDEBUG(D_NETERROR,
                               "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc,
                               HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port);
                goto out;
        }
        s = splnet();
        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
                CDEBUG(D_NET, "ksocknal sleep for waiting auto_connect.\n");
                (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ksocknal_conn", hz);
        }
        if ((rc = so->so_error) != 0) {
                so->so_error = 0;
                splx(s);
                CFS_NET_EX;
                CDEBUG(D_NETERROR,
                       "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc,
                       HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port);
                goto out;
        }
        LASSERT(so->so_state & SS_ISCONNECTED);
        splx(s);
        CFS_NET_EX;
        if (sockp)
                *sockp = so;
        return (0);
out:
        CFS_NET_IN;
        soshutdown(so, 2);
        soclose(so);
        CFS_NET_EX;
        return (-rc);
}

void
libcfs_sock_release (struct socket *sock)
{
        CFS_DECL_FUNNEL_DATA;
        CFS_NET_IN;
        soshutdown(sock, 0);
        CFS_NET_EX;
}
Exemplo n.º 27
0
/*
 * portal_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
 *	       struct file *a_fp)
 */
static int
portal_open(struct vop_open_args *ap)
{
	struct socket *so = 0;
	struct portalnode *pt;
	struct thread *td = curthread;
	struct vnode *vp = ap->a_vp;
	struct uio auio;
	struct iovec aiov[2];
	struct sockbuf sio;
	int res;
	struct mbuf *cm = 0;
	struct cmsghdr *cmsg;
	int newfds;
	int *ip;
	int fd;
	int error;
	int len;
	struct portalmount *fmp;
	struct file *fp;
	struct portal_cred pcred;

	/*
	 * Nothing to do when opening the root node.
	 */
	if (vp->v_flag & VROOT)
		return (vop_stdopen(ap));

	/*
	 * Can't be opened unless the caller is set up
	 * to deal with the side effects.  Check for this
	 * by testing whether the p_dupfd has been set.
	 */
	KKASSERT(td->td_proc);
	if (td->td_lwp->lwp_dupfd >= 0)
		return (ENODEV);

	pt = VTOPORTAL(vp);
	fmp = VFSTOPORTAL(vp->v_mount);

	/*
	 * Create a new socket.
	 */
	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0, td);
	if (error)
		goto bad;

	/*
	 * Reserve some buffer space
	 */
	res = pt->pt_size + sizeof(pcred) + 512;	/* XXX */
	error = soreserve(so, res, res, &td->td_proc->p_rlimit[RLIMIT_SBSIZE]);
	if (error)
		goto bad;

	/*
	 * Kick off connection
	 */
	error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
	if (error)
		goto bad;

	/*
	 * Wait for connection to complete
	 */
	/*
	 * XXX: Since the mount point is holding a reference on the
	 * underlying server socket, it is not easy to find out whether
	 * the server process is still running.  To handle this problem
	 * we loop waiting for the new socket to be connected (something
	 * which will only happen if the server is still running) or for
	 * the reference count on the server socket to drop to 1, which
	 * will happen if the server dies.  Sleep for 5 second intervals
	 * and keep polling the reference count.   XXX.
	 */
	crit_enter();
	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
		if (fmp->pm_server->f_count == 1) {
			error = ECONNREFUSED;
			crit_exit();
			goto bad;
		}
		(void) tsleep((caddr_t) &so->so_timeo, 0, "portalcon", 5 * hz);
	}
	crit_exit();

	if (so->so_error) {
		error = so->so_error;
		goto bad;
	}

	/*
	 * Set miscellaneous flags
	 */
	so->so_rcv.ssb_timeo = 0;
	so->so_snd.ssb_timeo = 0;
	atomic_set_int(&so->so_rcv.ssb_flags, SSB_NOINTR);
	atomic_set_int(&so->so_snd.ssb_flags, SSB_NOINTR);


	pcred.pcr_flag = ap->a_mode;
	pcred.pcr_uid = ap->a_cred->cr_uid;
	pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
	aiov[0].iov_base = (caddr_t) &pcred;
	aiov[0].iov_len = sizeof(pcred);
	aiov[1].iov_base = pt->pt_arg;
	aiov[1].iov_len = pt->pt_size;
	auio.uio_iov = aiov;
	auio.uio_iovcnt = 2;
	auio.uio_rw = UIO_WRITE;
	auio.uio_segflg = UIO_SYSSPACE;
	auio.uio_td = td;
	auio.uio_offset = 0;
	auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;

	error = sosend(so, NULL, &auio, NULL, NULL, 0, td);
	if (error)
		goto bad;

	len = sizeof(int);
	sbinit(&sio, len);
	do {
		struct mbuf *m;
		int flags;

		flags = MSG_WAITALL;
		error = soreceive(so, NULL, NULL, &sio, &cm, &flags);
		if (error)
			goto bad;

		/*
		 * Grab an error code from the mbuf.
		 */
		if ((m = sio.sb_mb) != NULL) {
			m = m_pullup(m, sizeof(int));	/* Needed? */
			if (m) {
				error = *(mtod(m, int *));
				m_freem(m);
			} else {
				error = EINVAL;
			}
		} else {
Exemplo n.º 28
0
/*
 * Do a remote procedure call (RPC) and wait for its reply.
 * If from_p is non-null, then we are doing broadcast, and
 * the address from whence the response came is saved there.
 * data:	input/output
 * from_p:	output
 */
int
krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func,
    struct mbuf **data, struct mbuf **from_p, int retries)
{
	struct socket *so;
	struct sockaddr_in *sin;
	struct mbuf *m, *nam, *mhead, *from, *mopt;
	struct rpc_call *call;
	struct rpc_reply *reply;
	struct uio auio;
	int error, rcvflg, timo, secs, len;
	static u_int32_t xid = 0;
	char addr[INET_ADDRSTRLEN];
	int *ip;
	struct timeval tv;

	/*
	 * Validate address family.
	 * Sorry, this is INET specific...
	 */
	if (sa->sin_family != AF_INET)
		return (EAFNOSUPPORT);

	/* Free at end if not null. */
	nam = mhead = NULL;
	from = NULL;

	/*
	 * Create socket and set its receive timeout.
	 */
	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
		goto out;

	m = m_get(M_WAIT, MT_SOOPTS);
	tv.tv_sec = 1;
	tv.tv_usec = 0;
	memcpy(mtod(m, struct timeval *), &tv, sizeof tv);
	m->m_len = sizeof(tv);
	if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
		goto out;

	/*
	 * Enable broadcast if necessary.
	 */
	if (from_p) {
		int32_t *on;
		m = m_get(M_WAIT, MT_SOOPTS);
		on = mtod(m, int32_t *);
		m->m_len = sizeof(*on);
		*on = 1;
		if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
			goto out;
	}

	/*
	 * Bind the local endpoint to a reserved port,
	 * because some NFS servers refuse requests from
	 * non-reserved (non-privileged) ports.
	 */
	MGET(mopt, M_WAIT, MT_SOOPTS);
	mopt->m_len = sizeof(int);
	ip = mtod(mopt, int *);
	*ip = IP_PORTRANGE_LOW;
	error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
	if (error)
		goto out;

	MGET(m, M_WAIT, MT_SONAME);
	sin = mtod(m, struct sockaddr_in *);
	sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
	sin->sin_family = AF_INET;
	sin->sin_addr.s_addr = INADDR_ANY;
	sin->sin_port = htons(0);
	error = sobind(so, m, &proc0);
	m_freem(m);
	if (error) {
		printf("bind failed\n");
		goto out;
	}

	MGET(mopt, M_WAIT, MT_SOOPTS);
	mopt->m_len = sizeof(int);
	ip = mtod(mopt, int *);
	*ip = IP_PORTRANGE_DEFAULT;
	error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
	if (error)
		goto out;

	/*
	 * Setup socket address for the server.
	 */
	nam = m_get(M_WAIT, MT_SONAME);
	sin = mtod(nam, struct sockaddr_in *);
	bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len));

	/*
	 * Prepend RPC message header.
	 */
	mhead = m_gethdr(M_WAIT, MT_DATA);
	mhead->m_next = *data;
	call = mtod(mhead, struct rpc_call *);
	mhead->m_len = sizeof(*call);
	bzero((caddr_t)call, sizeof(*call));
	/* rpc_call part */
	xid = krpc_get_xid();
	call->rp_xid = txdr_unsigned(xid);
	/* call->rp_direction = 0; */
	call->rp_rpcvers = txdr_unsigned(2);
	call->rp_prog = txdr_unsigned(prog);
	call->rp_vers = txdr_unsigned(vers);
	call->rp_proc = txdr_unsigned(func);
	/* rpc_auth part (auth_unix as root) */
	call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX);
	call->rpc_auth.authlen  = txdr_unsigned(sizeof(struct auth_unix));
	/* rpc_verf part (auth_null) */
	call->rpc_verf.authtype = 0;
	call->rpc_verf.authlen  = 0;

	/*
	 * Setup packet header
	 */
	len = 0;
	m = mhead;
	while (m) {
		len += m->m_len;
		m = m->m_next;
	}
	mhead->m_pkthdr.len = len;
	mhead->m_pkthdr.rcvif = NULL;

	/*
	 * Send it, repeatedly, until a reply is received,
	 * but delay each re-send by an increasing amount.
	 * If the delay hits the maximum, start complaining.
	 */
	for (timo = 0; retries; retries--) {
		/* Send RPC request (or re-send). */
		m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
		if (m == NULL) {
			error = ENOBUFS;
			goto out;
		}
		error = sosend(so, nam, NULL, m, NULL, 0);
		if (error) {
			printf("krpc_call: sosend: %d\n", error);
			goto out;
		}
		m = NULL;

		/* Determine new timeout. */
		if (timo < MAX_RESEND_DELAY)
			timo++;
		else
			printf("RPC timeout for server %s (0x%x) prog %u\n",
			    inet_ntop(AF_INET, &sin->sin_addr,
				addr, sizeof(addr)),
			    ntohl(sin->sin_addr.s_addr), prog);

		/*
		 * Wait for up to timo seconds for a reply.
		 * The socket receive timeout was set to 1 second.
		 */
		secs = timo;
		while (secs > 0) {
			if (from) {
				m_freem(from);
				from = NULL;
			}
			if (m) {
				m_freem(m);
				m = NULL;
			}
			auio.uio_resid = len = 1<<16;
			auio.uio_procp = NULL;
			rcvflg = 0;
			error = soreceive(so, &from, &auio, &m, NULL, &rcvflg,
			    0);
			if (error == EWOULDBLOCK) {
				secs--;
				continue;
			}
			if (error)
				goto out;
			len -= auio.uio_resid;

			/* Does the reply contain at least a header? */
			if (len < MIN_REPLY_HDR)
				continue;
			if (m->m_len < MIN_REPLY_HDR)
				continue;
			reply = mtod(m, struct rpc_reply *);

			/* Is it the right reply? */
			if (reply->rp_direction != txdr_unsigned(RPC_REPLY))
				continue;

			if (reply->rp_xid != txdr_unsigned(xid))
				continue;

			/* Was RPC accepted? (authorization OK) */
			if (reply->rp_astatus != 0) {
				error = fxdr_unsigned(u_int32_t, reply->rp_errno);
				printf("rpc denied, error=%d\n", error);
				continue;
			}

			/* Did the call succeed? */
			if (reply->rp_status != 0) {
				error = fxdr_unsigned(u_int32_t, reply->rp_status);
				printf("rpc denied, status=%d\n", error);
				continue;
			}

			goto gotreply;	/* break two levels */

		} /* while secs */
	} /* forever send/receive */

	error = ETIMEDOUT;
	goto out;

 gotreply:

	/*
	 * Get RPC reply header into first mbuf,
	 * get its length, then strip it off.
	 */
	len = sizeof(*reply);
	if (m->m_len < len) {
		m = m_pullup(m, len);
		if (m == NULL) {
			error = ENOBUFS;
			goto out;
		}
	}
	reply = mtod(m, struct rpc_reply *);
	if (reply->rp_auth.authtype != 0) {
		len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
		len = (len + 3) & ~3; /* XXX? */
	}
	m_adj(m, len);

	/* result */
	*data = m;
	if (from_p && error == 0) {
		*from_p = from;
		from = NULL;
	}

 out:
	if (nam) m_freem(nam);
	if (mhead) m_freem(mhead);
	if (from) m_freem(from);
	soclose(so);
	return error;
}
Exemplo n.º 29
0
          /*
	   | Add header digest to the iSCSI hdr mbuf
	   | XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN
	   */
          bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int));
          mh->m_len += sizeof(int);
          mh->m_pkthdr.len += sizeof(int);
     }
     mp = &mh->m_next;
     if(pq->pdu.ds) {
          struct mbuf   *md;
          int           off = 0;

          len = pp->ds_len;
	  while(len & 03) // the specs say it must be int alligned
	       len++;
          while(len > 0) {
                int       l;

	       MGET(md, MB_TRYWAIT, MT_DATA);
	       pq->refcnt++;

                l = min(MCLBYTES, len);
	       debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
	       md->m_ext.ext_buf = pq->buf;
	       md->m_ext.ext_free = ext_free;
	       md->m_ext.ext_ref = ext_ref;
	       md->m_ext.ext_arg = pq;
	       md->m_ext.ext_size = l;
	       md->m_flags |= M_EXT;
	       md->m_data = pp->ds + off;
	       md->m_len = l;
	       md->m_next = NULL;
	       mh->m_pkthdr.len += l;
	       *mp = md;
	       mp = &md->m_next;
	       len -= l;
	       off += l;
          }
     }
     if(sp->dataDigest) {
          struct mbuf   *me;

	  pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);

	  MGET(me, MB_TRYWAIT, MT_DATA);
          me->m_len = sizeof(int);
          MH_ALIGN(mh, sizeof(int));
          bcopy(&pp->ds_dig, me->m_data, sizeof(int));
          me->m_next = NULL;
          mh->m_pkthdr.len += sizeof(int);
          *mp = me;
     }
     if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, curthread)) != 0) {
	  sdebug(3, "error=%d", error);
	  return error;
     }
     sp->stats.nsent++;
     getmicrouptime(&sp->stats.t_sent);
     return 0;
}
#else /* NO_USE_MBUF */
int
isc_sendPDU(isc_session_t *sp, pduq_t *pq)
{
     struct uio *uio = &pq->uio;
     struct iovec *iv;
     pdu_t	*pp = &pq->pdu;
     int	len, error;

     debug_called(8);

     bzero(uio, sizeof(struct uio));
     uio->uio_rw = UIO_WRITE;
     uio->uio_segflg = UIO_SYSSPACE;
     uio->uio_td = curthread;
     uio->uio_iov = iv = pq->iov;

     iv->iov_base = &pp->ipdu;
     iv->iov_len = sizeof(union ipdu_u);
     uio->uio_resid = pq->len;
     iv++;
     if(sp->hdrDigest)
	  pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
     if(pp->ahs_len) {
	  iv->iov_base = pp->ahs;
	  iv->iov_len = pp->ahs_len;
	  iv++;

	  if(sp->hdrDigest)
	       pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
     }
     if(sp->hdrDigest) {
	  debug(2, "hdr_dig=%x", pq->pdu.hdr_dig);
	  iv->iov_base = &pp->hdr_dig;
	  iv->iov_len = sizeof(int);
	  iv++;
     }
     if(pq->pdu.ds) {
	  iv->iov_base = pp->ds;
	  iv->iov_len = pp->ds_len;
	  while(iv->iov_len & 03) // the specs say it must be int alligned
	       iv->iov_len++;
	  iv++;
     }
     if(sp->dataDigest) {
	  pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
	  iv->iov_base = &pp->ds_dig;
	  iv->iov_len = sizeof(int);
	  iv++;
     }
     uio->uio_iovcnt	= iv - pq->iov;
     sdebug(5, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
	    pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid,
	    ntohl(pp->ipdu.bhs.itt));
     sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p",
	    sp, sp->soc, uio, sp->td);
     do {
	  len = uio->uio_resid;
	  error = sosend(sp->soc, NULL, uio, 0, 0, 0, curthread);
	  if(uio->uio_resid == 0 || error || len == uio->uio_resid) {
	       if(uio->uio_resid) {
		    sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d",
			   uio->uio_resid, uio->uio_iovcnt, error, len);
		    if(error == 0)
			 error = EAGAIN; // 35
	       }
	       break;
	  }
	  /*
	   | XXX: untested code
	   */
	  sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
		uio->uio_resid, uio->uio_iovcnt);
	  iv = uio->uio_iov;
	  len -= uio->uio_resid;
	  while(uio->uio_iovcnt > 0) {
	       if(iv->iov_len > len) {
		    caddr_t	bp = (caddr_t)iv->iov_base;

		    iv->iov_len -= len;
		    iv->iov_base = (void *)&bp[len];
		    break;
	       }
	       len -= iv->iov_len;
	       uio->uio_iovcnt--;
	       uio->uio_iov++;
	       iv++;
	  }
     } while(uio->uio_resid);

     if(error == 0) {
	  sp->stats.nsent++;
	  getmicrouptime(&sp->stats.t_sent);

     }

     return error;
}
Exemplo n.º 30
0
int
ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
{ 
#if SOCKNAL_SINGLE_FRAG_TX 
        struct iovec    scratch; 
        struct iovec   *scratchiov = &scratch; 
        unsigned int    niov = 1;
#else 
        struct iovec   *scratchiov = conn->ksnc_scheduler->kss_scratch_iov; 
        unsigned int    niov = tx->tx_niov;
#endif
        struct socket *sock = conn->ksnc_sock;
        int            nob;
        int            rc;
        int            i;
        struct uio  suio = {
                .uio_iov        = scratchiov,
                .uio_iovcnt     = niov,
                .uio_offset     = 0,
                .uio_resid      = 0,            /* This will be valued after a while */
                .uio_segflg     = UIO_SYSSPACE,
                .uio_rw         = UIO_WRITE,
                .uio_procp      = NULL
        };
        int  flags = MSG_DONTWAIT;
        CFS_DECL_NET_DATA;

        for (nob = i = 0; i < niov; i++) { 
                scratchiov[i] = tx->tx_iov[i]; 
                nob += scratchiov[i].iov_len; 
        }
        suio.uio_resid = nob;

        CFS_NET_IN;
        rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
        CFS_NET_EX; 

        /* NB there is no return value can indicate how many 
         * have been sent and how many resid, we have to get 
         * sent bytes from suio. */
        if (rc != 0) {
                if (suio.uio_resid != nob &&\
                    (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
                        /* We have sent something */
                        rc = nob - suio.uio_resid;
                else if ( rc == EWOULDBLOCK ) 
                        /* Actually, EAGAIN and EWOULDBLOCK have same value in OSX */
                        rc = -EAGAIN;   
                else 
                        rc = -rc;
        } else  /* rc == 0 */
                rc = nob - suio.uio_resid;

        return rc;
}

int
ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
{
#if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK 
        struct iovec  scratch; 
        struct iovec *scratchiov = &scratch; 
        unsigned int  niov = 1;
#else
        struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
        unsigned int  niov = tx->tx_nkiov;
#endif
        struct socket *sock = conn->ksnc_sock;
        lnet_kiov_t    *kiov = tx->tx_kiov;
        int            nob;
        int            rc;
        int            i;
        struct  uio suio = {
                .uio_iov        = scratchiov,
                .uio_iovcnt     = niov,
                .uio_offset     = 0, 
                .uio_resid      = 0,    /* It should be valued after a while */
                .uio_segflg     = UIO_SYSSPACE,
                .uio_rw         = UIO_WRITE,
                .uio_procp      = NULL
        };
        int  flags = MSG_DONTWAIT;
        CFS_DECL_NET_DATA; 
        
        for (nob = i = 0; i < niov; i++) { 
                scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + 
                                         kiov[i].kiov_offset; 
                nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
        }
        suio.uio_resid = nob;

        CFS_NET_IN;
        rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
        CFS_NET_EX;

        for (i = 0; i < niov; i++) 
                cfs_kunmap(kiov[i].kiov_page);

        if (rc != 0) {
                if (suio.uio_resid != nob &&\
                    (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
                        /* We have sent something */
                        rc = nob - suio.uio_resid; 
                else if ( rc == EWOULDBLOCK ) 
                        /* EAGAIN and EWOULD BLOCK have same value in OSX */
                        rc = -EAGAIN;   
                else 
                        rc = -rc;
        } else  /* rc == 0 */
                rc = nob - suio.uio_resid;

        return rc;
}

/*
 * liang: Hack of inpcb and tcpcb.
 * To get tcpcb of a socket, and call tcp_output
 * to send quick ack.
 */
struct ks_tseg_qent{
        int foo;
};

struct ks_tcptemp{
        int foo;
};

LIST_HEAD(ks_tsegqe_head, ks_tseg_qent);

struct ks_tcpcb {
        struct ks_tsegqe_head t_segq;
        int     t_dupacks;
        struct ks_tcptemp *unused;
        int    t_timer[4];
        struct inpcb *t_inpcb;
        int    t_state;
        u_int  t_flags;
        /*
         * There are more fields but we dont need
         * ......
         */
};

#define TF_ACKNOW       0x00001
#define TF_DELACK       0x00002

struct ks_inpcb {
        LIST_ENTRY(ks_inpcb) inp_hash;
        struct  in_addr reserved1;
        struct  in_addr reserved2;
        u_short inp_fport;
        u_short inp_lport;
        LIST_ENTRY(inpcb) inp_list;
        caddr_t inp_ppcb;
        /*
         * There are more fields but we dont need
         * ......
         */
};

#define ks_sotoinpcb(so)   ((struct ks_inpcb *)(so)->so_pcb)
#define ks_intotcpcb(ip)   ((struct ks_tcpcb *)(ip)->inp_ppcb)
#define ks_sototcpcb(so)   (intotcpcb(sotoinpcb(so)))

void
ksocknal_lib_eager_ack (ksock_conn_t *conn)
{
        struct socket *sock = conn->ksnc_sock;
        struct ks_inpcb  *inp = ks_sotoinpcb(sock);
        struct ks_tcpcb  *tp = ks_intotcpcb(inp);
        int s;
        CFS_DECL_NET_DATA;

        extern int tcp_output(register struct ks_tcpcb *tp);

        CFS_NET_IN;
        s = splnet();

        /*
         * No TCP_QUICKACK supported in BSD, so I have to call tcp_fasttimo
         * to send immediate ACK. 
         */
        if (tp && tp->t_flags & TF_DELACK){
                tp->t_flags &= ~TF_DELACK;
                tp->t_flags |= TF_ACKNOW;
                (void) tcp_output(tp);
        }
        splx(s);

        CFS_NET_EX;

        return;
}

int
ksocknal_lib_recv_iov (ksock_conn_t *conn)
{
#if SOCKNAL_SINGLE_FRAG_RX 
        struct iovec  scratch; 
        struct iovec *scratchiov = &scratch; 
        unsigned int  niov = 1;
#else 
        struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
        unsigned int  niov = conn->ksnc_rx_niov;
#endif
        struct iovec *iov = conn->ksnc_rx_iov;
        int          nob;
        int          rc;
        int          i;
        struct uio  ruio = {
                .uio_iov        = scratchiov,
                .uio_iovcnt     = niov,
                .uio_offset     = 0,
                .uio_resid      = 0,    /* It should be valued after a while */
                .uio_segflg     = UIO_SYSSPACE,
                .uio_rw         = UIO_READ,
                .uio_procp      = NULL
        };
        int         flags = MSG_DONTWAIT;
        CFS_DECL_NET_DATA;

        for (nob = i = 0; i < niov; i++) { 
                scratchiov[i] = iov[i]; 
                nob += scratchiov[i].iov_len; 
        } 
        LASSERT (nob <= conn->ksnc_rx_nob_wanted);

        ruio.uio_resid = nob;

        CFS_NET_IN;
        rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, &flags);
        CFS_NET_EX;
        if (rc){
                if (ruio.uio_resid != nob && \
                    (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK || rc == EAGAIN))
                        /* data particially received */
                        rc = nob - ruio.uio_resid; 
                else if (rc == EWOULDBLOCK) 
                        /* EAGAIN and EWOULD BLOCK have same value in OSX */
                        rc = -EAGAIN; 
                else
                        rc = -rc;
        } else 
                rc = nob - ruio.uio_resid;

        return (rc);
}

int
ksocknal_lib_recv_kiov (ksock_conn_t *conn)
{
#if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK 
        struct iovec  scratch; 
        struct iovec *scratchiov = &scratch; 
        unsigned int  niov = 1;
#else 
        struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
        unsigned int  niov = conn->ksnc_rx_nkiov;
#endif
        lnet_kiov_t    *kiov = conn->ksnc_rx_kiov;
        int           nob;
        int           rc;
        int           i;
        struct uio  ruio = {
                .uio_iov        = scratchiov,
                .uio_iovcnt     = niov,
                .uio_offset     = 0,
                .uio_resid      = 0,
                .uio_segflg     = UIO_SYSSPACE,
                .uio_rw         = UIO_READ,
                .uio_procp      = NULL
        };
        int         flags = MSG_DONTWAIT;
        CFS_DECL_NET_DATA;

        for (nob = i = 0; i < niov; i++) { 
                scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + kiov[i].kiov_offset; 
                nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
        } 
        LASSERT (nob <= conn->ksnc_rx_nob_wanted);

        ruio.uio_resid = nob;

        CFS_NET_IN;
        rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, NULL, &flags);
        CFS_NET_EX;

        for (i = 0; i < niov; i++) 
                cfs_kunmap(kiov[i].kiov_page);

        if (rc){
                if (ruio.uio_resid != nob && \
                    (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
                        /* data particially received */
                        rc = nob - ruio.uio_resid; 
                else if (rc == EWOULDBLOCK)
                        /* receive blocked, EWOULDBLOCK == EAGAIN */ 
                        rc = -EAGAIN; 
                else
                        rc = -rc;
        } else
                rc = nob - ruio.uio_resid;

        return (rc);
}

int
ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
{
        struct socket *sock = conn->ksnc_sock;
        int            rc;

        rc = ksocknal_connsock_addref(conn);
        if (rc != 0) {
                LASSERT (conn->ksnc_closing);
                *txmem = *rxmem = *nagle = 0;
                return -ESHUTDOWN;
        }
        rc = libcfs_sock_getbuf(sock, txmem, rxmem);
        if (rc == 0) {
                struct sockopt  sopt;
                int            len;
                CFS_DECL_NET_DATA;

                len = sizeof(*nagle);
                bzero(&sopt, sizeof sopt);
                sopt.sopt_dir = SOPT_GET; 
                sopt.sopt_level = IPPROTO_TCP;
                sopt.sopt_name = TCP_NODELAY;
                sopt.sopt_val = nagle;
                sopt.sopt_valsize = len;

                CFS_NET_IN;
                rc = -sogetopt(sock, &sopt);
                CFS_NET_EX;
        }

        ksocknal_connsock_decref(conn);

        if (rc == 0)
                *nagle = !*nagle;
        else
                *txmem = *rxmem = *nagle = 0;
        return (rc);
}

int
ksocknal_lib_setup_sock (struct socket *so)
{
        struct sockopt  sopt;
        int             rc; 
        int             option; 
        int             keep_idle; 
        int             keep_intvl; 
        int             keep_count; 
        int             do_keepalive; 
        struct linger   linger;
        CFS_DECL_NET_DATA;

        rc = libcfs_sock_setbuf(so,
                                *ksocknal_tunables.ksnd_tx_buffer_size,
                                *ksocknal_tunables.ksnd_rx_buffer_size);
        if (rc != 0) {
                CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
                        *ksocknal_tunables.ksnd_tx_buffer_size,
                        *ksocknal_tunables.ksnd_rx_buffer_size, rc);
                return (rc);
        }

        /* Ensure this socket aborts active sends immediately when we close
         * it. */
        bzero(&sopt, sizeof sopt);

        linger.l_onoff = 0;
        linger.l_linger = 0;
        sopt.sopt_dir = SOPT_SET;
        sopt.sopt_level = SOL_SOCKET;
        sopt.sopt_name = SO_LINGER;
        sopt.sopt_val = &linger;
        sopt.sopt_valsize = sizeof(linger);

        CFS_NET_IN;
        rc = -sosetopt(so, &sopt);
        if (rc != 0) {
                CERROR ("Can't set SO_LINGER: %d\n", rc);
                goto out;
        }

        if (!*ksocknal_tunables.ksnd_nagle) { 
                option = 1; 
                bzero(&sopt, sizeof sopt);
                sopt.sopt_dir = SOPT_SET; 
                sopt.sopt_level = IPPROTO_TCP;
                sopt.sopt_name = TCP_NODELAY; 
                sopt.sopt_val = &option; 
                sopt.sopt_valsize = sizeof(option);
                rc = -sosetopt(so, &sopt);
                if (rc != 0) { 
                        CERROR ("Can't disable nagle: %d\n", rc); 
                        goto out;
                } 
        } 

        /* snapshot tunables */ 
        keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle; 
        keep_count = *ksocknal_tunables.ksnd_keepalive_count; 
        keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;

        do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); 
        option = (do_keepalive ? 1 : 0); 
        bzero(&sopt, sizeof sopt); 
        sopt.sopt_dir = SOPT_SET; 
        sopt.sopt_level = SOL_SOCKET; 
        sopt.sopt_name = SO_KEEPALIVE; 
        sopt.sopt_val = &option; 
        sopt.sopt_valsize = sizeof(option); 
        rc = -sosetopt(so, &sopt); 
        if (rc != 0) { 
                CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); 
                goto out; 
        }
        
        if (!do_keepalive) { 
                /* no more setting, just return */
                rc = 0;
                goto out;
        } 
        
        bzero(&sopt, sizeof sopt); 
        sopt.sopt_dir = SOPT_SET; 
        sopt.sopt_level = IPPROTO_TCP; 
        sopt.sopt_name = TCP_KEEPALIVE; 
        sopt.sopt_val = &keep_idle; 
        sopt.sopt_valsize = sizeof(keep_idle); 
        rc = -sosetopt(so, &sopt); 
        if (rc != 0) { 
                CERROR ("Can't set TCP_KEEPALIVE : %d\n", rc); 
                goto out; 
        }
out:
        CFS_NET_EX;
        return (rc);
}

void
ksocknal_lib_push_conn(ksock_conn_t *conn)
{ 
        struct socket   *sock; 
        struct sockopt  sopt; 
        int             val = 1; 
        int             rc; 
        CFS_DECL_NET_DATA; 
        
        rc = ksocknal_connsock_addref(conn); 
        if (rc != 0)            /* being shut down */ 
                return; 
        sock = conn->ksnc_sock; 
        bzero(&sopt, sizeof sopt); 
        sopt.sopt_dir = SOPT_SET; 
        sopt.sopt_level = IPPROTO_TCP; 
        sopt.sopt_name = TCP_NODELAY; 
        sopt.sopt_val = &val; 
        sopt.sopt_valsize = sizeof val; 

        CFS_NET_IN; 
        sosetopt(sock, &sopt); 
        CFS_NET_EX; 

        ksocknal_connsock_decref(conn);
        return;
}


extern void ksocknal_read_callback (ksock_conn_t *conn);
extern void ksocknal_write_callback (ksock_conn_t *conn);

static void
ksocknal_upcall(struct socket *so, caddr_t arg, int waitf)
{
        ksock_conn_t  *conn = (ksock_conn_t *)arg;
        ENTRY;

        read_lock (&ksocknal_data.ksnd_global_lock);
        if (conn == NULL)
                goto out;

        if (so->so_rcv.sb_flags & SB_UPCALL) {
                extern int soreadable(struct socket *so);
                if (conn->ksnc_rx_nob_wanted && soreadable(so))
                        /* To verify whether the upcall is for receive */
                        ksocknal_read_callback (conn);
        }
        /* go foward? */
        if (so->so_snd.sb_flags & SB_UPCALL){
                extern int sowriteable(struct socket *so);
                if (sowriteable(so))
                        /* socket is writable */
                        ksocknal_write_callback(conn);
        }
out:
        read_unlock (&ksocknal_data.ksnd_global_lock);

        EXIT;
}

void
ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
{ 
        /* No callback need to save in osx */
        return;
}

void
ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn)
{ 
        CFS_DECL_NET_DATA;

        CFS_NET_IN;
        sock->so_upcallarg = (void *)conn;
        sock->so_upcall = ksocknal_upcall; 
        sock->so_snd.sb_timeo = 0; 
        sock->so_rcv.sb_timeo = cfs_time_seconds(2);
        sock->so_rcv.sb_flags |= SB_UPCALL; 
        sock->so_snd.sb_flags |= SB_UPCALL; 
        CFS_NET_EX;
        return;
}

void
ksocknal_lib_act_callback(struct socket *sock, ksock_conn_t *conn)
{
        CFS_DECL_NET_DATA;

        CFS_NET_IN;
        ksocknal_upcall (sock, (void *)conn, 0);
        CFS_NET_EX;
}