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

📄 af_llc.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
}static int llc_ui_wait_for_data(struct sock *sk, int timeout){	DECLARE_WAITQUEUE(wait, current);	int rc = 0;	add_wait_queue_exclusive(sk->sk_sleep, &wait);	for (;;) {		__set_current_state(TASK_INTERRUPTIBLE);		if (sk->sk_shutdown & RCV_SHUTDOWN)			break;		/*		 * Well, if we have backlog, try to process it now.		 */                if (sk->sk_backlog.tail) {			release_sock(sk);			lock_sock(sk);		}		rc = 0;		if (skb_queue_empty(&sk->sk_receive_queue)) {			release_sock(sk);			timeout = schedule_timeout(timeout);			lock_sock(sk);		} else			break;		rc = -ERESTARTSYS;		if (signal_pending(current))			break;		rc = -EAGAIN;		if (!timeout)			break;	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(sk->sk_sleep, &wait);	return rc;}static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout){	DECLARE_WAITQUEUE(wait, current);	struct llc_opt *llc = llc_sk(sk);	int rc;	add_wait_queue_exclusive(sk->sk_sleep, &wait);	for (;;) {		dprintk("%s: looping...\n", __FUNCTION__);		__set_current_state(TASK_INTERRUPTIBLE);		rc = -ENOTCONN;		if (sk->sk_shutdown & RCV_SHUTDOWN)			break;		rc = 0;		if (llc_data_accept_state(llc->state) || llc->p_flag) {			release_sock(sk);			timeout = schedule_timeout(timeout);			lock_sock(sk);		} else			break;		rc = -ERESTARTSYS;		if (signal_pending(current))			break;		rc = -EAGAIN;		if (!timeout)			break;	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(sk->sk_sleep, &wait);	return rc;}/** *	llc_ui_accept - accept a new incoming connection. *	@sock: Socket which connections arrive on. *	@newsock: Socket to move incoming connection to. *	@flags: User specified operational flags. * *	Accept a new incoming connection. *	Returns 0 upon success, negative otherwise. */static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags){	struct sock *sk = sock->sk, *newsk;	struct llc_opt *llc, *newllc;	struct sk_buff *skb;	int rc = -EOPNOTSUPP;	dprintk("%s: accepting on %02X\n", __FUNCTION__,	        llc_sk(sk)->laddr.lsap);	lock_sock(sk);	if (sk->sk_type != SOCK_STREAM)		goto out;	rc = -EINVAL;	if (sock->state != SS_UNCONNECTED || sk->sk_state != TCP_LISTEN)		goto out;	/* wait for a connection to arrive. */	rc = llc_ui_wait_for_data(sk, sk->sk_rcvtimeo);	if (rc)		goto out;	dprintk("%s: got a new connection on %02X\n", __FUNCTION__,	        llc_sk(sk)->laddr.lsap);	skb = skb_dequeue(&sk->sk_receive_queue);	rc = -EINVAL;	if (!skb->sk)		goto frees;	rc = 0;	newsk = skb->sk;	/* attach connection to a new socket. */	llc_ui_sk_init(newsock, newsk);	newsk->sk_zapped	= 0;	newsk->sk_state		= TCP_ESTABLISHED;	newsock->state		= SS_CONNECTED;	llc			= llc_sk(sk);	newllc			= llc_sk(newsk);	memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));	newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);	/* put original socket back into a clean listen state. */	sk->sk_state = TCP_LISTEN;	sk->sk_ack_backlog--;	skb->sk = NULL;	dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,		llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap);frees:	kfree_skb(skb);out:	release_sock(sk);	return rc;}/** *	llc_ui_recvmsg - copy received data to the socket user. *	@sock: Socket to copy data from. *	@msg: Various user space related information. *	@size: Size of user buffer. *	@flags: User specified flags. * *	Copy received data to the socket user. *	Returns non-negative upon success, negative otherwise. */static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,			  struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;	struct sk_buff *skb;	size_t copied = 0;	int rc = -ENOMEM, timeout;	int noblock = flags & MSG_DONTWAIT;	dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,		llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);	lock_sock(sk);	timeout = sock_rcvtimeo(sk, noblock);	rc = llc_ui_wait_for_data(sk, timeout);	if (rc) {		dprintk("%s: llc_ui_wait_for_data failed recv "			"in %02X from %02X\n", __FUNCTION__,			llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);		goto out;	}	skb = skb_dequeue(&sk->sk_receive_queue);	if (!skb) /* shutdown */		goto out;	copied = skb->len;	if (copied > size)		copied = size;	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (rc)		goto dgram_free;	if (skb->len > copied) {		skb_pull(skb, copied);		skb_queue_head(&sk->sk_receive_queue, skb);	}	if (uaddr)		memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));	msg->msg_namelen = sizeof(*uaddr);	if (!skb->list) {dgram_free:		kfree_skb(skb);	}out:	release_sock(sk);	return rc ? : copied;}/** *	llc_ui_sendmsg - Transmit data provided by the socket user. *	@sock: Socket to transmit data from. *	@msg: Various user related information. *	@len: Length of data to transmit. * *	Transmit data provided by the socket user. *	Returns non-negative upon success, negative otherwise. */static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock,			  struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	struct llc_opt *llc = llc_sk(sk);	struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;	int flags = msg->msg_flags;	int noblock = flags & MSG_DONTWAIT;	struct net_device *dev;	struct sk_buff *skb;	size_t size = 0;	int rc = -EINVAL, copied = 0, hdrlen;	dprintk("%s: sending from %02X to %02X\n", __FUNCTION__,		llc->laddr.lsap, llc->daddr.lsap);	lock_sock(sk);	if (addr) {		if (msg->msg_namelen < sizeof(*addr))			goto release;	} else {		if (llc_ui_addr_null(&llc->addr))			goto release;		addr = &llc->addr;	}	/* must bind connection to sap if user hasn't done it. */	if (sk->sk_zapped) {		/* bind to sap with null dev, exclusive. */		rc = llc_ui_autobind(sock, addr);		if (rc)			goto release;	}	dev = llc->dev;	hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr);	size = hdrlen + len;	if (size > dev->mtu)		size = dev->mtu;	copied = size - hdrlen;	release_sock(sk);	skb = sock_alloc_send_skb(sk, size, noblock, &rc);	lock_sock(sk);	if (!skb)		goto release;	skb->sk	      = sk;	skb->dev      = dev;	skb->protocol = llc_proto_type(addr->sllc_arphrd);	skb_reserve(skb, hdrlen); 	rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied);	if (rc)		goto out;	if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) {		llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_mac,					  addr->sllc_sap);		goto out;	}	if (addr->sllc_test) {		llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_mac,					    addr->sllc_sap);		goto out;	}	if (addr->sllc_xid) {		llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_mac,					   addr->sllc_sap);		goto out;	}	rc = -ENOPROTOOPT;	if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua))		goto out;	rc = llc_ui_send_data(sk, skb, noblock);	if (rc)		dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc);out:	if (rc)		kfree_skb(skb);release:	if (rc)		dprintk("%s: failed sending from %02X to %02X: %d\n",			__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);	release_sock(sk);	return rc ? : copied;}/** *	llc_ui_getname - return the address info of a socket *	@sock: Socket to get address of. *	@uaddr: Address structure to return information. *	@uaddrlen: Length of address structure. *	@peer: Does user want local or remote address information. * *	Return the address information of a socket. */static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,			  int *uaddrlen, int peer){	struct sockaddr_llc sllc;	struct sock *sk = sock->sk;	struct llc_opt *llc = llc_sk(sk);	int rc = 0;	lock_sock(sk);	if (sk->sk_zapped)		goto out;	*uaddrlen = sizeof(sllc);	memset(uaddr, 0, *uaddrlen);	if (peer) {		rc = -ENOTCONN;		if (sk->sk_state != TCP_ESTABLISHED)			goto out;		if(llc->dev)			sllc.sllc_arphrd = llc->dev->type;		sllc.sllc_sap = llc->daddr.lsap;		memcpy(&sllc.sllc_mac, &llc->daddr.mac, IFHWADDRLEN);	} else {		rc = -EINVAL;		if (!llc->sap)			goto out;		sllc.sllc_sap = llc->sap->laddr.lsap;		if (llc->dev) {			sllc.sllc_arphrd = llc->dev->type;			memcpy(&sllc.sllc_mac, &llc->dev->dev_addr,			       IFHWADDRLEN);		}	}	rc = 0;	sllc.sllc_family = AF_LLC;	memcpy(uaddr, &sllc, sizeof(sllc));out:	release_sock(sk);	return rc;}/** *	llc_ui_ioctl - io controls for PF_LLC *	@sock: Socket to get/set info *	@cmd: command *	@arg: optional argument for cmd * *	get/set info on llc sockets */static int llc_ui_ioctl(struct socket *sock, unsigned int cmd,			unsigned long arg){	return dev_ioctl(cmd, (void __user *)arg);}/** *	llc_ui_setsockopt - set various connection specific parameters. *	@sock: Socket to set options on. *	@level: Socket level user is requesting operations on. *	@optname: Operation name. *	@optval User provided operation data. *	@optlen: Length of optval. * *	Set various connection specific parameters. */static int llc_ui_setsockopt(struct socket *sock, int level, int optname,			     char __user *optval, int optlen){	struct sock *sk = sock->sk;	struct llc_opt *llc = llc_sk(sk);	int rc = -EINVAL, opt;	lock_sock(sk);	if (level != SOL_LLC || optlen != sizeof(int))		goto out;	rc = get_user(opt, (int __user *)optval);	if (rc)		goto out;	rc = -EINVAL;	switch (optname) {	case LLC_OPT_RETRY:		if (opt > LLC_OPT_MAX_RETRY)			goto out;		llc->n2 = opt;		break;	case LLC_OPT_SIZE:		if (opt > LLC_OPT_MAX_SIZE)			goto out;		llc->n1 = opt;		break;	case LLC_OPT_ACK_TMR_EXP:		if (opt > LLC_OPT_MAX_ACK_TMR_EXP)			goto out;		llc->ack_timer.expire = opt;		break;	case LLC_OPT_P_TMR_EXP:		if (opt > LLC_OPT_MAX_P_TMR_EXP)			goto out;		llc->pf_cycle_timer.expire = opt;		break;	case LLC_OPT_REJ_TMR_EXP:		if (opt > LLC_OPT_MAX_REJ_TMR_EXP)			goto out;		llc->rej_sent_timer.expire = opt;		break;	case LLC_OPT_BUSY_TMR_EXP:		if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)			goto out;		llc->busy_state_timer.expire = opt;		break;	case LLC_OPT_TX_WIN:		if (opt > LLC_OPT_MAX_WIN)			goto out;		llc->k = opt;		break;	case LLC_OPT_RX_WIN:		if (opt > LLC_OPT_MAX_WIN)			goto out;		llc->rw = opt;		break;	default:		rc = -ENOPROTOOPT;		goto out;	}	rc = 0;out:	release_sock(sk);	return rc;}/** *	llc_ui_getsockopt - get connection specific socket info *	@sock: Socket to get information from. *	@level: Socket level user is requesting operations on. *	@optname: Operation name. *	@optval: Variable to return operation data in. *	@optlen: Length of optval. * *	Get connection specific socket information. */static int llc_ui_getsockopt(struct socket *sock, int level, int optname,			     char __user *optval, int __user *optlen){	struct sock *sk = sock->sk;	struct llc_opt *llc = llc_sk(sk);	int val = 0, len = 0, rc = -EINVAL;	lock_sock(sk);	if (level != SOL_LLC)		goto out;	rc = get_user(len, optlen);	if (rc)		goto out;	rc = -EINVAL;	if (len != sizeof(int))		goto out;	switch (optname) {	case LLC_OPT_RETRY:		val = llc->n2;				break;	case LLC_OPT_SIZE:		val = llc->n1;				break;	case LLC_OPT_ACK_TMR_EXP:		val = llc->ack_timer.expire;		break;	case LLC_OPT_P_TMR_EXP:		val = llc->pf_cycle_timer.expire;	break;	case LLC_OPT_REJ_TMR_EXP:		val = llc->rej_sent_timer.expire;	break;	case LLC_OPT_BUSY_TMR_EXP:		val = llc->busy_state_timer.expire;	break;	case LLC_OPT_TX_WIN:		val = llc->k;				break;	case LLC_OPT_RX_WIN:		val = llc->rw;				break;	default:		rc = -ENOPROTOOPT;		goto out;	}	rc = 0;	if (put_user(len, optlen) || copy_to_user(optval, &val, len))		rc = -EFAULT;out:	release_sock(sk);	return rc;}static struct net_proto_family llc_ui_family_ops = {	.family = PF_LLC,	.create = llc_ui_create,	.owner	= THIS_MODULE,};static struct proto_ops llc_ui_ops = {	.family	     = PF_LLC,	.owner       = THIS_MODULE,	.release     = llc_ui_release,	.bind	     = llc_ui_bind,	.connect     = llc_ui_connect,	.socketpair  = sock_no_socketpair,	.accept      = llc_ui_accept,	.getname     = llc_ui_getname,	.poll	     = datagram_poll,	.ioctl       = llc_ui_ioctl,	.listen      = llc_ui_listen,	.shutdown    = llc_ui_shutdown,	.setsockopt  = llc_ui_setsockopt,	.getsockopt  = llc_ui_getsockopt,	.sendmsg     = llc_ui_sendmsg,	.recvmsg     = llc_ui_recvmsg,	.mmap	     = sock_no_mmap,	.sendpage    = sock_no_sendpage,};extern void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb);extern void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb);static int __init llc2_init(void){	int rc;	llc_build_offset_table();	llc_station_init();	llc_ui_sap_last_autoport = LLC_SAP_DYN_START;	rc = llc_proc_init();	if (!rc) {		sock_register(&llc_ui_family_ops);		llc_add_pack(LLC_DEST_SAP, llc_sap_handler);		llc_add_pack(LLC_DEST_CONN, llc_conn_handler);	}	return rc;}static void __exit llc2_exit(void){	llc_station_exit();	llc_remove_pack(LLC_DEST_SAP);	llc_remove_pack(LLC_DEST_CONN);	sock_unregister(PF_LLC);	llc_proc_exit();}module_init(llc2_init);module_exit(llc2_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003");MODULE_DESCRIPTION("IEEE 802.2 PF_LLC support");MODULE_ALIAS_NETPROTO(PF_LLC);

⌨️ 快捷键说明

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