⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 svc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* net/atm/svc.c - ATM SVC sockets *//* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */#include <linux/string.h>#include <linux/net.h>		/* struct socket, struct proto_ops */#include <linux/errno.h>	/* error codes */#include <linux/kernel.h>	/* printk */#include <linux/skbuff.h>#include <linux/wait.h>#include <linux/sched.h>	/* jiffies and HZ */#include <linux/fcntl.h>	/* O_NONBLOCK */#include <linux/init.h>#include <linux/atm.h>		/* ATM stuff */#include <linux/atmsap.h>#include <linux/atmsvc.h>#include <linux/atmdev.h>#include <linux/bitops.h>#include <net/sock.h>		/* for sock_no_* */#include <asm/uaccess.h>#include "resources.h"#include "common.h"		/* common for PVCs and SVCs */#include "signaling.h"#include "addr.h"static int svc_create(struct net *net, struct socket *sock,int protocol);/* * Note: since all this is still nicely synchronized with the signaling demon, *       there's no need to protect sleep loops with clis. If signaling is *       moved into the kernel, that would change. */static int svc_shutdown(struct socket *sock,int how){	return 0;}static void svc_disconnect(struct atm_vcc *vcc){	DEFINE_WAIT(wait);	struct sk_buff *skb;	struct sock *sk = sk_atm(vcc);	pr_debug("svc_disconnect %p\n",vcc);	if (test_bit(ATM_VF_REGIS,&vcc->flags)) {		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);		sigd_enq(vcc,as_close,NULL,NULL,NULL);		while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {			schedule();			prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);		}		finish_wait(sk->sk_sleep, &wait);	}	/* beware - socket is still in use by atmsigd until the last	   as_indicate has been answered */	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {		atm_return(vcc, skb->truesize);		pr_debug("LISTEN REL\n");		sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);		dev_kfree_skb(skb);	}	clear_bit(ATM_VF_REGIS, &vcc->flags);	/* ... may retry later */}static int svc_release(struct socket *sock){	struct sock *sk = sock->sk;	struct atm_vcc *vcc;	if (sk)  {		vcc = ATM_SD(sock);		pr_debug("svc_release %p\n", vcc);		clear_bit(ATM_VF_READY, &vcc->flags);		/* VCC pointer is used as a reference, so we must not free it		   (thereby subjecting it to re-use) before all pending connections		   are closed */		svc_disconnect(vcc);		vcc_release(sock);	}	return 0;}static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,    int sockaddr_len){	DEFINE_WAIT(wait);	struct sock *sk = sock->sk;	struct sockaddr_atmsvc *addr;	struct atm_vcc *vcc;	int error;	if (sockaddr_len != sizeof(struct sockaddr_atmsvc))		return -EINVAL;	lock_sock(sk);	if (sock->state == SS_CONNECTED) {		error = -EISCONN;		goto out;	}	if (sock->state != SS_UNCONNECTED) {		error = -EINVAL;		goto out;	}	vcc = ATM_SD(sock);	addr = (struct sockaddr_atmsvc *) sockaddr;	if (addr->sas_family != AF_ATMSVC) {		error = -EAFNOSUPPORT;		goto out;	}	clear_bit(ATM_VF_BOUND,&vcc->flags);	    /* failing rebind will kill old binding */	/* @@@ check memory (de)allocation on rebind */	if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) {		error = -EBADFD;		goto out;	}	vcc->local = *addr;	set_bit(ATM_VF_WAITING, &vcc->flags);	prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);	sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {		schedule();		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);	}	finish_wait(sk->sk_sleep, &wait);	clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */	if (!sigd) {		error = -EUNATCH;		goto out;	}	if (!sk->sk_err)		set_bit(ATM_VF_BOUND,&vcc->flags);	error = -sk->sk_err;out:	release_sock(sk);	return error;}static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,    int sockaddr_len,int flags){	DEFINE_WAIT(wait);	struct sock *sk = sock->sk;	struct sockaddr_atmsvc *addr;	struct atm_vcc *vcc = ATM_SD(sock);	int error;	pr_debug("svc_connect %p\n",vcc);	lock_sock(sk);	if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {		error = -EINVAL;		goto out;	}	switch (sock->state) {	default:		error = -EINVAL;		goto out;	case SS_CONNECTED:		error = -EISCONN;		goto out;	case SS_CONNECTING:		if (test_bit(ATM_VF_WAITING, &vcc->flags)) {			error = -EALREADY;			goto out;		}		sock->state = SS_UNCONNECTED;		if (sk->sk_err) {			error = -sk->sk_err;			goto out;		}		break;	case SS_UNCONNECTED:		addr = (struct sockaddr_atmsvc *) sockaddr;		if (addr->sas_family != AF_ATMSVC) {			error = -EAFNOSUPPORT;			goto out;		}		if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {			error = -EBADFD;			goto out;		}		if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||		    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) {			error = -EINVAL;			goto out;		}		if (!vcc->qos.txtp.traffic_class &&		    !vcc->qos.rxtp.traffic_class) {			error = -EINVAL;			goto out;		}		vcc->remote = *addr;		set_bit(ATM_VF_WAITING, &vcc->flags);		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);		sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);		if (flags & O_NONBLOCK) {			finish_wait(sk->sk_sleep, &wait);			sock->state = SS_CONNECTING;			error = -EINPROGRESS;			goto out;		}		error = 0;		while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {			schedule();			if (!signal_pending(current)) {				prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);				continue;			}			pr_debug("*ABORT*\n");			/*			 * This is tricky:			 *   Kernel ---close--> Demon			 *   Kernel <--close--- Demon			 * or			 *   Kernel ---close--> Demon			 *   Kernel <--error--- Demon			 * or			 *   Kernel ---close--> Demon			 *   Kernel <--okay---- Demon			 *   Kernel <--close--- Demon			 */			sigd_enq(vcc,as_close,NULL,NULL,NULL);			while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {				prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);				schedule();			}			if (!sk->sk_err)				while (!test_bit(ATM_VF_RELEASED,&vcc->flags)				    && sigd) {					prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);					schedule();				}			clear_bit(ATM_VF_REGIS,&vcc->flags);			clear_bit(ATM_VF_RELEASED,&vcc->flags);			clear_bit(ATM_VF_CLOSE,&vcc->flags);			    /* we're gone now but may connect later */			error = -EINTR;			break;		}		finish_wait(sk->sk_sleep, &wait);		if (error)			goto out;		if (!sigd) {			error = -EUNATCH;			goto out;		}		if (sk->sk_err) {			error = -sk->sk_err;			goto out;		}	}/* * Not supported yet * * #ifndef CONFIG_SINGLE_SIGITF */	vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);	vcc->qos.txtp.pcr = 0;	vcc->qos.txtp.min_pcr = 0;/* * #endif */	if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci)))		sock->state = SS_CONNECTED;	else		(void) svc_disconnect(vcc);out:	release_sock(sk);	return error;}static int svc_listen(struct socket *sock,int backlog){	DEFINE_WAIT(wait);	struct sock *sk = sock->sk;	struct atm_vcc *vcc = ATM_SD(sock);	int error;	pr_debug("svc_listen %p\n",vcc);	lock_sock(sk);	/* let server handle listen on unbound sockets */	if (test_bit(ATM_VF_SESSION,&vcc->flags)) {		error = -EINVAL;		goto out;	}	vcc_insert_socket(sk);	set_bit(ATM_VF_WAITING, &vcc->flags);	prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);	sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {		schedule();		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);	}	finish_wait(sk->sk_sleep, &wait);	if (!sigd) {		error = -EUNATCH;		goto out;	}	set_bit(ATM_VF_LISTEN,&vcc->flags);	sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;	error = -sk->sk_err;out:	release_sock(sk);	return error;}static int svc_accept(struct socket *sock,struct socket *newsock,int flags){	struct sock *sk = sock->sk;	struct sk_buff *skb;	struct atmsvc_msg *msg;	struct atm_vcc *old_vcc = ATM_SD(sock);	struct atm_vcc *new_vcc;	int error;	lock_sock(sk);	error = svc_create(sk->sk_net, newsock,0);	if (error)		goto out;	new_vcc = ATM_SD(newsock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -