diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 | 
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/llc | |
| download | linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.bz2 | |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/llc')
| -rw-r--r-- | net/llc/Kconfig | 10 | ||||
| -rw-r--r-- | net/llc/Makefile | 24 | ||||
| -rw-r--r-- | net/llc/af_llc.c | 1079 | ||||
| -rw-r--r-- | net/llc/llc_c_ac.c | 1514 | ||||
| -rw-r--r-- | net/llc/llc_c_ev.c | 769 | ||||
| -rw-r--r-- | net/llc/llc_c_st.c | 4946 | ||||
| -rw-r--r-- | net/llc/llc_conn.c | 915 | ||||
| -rw-r--r-- | net/llc/llc_core.c | 179 | ||||
| -rw-r--r-- | net/llc/llc_if.c | 157 | ||||
| -rw-r--r-- | net/llc/llc_input.c | 189 | ||||
| -rw-r--r-- | net/llc/llc_output.c | 107 | ||||
| -rw-r--r-- | net/llc/llc_output.h | 20 | ||||
| -rw-r--r-- | net/llc/llc_pdu.c | 372 | ||||
| -rw-r--r-- | net/llc/llc_proc.c | 267 | ||||
| -rw-r--r-- | net/llc/llc_s_ac.c | 205 | ||||
| -rw-r--r-- | net/llc/llc_s_ev.c | 115 | ||||
| -rw-r--r-- | net/llc/llc_s_st.c | 183 | ||||
| -rw-r--r-- | net/llc/llc_sap.c | 316 | ||||
| -rw-r--r-- | net/llc/llc_station.c | 713 | 
19 files changed, 12080 insertions, 0 deletions
| diff --git a/net/llc/Kconfig b/net/llc/Kconfig new file mode 100644 index 000000000000..b91c65108162 --- /dev/null +++ b/net/llc/Kconfig @@ -0,0 +1,10 @@ +config LLC +	tristate +	depends on NET + +config LLC2 +	tristate "ANSI/IEEE 802.2 LLC type 2 Support" +	select LLC +	help +	  This is a Logical Link Layer type 2, connection oriented support.  +	  Select this if you want to have support for PF_LLC sockets. diff --git a/net/llc/Makefile b/net/llc/Makefile new file mode 100644 index 000000000000..5ebd4ed2bd42 --- /dev/null +++ b/net/llc/Makefile @@ -0,0 +1,24 @@ +########################################################################### +# Makefile for the Linux 802.2 LLC (fully-functional) layer. +# +# Copyright (c) 1997 by Procom Technology,Inc. +#		2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> +# +# This program can be redistributed or modified under the terms of the  +# GNU General Public License as published by the Free Software Foundation. +# This program is distributed without any warranty or implied warranty +# of merchantability or fitness for a particular purpose. +# +# See the GNU General Public License for more details. +########################################################################### + +obj-$(CONFIG_LLC) += llc.o + +llc-y := llc_core.o llc_input.o llc_output.o + +obj-$(CONFIG_LLC2) += llc2.o + +llc2-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_conn.o llc_c_st.o llc_pdu.o \ +	  llc_sap.o llc_s_ac.o llc_s_ev.o llc_s_st.o af_llc.o llc_station.o + +llc2-$(CONFIG_PROC_FS) += llc_proc.o diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c new file mode 100644 index 000000000000..20b4cfebd74c --- /dev/null +++ b/net/llc/af_llc.c @@ -0,0 +1,1079 @@ +/* + * af_llc.c - LLC User Interface SAPs + * Description: + *   Functions in this module are implementation of socket based llc + *   communications for the Linux operating system. Support of llc class + *   one and class two is provided via SOCK_DGRAM and SOCK_STREAM + *   respectively. + * + *   An llc2 connection is (mac + sap), only one llc2 sap connection + *   is allowed per mac. Though one sap may have multiple mac + sap + *   connections. + * + * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org> + *		 2002-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/tcp.h> +#include <linux/rtnetlink.h> +#include <linux/init.h> +#include <net/llc.h> +#include <net/llc_sap.h> +#include <net/llc_pdu.h> +#include <net/llc_conn.h> + +/* remember: uninitialized global data is zeroed because its in .bss */ +static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START; +static u16 llc_ui_sap_link_no_max[256]; +static struct sockaddr_llc llc_ui_addrnull; +static struct proto_ops llc_ui_ops; + +static int llc_ui_wait_for_conn(struct sock *sk, int timeout); +static int llc_ui_wait_for_disc(struct sock *sk, int timeout); +static int llc_ui_wait_for_data(struct sock *sk, int timeout); +static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout); + +#if 0 +#define dprintk(args...) printk(KERN_DEBUG args) +#else +#define dprintk(args...) +#endif + +/** + *	llc_ui_next_link_no - return the next unused link number for a sap + *	@sap: Address of sap to get link number from. + * + *	Return the next unused link number for a given sap. + */ +static __inline__ u16 llc_ui_next_link_no(int sap) +{ +	return llc_ui_sap_link_no_max[sap]++; +} + +/** + *	llc_proto_type - return eth protocol for ARP header type + *	@arphrd: ARP header type. + * + *	Given an ARP header type return the corresponding ethernet protocol. + */ +static __inline__ u16 llc_proto_type(u16 arphrd) +{ +	return arphrd == ARPHRD_IEEE802_TR ? +		         htons(ETH_P_TR_802_2) : htons(ETH_P_802_2); +} + +/** + *	llc_ui_addr_null - determines if a address structure is null + *	@addr: Address to test if null. + */ +static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr) +{ +	return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr)); +} + +/** + *	llc_ui_header_len - return length of llc header based on operation + *	@sk: Socket which contains a valid llc socket type. + *	@addr: Complete sockaddr_llc structure received from the user. + * + *	Provide the length of the llc header depending on what kind of + *	operation the user would like to perform and the type of socket. + *	Returns the correct llc header length. + */ +static __inline__ u8 llc_ui_header_len(struct sock *sk, +				       struct sockaddr_llc *addr) +{ +	u8 rc = LLC_PDU_LEN_U; + +	if (addr->sllc_test || addr->sllc_xid) +		rc = LLC_PDU_LEN_U; +	else if (sk->sk_type == SOCK_STREAM) +		rc = LLC_PDU_LEN_I; +	return rc; +} + +/** + *	llc_ui_send_data - send data via reliable llc2 connection + *	@sk: Connection the socket is using. + *	@skb: Data the user wishes to send. + *	@addr: Source and destination fields provided by the user. + *	@noblock: can we block waiting for data? + * + *	Send data via reliable llc2 connection. + *	Returns 0 upon success, non-zero if action did not succeed. + */ +static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) +{ +	struct llc_sock* llc = llc_sk(sk); +	int rc = 0; + +	if (llc_data_accept_state(llc->state) || llc->p_flag) { +		int timeout = sock_sndtimeo(sk, noblock); + +		rc = llc_ui_wait_for_busy_core(sk, timeout); +	} +	if (!rc) +		rc = llc_build_and_send_pkt(sk, skb); +	return rc; +} + +static void llc_ui_sk_init(struct socket *sock, struct sock *sk) +{ +	sk->sk_type	= sock->type; +	sk->sk_sleep	= &sock->wait; +	sk->sk_socket	= sock; +	sock->sk	= sk; +	sock->ops	= &llc_ui_ops; +} + +static struct proto llc_proto = { +	.name	  = "DDP", +	.owner	  = THIS_MODULE, +	.obj_size = sizeof(struct llc_sock), +}; + +/** + *	llc_ui_create - alloc and init a new llc_ui socket + *	@sock: Socket to initialize and attach allocated sk to. + *	@protocol: Unused. + * + *	Allocate and initialize a new llc_ui socket, validate the user wants a + *	socket type we have available. + *	Returns 0 upon success, negative upon failure. + */ +static int llc_ui_create(struct socket *sock, int protocol) +{ +	struct sock *sk; +	int rc = -ESOCKTNOSUPPORT; + +	if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) { +		rc = -ENOMEM; +		sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto); +		if (sk) { +			rc = 0; +			llc_ui_sk_init(sock, sk); +		} +	} +	return rc; +} + +/** + *	llc_ui_release - shutdown socket + *	@sock: Socket to release. + * + *	Shutdown and deallocate an existing socket. + */ +static int llc_ui_release(struct socket *sock) +{ +	struct sock *sk = sock->sk; +	struct llc_sock *llc; + +	if (!sk) +		goto out; +	sock_hold(sk); +	lock_sock(sk); +	llc = llc_sk(sk); +	dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__, +		llc->laddr.lsap, llc->daddr.lsap); +	if (!llc_send_disc(sk)) +		llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); +	if (!sock_flag(sk, SOCK_ZAPPED)) +		llc_sap_remove_socket(llc->sap, sk); +	release_sock(sk); +	if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) { +		llc_release_sockets(llc->sap); +		llc_sap_close(llc->sap); +	} +	if (llc->dev) +		dev_put(llc->dev); +	sock_put(sk); +	llc_sk_free(sk); +out: +	return 0; +} + +/** + *	llc_ui_autoport - provide dynamically allocate SAP number + * + *	Provide the caller with a dynamically allocated SAP number according + *	to the rules that are set in this function. Returns: 0, upon failure, + *	SAP number otherwise. + */ +static int llc_ui_autoport(void) +{ +	struct llc_sap *sap; +	int i, tries = 0; + +	while (tries < LLC_SAP_DYN_TRIES) { +		for (i = llc_ui_sap_last_autoport; +		     i < LLC_SAP_DYN_STOP; i += 2) { +			sap = llc_sap_find(i); +			if (!sap) { +				llc_ui_sap_last_autoport = i + 2; +				goto out; +			} +		} +		llc_ui_sap_last_autoport = LLC_SAP_DYN_START; +		tries++; +	} +	i = 0; +out: +	return i; +} + +/** + *	llc_ui_autobind - Bind a socket to a specific address. + *	@sk: Socket to bind an address to. + *	@addr: Address the user wants the socket bound to. + * + *	Bind a socket to a specific address. For llc a user is able to bind to + *	a specific sap only or mac + sap. If the user only specifies a sap and + *	a null dmac (all zeros) the user is attempting to bind to an entire + *	sap. This will stop anyone else on the local system from using that + *	sap.  If someone else has a mac + sap open the bind to null + sap will + *	fail. + *	If the user desires to bind to a specific mac + sap, it is possible to + *	have multiple sap connections via multiple macs. + *	Bind and autobind for that matter must enforce the correct sap usage + *	otherwise all hell will break loose. + *	Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) +{ +	struct sock *sk = sock->sk; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_sap *sap; +	int rc = -EINVAL; + +	if (!sock_flag(sk, SOCK_ZAPPED)) +		goto out; +	rc = -ENODEV; +	llc->dev = dev_getfirstbyhwtype(addr->sllc_arphrd); +	if (!llc->dev) +		goto out; +	rc = -EUSERS; +	llc->laddr.lsap = llc_ui_autoport(); +	if (!llc->laddr.lsap) +		goto out; +	rc = -EBUSY; /* some other network layer is using the sap */ +	sap = llc_sap_open(llc->laddr.lsap, NULL); +	if (!sap) +		goto out; +	memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN); +	memcpy(&llc->addr, addr, sizeof(llc->addr)); +	/* assign new connection to its SAP */ +	llc_sap_add_socket(sap, sk); +	sock_reset_flag(sk, SOCK_ZAPPED); +	rc = 0; +out: +	return rc; +} + +/** + *	llc_ui_bind - bind a socket to a specific address. + *	@sock: Socket to bind an address to. + *	@uaddr: Address the user wants the socket bound to. + *	@addrlen: Length of the uaddr structure. + * + *	Bind a socket to a specific address. For llc a user is able to bind to + *	a specific sap only or mac + sap. If the user only specifies a sap and + *	a null dmac (all zeros) the user is attempting to bind to an entire + *	sap. This will stop anyone else on the local system from using that + *	sap. If someone else has a mac + sap open the bind to null + sap will + *	fail. + *	If the user desires to bind to a specific mac + sap, it is possible to + *	have multiple sap connections via multiple macs. + *	Bind and autobind for that matter must enforce the correct sap usage + *	otherwise all hell will break loose. + *	Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) +{ +	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; +	struct sock *sk = sock->sk; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_sap *sap; +	int rc = -EINVAL; + +	dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap); +	if (!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)) +		goto out; +	rc = -EAFNOSUPPORT; +	if (addr->sllc_family != AF_LLC) +		goto out; +	if (!addr->sllc_sap) { +		rc = -EUSERS; +		addr->sllc_sap = llc_ui_autoport(); +		if (!addr->sllc_sap) +			goto out; +	} +	sap = llc_sap_find(addr->sllc_sap); +	if (!sap) { +		sap = llc_sap_open(addr->sllc_sap, NULL); +		rc = -EBUSY; /* some other network layer is using the sap */ +		if (!sap) +			goto out; +	} else { +		struct llc_addr laddr, daddr; +		struct sock *ask; + +		memset(&laddr, 0, sizeof(laddr)); +		memset(&daddr, 0, sizeof(daddr)); +		/* +		 * FIXME: check if the the address is multicast, +		 * 	  only SOCK_DGRAM can do this. +		 */ +		memcpy(laddr.mac, addr->sllc_mac, IFHWADDRLEN); +		laddr.lsap = addr->sllc_sap; +		rc = -EADDRINUSE; /* mac + sap clash. */ +		ask = llc_lookup_established(sap, &daddr, &laddr); +		if (ask) { +			sock_put(ask); +			goto out; +		} +	} +	llc->laddr.lsap = addr->sllc_sap; +	memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN); +	memcpy(&llc->addr, addr, sizeof(llc->addr)); +	/* assign new connection to its SAP */ +	llc_sap_add_socket(sap, sk); +	sock_reset_flag(sk, SOCK_ZAPPED); +	rc = 0; +out: +	return rc; +} + +/** + *	llc_ui_shutdown - shutdown a connect llc2 socket. + *	@sock: Socket to shutdown. + *	@how: What part of the socket to shutdown. + * + *	Shutdown a connected llc2 socket. Currently this function only supports + *	shutting down both sends and receives (2), we could probably make this + *	function such that a user can shutdown only half the connection but not + *	right now. + *	Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_shutdown(struct socket *sock, int how) +{ +	struct sock *sk = sock->sk; +	int rc = -ENOTCONN; + +	lock_sock(sk); +	if (sk->sk_state != TCP_ESTABLISHED) +		goto out; +	rc = -EINVAL; +	if (how != 2) +		goto out; +	rc = llc_send_disc(sk); +	if (!rc) +		rc = llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); +	/* Wake up anyone sleeping in poll */ +	sk->sk_state_change(sk); +out: +	release_sock(sk); +	return rc; +} + +/** + *	llc_ui_connect - Connect to a remote llc2 mac + sap. + *	@sock: Socket which will be connected to the remote destination. + *	@uaddr: Remote and possibly the local address of the new connection. + *	@addrlen: Size of uaddr structure. + *	@flags: Operational flags specified by the user. + * + *	Connect to a remote llc2 mac + sap. The caller must specify the + *	destination mac and address to connect to. If the user hasn't previously + *	called bind(2) with a smac the address of the first interface of the + *	specified arp type will be used. + *	This function will autobind if user did not previously call bind. + *	Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, +			  int addrlen, int flags) +{ +	struct sock *sk = sock->sk; +	struct llc_sock *llc = llc_sk(sk); +	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; +	struct net_device *dev; +	int rc = -EINVAL; + +	lock_sock(sk); +	if (addrlen != sizeof(*addr)) +		goto out; +	rc = -EAFNOSUPPORT; +	if (addr->sllc_family != AF_LLC) +		goto out; +	/* bind connection to sap if user hasn't done it. */ +	if (sock_flag(sk, SOCK_ZAPPED)) { +		/* bind to sap with null dev, exclusive */ +		rc = llc_ui_autobind(sock, addr); +		if (rc) +			goto out; +		llc->daddr.lsap = addr->sllc_sap; +		memcpy(llc->daddr.mac, addr->sllc_mac, IFHWADDRLEN); +	} +	dev = llc->dev; +	if (sk->sk_type != SOCK_STREAM) +		goto out; +	rc = -EALREADY; +	if (sock->state == SS_CONNECTING) +		goto out; +	sock->state = SS_CONNECTING; +	sk->sk_state   = TCP_SYN_SENT; +	llc->link   = llc_ui_next_link_no(llc->sap->laddr.lsap); +	rc = llc_establish_connection(sk, dev->dev_addr, +				      addr->sllc_mac, addr->sllc_sap); +	if (rc) { +		dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__); +		sock->state  = SS_UNCONNECTED; +		sk->sk_state = TCP_CLOSE; +		goto out; +	} +	rc = llc_ui_wait_for_conn(sk, sk->sk_rcvtimeo); +	if (rc) +		dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc); +out: +	release_sock(sk); +	return rc; +} + +/** + *	llc_ui_listen - allow a normal socket to accept incoming connections + *	@sock: Socket to allow incoming connections on. + *	@backlog: Number of connections to queue. + * + *	Allow a normal socket to accept incoming connections. + *	Returns 0 upon success, negative otherwise. + */ +static int llc_ui_listen(struct socket *sock, int backlog) +{ +	struct sock *sk = sock->sk; +	int rc = -EINVAL; + +	lock_sock(sk); +	if (sock->state != SS_UNCONNECTED) +		goto out; +	rc = -EOPNOTSUPP; +	if (sk->sk_type != SOCK_STREAM) +		goto out; +	rc = -EAGAIN; +	if (sock_flag(sk, SOCK_ZAPPED)) +		goto out; +	rc = 0; +	if (!(unsigned)backlog)	/* BSDism */ +		backlog = 1; +	sk->sk_max_ack_backlog = backlog; +	if (sk->sk_state != TCP_LISTEN) { +		sk->sk_ack_backlog = 0; +		sk->sk_state	   = TCP_LISTEN; +	} +	sk->sk_socket->flags |= __SO_ACCEPTCON; +out: +	release_sock(sk); +	return rc; +} + +static int llc_ui_wait_for_disc(struct sock *sk, int timeout) +{ +	DECLARE_WAITQUEUE(wait, current); +	int rc; + +	add_wait_queue_exclusive(sk->sk_sleep, &wait); +	for (;;) { +		__set_current_state(TASK_INTERRUPTIBLE); +		rc = 0; +		if (sk->sk_state != TCP_CLOSE) { +			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_conn(struct sock *sk, int timeout) +{ +	DECLARE_WAITQUEUE(wait, current); +	int rc; + +	add_wait_queue_exclusive(sk->sk_sleep, &wait); +	for (;;) { +		__set_current_state(TASK_INTERRUPTIBLE); +		rc = -EAGAIN; +		if (sk->sk_state == TCP_CLOSE) +			break; +		rc = 0; +		if (sk->sk_state != TCP_ESTABLISHED) { +			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_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_sock *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_sock *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); +	sock_reset_flag(newsk, SOCK_ZAPPED); +	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_sock *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 (sock_flag(sk, SOCK_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_sock *llc = llc_sk(sk); +	int rc = 0; + +	lock_sock(sk); +	if (sock_flag(sk, SOCK_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_sock *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_sock *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 = proto_register(&llc_proto, 0); + +	if (rc != 0) +		goto out; + +	llc_build_offset_table(); +	llc_station_init(); +	llc_ui_sap_last_autoport = LLC_SAP_DYN_START; +	rc = llc_proc_init(); +	if (rc != 0) +		goto out_unregister_llc_proto; +	sock_register(&llc_ui_family_ops); +	llc_add_pack(LLC_DEST_SAP, llc_sap_handler); +	llc_add_pack(LLC_DEST_CONN, llc_conn_handler); +out: +	return rc; +out_unregister_llc_proto: +	proto_unregister(&llc_proto); +	goto out; +} + +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(); +	proto_unregister(&llc_proto); +} + +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); diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c new file mode 100644 index 000000000000..b218be4c10ec --- /dev/null +++ b/net/llc/llc_c_ac.c @@ -0,0 +1,1514 @@ +/* + * llc_c_ac.c - actions performed during connection state transition. + * + * Description: + *   Functions in this module are implementation of connection component actions + *   Details of actions can be found in IEEE-802.2 standard document. + *   All functions have one connection and one event as input argument. All of + *   them return 0 On success and 1 otherwise. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/netdevice.h> +#include <net/llc_conn.h> +#include <net/llc_sap.h> +#include <net/sock.h> +#include <net/llc_c_ev.h> +#include <net/llc_c_ac.h> +#include <net/llc_c_st.h> +#include <net/llc_pdu.h> +#include <net/llc.h> + +#include "llc_output.h" + +static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb); +static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb); +static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev); + +static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb); + +static int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk, +					       struct sk_buff *skb); + +static int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb); + +#define INCORRECT 0 + +int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (llc->remote_busy_flag) { +		u8 nr; +		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +		llc->remote_busy_flag = 0; +		del_timer(&llc->busy_state_timer.timer); +		nr = LLC_I_GET_NR(pdu); +		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0); +	} +	return 0; +} + +int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOTCONN; +	u8 dsap; +	struct llc_sap *sap; + +	llc_pdu_decode_dsap(skb, &dsap); +	sap = llc_sap_find(dsap); +	if (sap) { +		struct llc_conn_state_ev *ev = llc_conn_ev(skb); +		struct llc_sock *llc = llc_sk(sk); + +		llc_pdu_decode_sa(skb, llc->daddr.mac); +		llc_pdu_decode_da(skb, llc->laddr.mac); +		llc->dev = skb->dev; +		ev->ind_prim = LLC_CONN_PRIM; +		rc = 0; +	} +	return rc; +} + +int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->cfm_prim = LLC_CONN_PRIM; +	return 0; +} + +static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->cfm_prim = LLC_DATA_PRIM; +	return 0; +} + +int llc_conn_ac_data_ind(struct sock *sk, struct sk_buff *skb) +{ +	llc_conn_rtn_pdu(sk, skb); +	return 0; +} + +int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); +	u8 reason = 0; +	int rc = 0; + +	if (ev->type == LLC_CONN_EV_TYPE_PDU) { +		struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +		if (LLC_PDU_IS_RSP(pdu) && +		    LLC_PDU_TYPE_IS_U(pdu) && +		    LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM) +			reason = LLC_DISC_REASON_RX_DM_RSP_PDU; +		else if (LLC_PDU_IS_CMD(pdu) && +			   LLC_PDU_TYPE_IS_U(pdu) && +			   LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC) +			reason = LLC_DISC_REASON_RX_DISC_CMD_PDU; +	} else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR) +		reason = LLC_DISC_REASON_ACK_TMR_EXP; +	else { +		reason = 0; +		rc = -EINVAL; +	} +	if (!rc) { +		ev->reason   = reason; +		ev->ind_prim = LLC_DISC_PRIM; +	} +	return rc; +} + +int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->reason   = ev->status; +	ev->cfm_prim = LLC_DISC_PRIM; +	return 0; +} + +int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb) +{ +	u8 reason = 0; +	int rc = 1; +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); +	struct llc_sock *llc = llc_sk(sk); + +	switch (ev->type) { +	case LLC_CONN_EV_TYPE_PDU: +		if (LLC_PDU_IS_RSP(pdu) && +		    LLC_PDU_TYPE_IS_U(pdu) && +		    LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR) { +			reason = LLC_RESET_REASON_LOCAL; +			rc = 0; +		} else if (LLC_PDU_IS_CMD(pdu) && +			   LLC_PDU_TYPE_IS_U(pdu) && +			   LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME) { +			reason = LLC_RESET_REASON_REMOTE; +			rc = 0; +		} else { +			reason = 0; +			rc  = 1; +		} +		break; +	case LLC_CONN_EV_TYPE_ACK_TMR: +	case LLC_CONN_EV_TYPE_P_TMR: +	case LLC_CONN_EV_TYPE_REJ_TMR: +	case LLC_CONN_EV_TYPE_BUSY_TMR: +		if (llc->retry_count > llc->n2) { +			reason = LLC_RESET_REASON_LOCAL; +			rc = 0; +		} else +			rc = 1; +		break; +	} +	if (!rc) { +		ev->reason   = reason; +		ev->ind_prim = LLC_RESET_PRIM; +	} +	return rc; +} + +int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->reason   = 0; +	ev->cfm_prim = LLC_RESET_PRIM; +	return 0; +} + +int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk, +					    struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	if (LLC_PDU_IS_RSP(pdu) && +	    LLC_PDU_TYPE_IS_I(pdu) && +	    LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf) +		llc_conn_ac_clear_remote_busy(sk, skb); +	return 0; +} + +int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk, +					       struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (llc->data_flag == 2) +		del_timer(&llc->rej_sent_timer.timer); +	return 0; +} + +int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_CMD); +		llc_pdu_init_as_disc_cmd(nskb, 1); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +		llc_conn_ac_set_p_flag_1(sk, skb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		u8 f_bit; + +		nskb->dev = llc->dev; +		llc_pdu_decode_pf_bit(skb, &f_bit); +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_dm_rsp(nskb, f_bit); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		u8 f_bit = 1; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_dm_rsp(nskb, f_bit); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb) +{ +	u8 f_bit; +	int rc = -ENOBUFS; +	struct sk_buff *nskb; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	struct llc_sock *llc = llc_sk(sk); + +	llc->rx_pdu_hdr = *((u32 *)pdu); +	if (LLC_PDU_IS_CMD(pdu)) +		llc_pdu_decode_pf_bit(skb, &f_bit); +	else +		f_bit = 0; +	nskb = llc_alloc_frame(); +	if (nskb) { +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS, +					 llc->vR, INCORRECT); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		u8 f_bit = 0; +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)&llc->rx_pdu_hdr; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS, +					 llc->vR, INCORRECT); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) +{ +	u8 f_bit; +	int rc = -ENOBUFS; +	struct sk_buff *nskb; + +	llc_pdu_decode_pf_bit(skb, &f_bit); +	nskb = llc_alloc_frame(); +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS, +					 llc->vR, INCORRECT); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_sap *sap = llc->sap; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, +			    llc->daddr.lsap, LLC_PDU_CMD); +	llc_pdu_init_as_i_cmd(skb, 1, llc->vS, llc->vR); +	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); +	if (!rc) { +		llc_conn_send_pdu(sk, skb); +		llc_conn_ac_inc_vs_by_1(sk, skb); +	} +	return rc; +} + +static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_sap *sap = llc->sap; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, +			    llc->daddr.lsap, LLC_PDU_CMD); +	llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR); +	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); +	if (!rc) { +		llc_conn_send_pdu(sk, skb); +		llc_conn_ac_inc_vs_by_1(sk, skb); +	} +	return rc; +} + +int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_sap *sap = llc->sap; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, +			    llc->daddr.lsap, LLC_PDU_CMD); +	llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR); +	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); +	if (!rc) { +		llc_conn_send_pdu(sk, skb); +		llc_conn_ac_inc_vs_by_1(sk, skb); +	} +	return 0; +} + +int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 nr = LLC_I_GET_NR(pdu); + +	llc_conn_resend_i_pdu_as_cmd(sk, nr, 0); +	return 0; +} + +int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk, +						struct sk_buff *skb) +{ +	u8 nr; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (!rc) +			llc_conn_send_pdu(sk, nskb); +		else +			kfree_skb(skb); +	} +	if (rc) { +		nr = LLC_I_GET_NR(pdu); +		rc = 0; +		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0); +	} +	return rc; +} + +int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 nr = LLC_I_GET_NR(pdu); + +	llc_conn_resend_i_pdu_as_rsp(sk, nr, 1); +	return 0; +} + +int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_CMD); +		llc_pdu_init_as_rej_cmd(nskb, 1, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		u8 f_bit = 1; +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		u8 f_bit = 0; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_CMD); +		llc_pdu_init_as_rnr_cmd(nskb, 1, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		u8 f_bit = 1; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		u8 f_bit = 0; +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (!llc->remote_busy_flag) { +		llc->remote_busy_flag = 1; +		mod_timer(&llc->busy_state_timer.timer, +			 jiffies + llc->busy_state_timer.expire * HZ); +	} +	return 0; +} + +int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rnr_rsp(nskb, 0, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_CMD); +		llc_pdu_init_as_rr_cmd(nskb, 1, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		u8 f_bit = 1; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; +		u8 f_bit = 1; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +void llc_conn_set_p_flag(struct sock *sk, u8 value) +{ +	int state_changed = llc_sk(sk)->p_flag && !value; + +	llc_sk(sk)->p_flag = value; + +	if (state_changed) +		sk->sk_state_change(sk); +} + +int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); +	struct llc_sock *llc = llc_sk(sk); + +	if (nskb) { +		struct llc_sap *sap = llc->sap; +		u8 *dmac = llc->daddr.mac; + +		if (llc->dev->flags & IFF_LOOPBACK) +			dmac = llc->dev->dev_addr; +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_CMD); +		llc_pdu_init_as_sabme_cmd(nskb, 1); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, dmac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +		llc_conn_set_p_flag(sk, 1); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) +{ +	u8 f_bit; +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	llc_pdu_decode_pf_bit(skb, &f_bit); +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_ua_rsp(nskb, f_bit); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +int llc_conn_ac_set_s_flag_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->s_flag = 0; +	return 0; +} + +int llc_conn_ac_set_s_flag_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->s_flag = 1; +	return 0; +} + +int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	llc_conn_set_p_flag(sk, 1); +	mod_timer(&llc->pf_cycle_timer.timer, +		  jiffies + llc->pf_cycle_timer.expire * HZ); +	return 0; +} + +/** + *	llc_conn_ac_send_ack_if_needed - check if ack is needed + *	@sk: current connection structure + *	@skb: current event + * + *	Checks number of received PDUs which have not been acknowledged, yet, + *	If number of them reaches to "npta"(Number of PDUs To Acknowledge) then + *	sends an RR response as acknowledgement for them.  Returns 0 for + *	success, 1 otherwise. + */ +int llc_conn_ac_send_ack_if_needed(struct sock *sk, struct sk_buff *skb) +{ +	u8 pf_bit; +	struct llc_sock *llc = llc_sk(sk); + +	llc_pdu_decode_pf_bit(skb, &pf_bit); +	llc->ack_pf |= pf_bit & 1; +	if (!llc->ack_must_be_send) { +		llc->first_pdu_Ns = llc->vR; +		llc->ack_must_be_send = 1; +		llc->ack_pf = pf_bit & 1; +	} +	if (((llc->vR - llc->first_pdu_Ns + 129) % 128) >= llc->npta) { +		llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, skb); +		llc->ack_must_be_send	= 0; +		llc->ack_pf		= 0; +		llc_conn_ac_inc_npta_value(sk, skb); +	} +	return 0; +} + +/** + *	llc_conn_ac_rst_sendack_flag - resets ack_must_be_send flag + *	@sk: current connection structure + *	@skb: current event + * + *	This action resets ack_must_be_send flag of given connection, this flag + *	indicates if there is any PDU which has not been acknowledged yet. + *	Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_rst_sendack_flag(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->ack_must_be_send = llc_sk(sk)->ack_pf = 0; +	return 0; +} + +/** + *	llc_conn_ac_send_i_rsp_f_set_ackpf - acknowledge received PDUs + *	@sk: current connection structure + *	@skb: current event + * + *	Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to + *	all received PDUs which have not been acknowledged, yet. ack_pf flag is + *	set to one if one PDU with p-bit set to one is received.  Returns 0 for + *	success, 1 otherwise. + */ +static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, +					      struct sk_buff *skb) +{ +	int rc; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_sap *sap = llc->sap; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, +			    llc->daddr.lsap, LLC_PDU_RSP); +	llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR); +	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); +	if (!rc) { +		llc_conn_send_pdu(sk, skb); +		llc_conn_ac_inc_vs_by_1(sk, skb); +	} +	return rc; +} + +/** + *	llc_conn_ac_send_i_as_ack - sends an I-format PDU to acknowledge rx PDUs + *	@sk: current connection structure. + *	@skb: current event. + * + *	This action sends an I-format PDU as acknowledge to received PDUs which + *	have not been acknowledged, yet, if there is any. By using of this + *	action number of acknowledgements decreases, this technic is called + *	piggy backing. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (llc->ack_must_be_send) { +		llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb); +		llc->ack_must_be_send = 0 ; +		llc->ack_pf = 0; +	} else +		llc_conn_ac_send_i_cmd_p_set_0(sk, skb); +	return 0; +} + +/** + *	llc_conn_ac_send_rr_rsp_f_set_ackpf - ack all rx PDUs not yet acked + *	@sk: current connection structure. + *	@skb: current event. + * + *	This action sends an RR response with f-bit set to ack_pf flag as + *	acknowledge to all received PDUs which have not been acknowledged, yet, + *	if there is any. ack_pf flag indicates if a PDU has been received with + *	p-bit set to one. Returns 0 for success, 1 otherwise. + */ +static int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk, +					       struct sk_buff *skb) +{ +	int rc = -ENOBUFS; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (nskb) { +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		nskb->dev = llc->dev; +		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, +				    llc->daddr.lsap, LLC_PDU_RSP); +		llc_pdu_init_as_rr_rsp(nskb, llc->ack_pf, llc->vR); +		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac); +		if (rc) +			goto free; +		llc_conn_send_pdu(sk, nskb); +	} +out: +	return rc; +free: +	kfree_skb(nskb); +	goto out; +} + +/** + *	llc_conn_ac_inc_npta_value - tries to make value of npta greater + *	@sk: current connection structure. + *	@skb: current event. + * + *	After "inc_cntr" times calling of this action, "npta" increase by one. + *	this action tries to make vale of "npta" greater as possible; number of + *	acknowledgements decreases by increasing of "npta". Returns 0 for + *	success, 1 otherwise. + */ +static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (!llc->inc_cntr) { +		llc->dec_step = 0; +		llc->dec_cntr = llc->inc_cntr = 2; +		++llc->npta; +		if (llc->npta > 127) +			llc->npta = 127 ; +	} else +		--llc->inc_cntr; +	return 0; +} + +/** + *	llc_conn_ac_adjust_npta_by_rr - decreases "npta" by one + *	@sk: current connection structure. + *	@skb: current event. + * + *	After receiving "dec_cntr" times RR command, this action decreases + *	"npta" by one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (!llc->connect_step && !llc->remote_busy_flag) { +		if (!llc->dec_step) { +			if (!llc->dec_cntr) { +				llc->inc_cntr = llc->dec_cntr = 2; +				if (llc->npta > 0) +					llc->npta = llc->npta - 1; +			} else +				llc->dec_cntr -=1; +		} +	} else +		llc->connect_step = 0 ; +	return 0; +} + +/** + *	llc_conn_ac_adjust_npta_by_rnr - decreases "npta" by one + *	@sk: current connection structure. + *	@skb: current event. + * + *	After receiving "dec_cntr" times RNR command, this action decreases + *	"npta" by one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (llc->remote_busy_flag) +		if (!llc->dec_step) { +			if (!llc->dec_cntr) { +				llc->inc_cntr = llc->dec_cntr = 2; +				if (llc->npta > 0) +					--llc->npta; +			} else +				--llc->dec_cntr; +		} +	return 0; +} + +/** + *	llc_conn_ac_dec_tx_win_size - decreases tx window size + *	@sk: current connection structure. + *	@skb: current event. + * + *	After receiving of a REJ command or response, transmit window size is + *	decreased by number of PDUs which are outstanding yet. Returns 0 for + *	success, 1 otherwise. + */ +int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); +	u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q); + +	llc->k -= unacked_pdu; +	if (llc->k < 2) +		llc->k = 2; +	return 0; +} + +/** + *	llc_conn_ac_inc_tx_win_size - tx window size is inc by 1 + *	@sk: current connection structure. + *	@skb: current event. + * + *	After receiving an RR response with f-bit set to one, transmit window + *	size is increased by one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	llc->k += 1; +	if (llc->k > 128) +		llc->k = 128 ; +	return 0; +} + +int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	del_timer(&llc->pf_cycle_timer.timer); +	del_timer(&llc->ack_timer.timer); +	del_timer(&llc->rej_sent_timer.timer); +	del_timer(&llc->busy_state_timer.timer); +	llc->ack_must_be_send = 0; +	llc->ack_pf = 0; +	return 0; +} + +int llc_conn_ac_stop_other_timers(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	del_timer(&llc->rej_sent_timer.timer); +	del_timer(&llc->pf_cycle_timer.timer); +	del_timer(&llc->busy_state_timer.timer); +	llc->ack_must_be_send = 0; +	llc->ack_pf = 0; +	return 0; +} + +int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire * HZ); +	return 0; +} + +int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	mod_timer(&llc->rej_sent_timer.timer, +		  jiffies + llc->rej_sent_timer.expire * HZ); +	return 0; +} + +int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk, +					     struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	if (!timer_pending(&llc->ack_timer.timer)) +		mod_timer(&llc->ack_timer.timer, +			  jiffies + llc->ack_timer.expire * HZ); +	return 0; +} + +int llc_conn_ac_stop_ack_timer(struct sock *sk, struct sk_buff *skb) +{ +	del_timer(&llc_sk(sk)->ack_timer.timer); +	return 0; +} + +int llc_conn_ac_stop_p_timer(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_sock *llc = llc_sk(sk); + +	del_timer(&llc->pf_cycle_timer.timer); +	llc_conn_set_p_flag(sk, 0); +	return 0; +} + +int llc_conn_ac_stop_rej_timer(struct sock *sk, struct sk_buff *skb) +{ +	del_timer(&llc_sk(sk)->rej_sent_timer.timer); +	return 0; +} + +int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb) +{ +	int acked; +	u16 unacked = 0; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	struct llc_sock *llc = llc_sk(sk); + +	llc->last_nr = PDU_SUPV_GET_Nr(pdu); +	acked = llc_conn_remove_acked_pdus(sk, llc->last_nr, &unacked); +	/* On loopback we don't queue I frames in unack_pdu_q queue. */ +	if (acked > 0 || (llc->dev->flags & IFF_LOOPBACK)) { +		llc->retry_count = 0; +		del_timer(&llc->ack_timer.timer); +		if (llc->failed_data_req) { +			/* already, we did not accept data from upper layer +			 * (tx_window full or unacceptable state). Now, we +			 * can send data and must inform to upper layer. +			 */ +			llc->failed_data_req = 0; +			llc_conn_ac_data_confirm(sk, skb); +		} +		if (unacked) +			mod_timer(&llc->ack_timer.timer, +				  jiffies + llc->ack_timer.expire * HZ); +	} else if (llc->failed_data_req) { +		u8 f_bit; + +		llc_pdu_decode_pf_bit(skb, &f_bit); +		if (f_bit == 1) { +			llc->failed_data_req = 0; +			llc_conn_ac_data_confirm(sk, skb); +		} +	} +	return 0; +} + +int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	if (LLC_PDU_IS_RSP(pdu)) { +		u8 f_bit; + +		llc_pdu_decode_pf_bit(skb, &f_bit); +		if (f_bit) { +			llc_conn_set_p_flag(sk, 0); +			llc_conn_ac_stop_p_timer(sk, skb); +		} +	} +	return 0; +} + +int llc_conn_ac_set_data_flag_2(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->data_flag = 2; +	return 0; +} + +int llc_conn_ac_set_data_flag_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->data_flag = 0; +	return 0; +} + +int llc_conn_ac_set_data_flag_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->data_flag = 1; +	return 0; +} + +int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock *sk, +						  struct sk_buff *skb) +{ +	if (!llc_sk(sk)->data_flag) +		llc_sk(sk)->data_flag = 1; +	return 0; +} + +int llc_conn_ac_set_p_flag_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_conn_set_p_flag(sk, 0); +	return 0; +} + +static int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_conn_set_p_flag(sk, 1); +	return 0; +} + +int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->remote_busy_flag = 0; +	return 0; +} + +int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->cause_flag = 0; +	return 0; +} + +int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->cause_flag = 1; +	return 0; +} + +int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->retry_count = 0; +	return 0; +} + +int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->retry_count++; +	return 0; +} + +int llc_conn_ac_set_vr_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->vR = 0; +	return 0; +} + +int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->vR = PDU_GET_NEXT_Vr(llc_sk(sk)->vR); +	return 0; +} + +int llc_conn_ac_set_vs_0(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->vS = 0; +	return 0; +} + +int llc_conn_ac_set_vs_nr(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->vS = llc_sk(sk)->last_nr; +	return 0; +} + +int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % 128; +	return 0; +} + +void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data) +{ +	struct sock *sk = (struct sock *)timeout_data; +	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + +	bh_lock_sock(sk); +	if (skb) { +		struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +		skb->sk  = sk; +		ev->type = LLC_CONN_EV_TYPE_P_TMR; +		llc_process_tmr_ev(sk, skb); +	} +	bh_unlock_sock(sk); +} + +void llc_conn_busy_tmr_cb(unsigned long timeout_data) +{ +	struct sock *sk = (struct sock *)timeout_data; +	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + +	bh_lock_sock(sk); +	if (skb) { +		struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +		skb->sk  = sk; +		ev->type = LLC_CONN_EV_TYPE_BUSY_TMR; +		llc_process_tmr_ev(sk, skb); +	} +	bh_unlock_sock(sk); +} + +void llc_conn_ack_tmr_cb(unsigned long timeout_data) +{ +	struct sock* sk = (struct sock *)timeout_data; +	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + +	bh_lock_sock(sk); +	if (skb) { +		struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +		skb->sk  = sk; +		ev->type = LLC_CONN_EV_TYPE_ACK_TMR; +		llc_process_tmr_ev(sk, skb); +	} +	bh_unlock_sock(sk); +} + +void llc_conn_rej_tmr_cb(unsigned long timeout_data) +{ +	struct sock *sk = (struct sock *)timeout_data; +	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + +	bh_lock_sock(sk); +	if (skb) { +		struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +		skb->sk  = sk; +		ev->type = LLC_CONN_EV_TYPE_REJ_TMR; +		llc_process_tmr_ev(sk, skb); +	} +	bh_unlock_sock(sk); +} + +int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk(sk)->X = llc_sk(sk)->vS; +	llc_conn_ac_set_vs_nr(sk, skb); +	return 0; +} + +int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 nr = PDU_SUPV_GET_Nr(pdu); + +	if (llc_circular_between(llc_sk(sk)->vS, nr, llc_sk(sk)->X)) +		llc_conn_ac_set_vs_nr(sk, skb); +	return 0; +} + +/* + * Non-standard actions; these not contained in IEEE specification; for + * our own usage + */ +/** + *	llc_conn_disc - removes connection from SAP list and frees it + *	@sk: closed connection + *	@skb: occurred event + */ +int llc_conn_disc(struct sock *sk, struct sk_buff *skb) +{ +	/* FIXME: this thing seems to want to die */ +	return 0; +} + +/** + *	llc_conn_reset - resets connection + *	@sk : reseting connection. + *	@skb: occurred event. + * + *	Stop all timers, empty all queues and reset all flags. + */ +int llc_conn_reset(struct sock *sk, struct sk_buff *skb) +{ +	llc_sk_reset(sk); +	return 0; +} + +/** + *	llc_circular_between - designates that b is between a and c or not + *	@a: lower bound + *	@b: element to see if is between a and b + *	@c: upper bound + * + *	This function designates that b is between a and c or not (for example, + *	0 is between 127 and 1). Returns 1 if b is between a and c, 0 + *	otherwise. + */ +u8 llc_circular_between(u8 a, u8 b, u8 c) +{ +	b = b - a; +	c = c - a; +	return b <= c; +} + +/** + *	llc_process_tmr_ev - timer backend + *	@sk: active connection + *	@skb: occurred event + * + *	This function is called from timer callback functions. When connection + *	is busy (during sending a data frame) timer expiration event must be + *	queued. Otherwise this event can be sent to connection state machine. + *	Queued events will process by llc_backlog_rcv function after sending + *	data frame. + */ +static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb) +{ +	if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) { +		printk(KERN_WARNING "%s: timer called on closed connection\n", +		       __FUNCTION__); +		kfree_skb(skb); +	} else { +		if (!sock_owned_by_user(sk)) +			llc_conn_state_process(sk, skb); +		else { +			llc_set_backlog_type(skb, LLC_EVENT); +			sk_add_backlog(sk, skb); +		} +	} +} diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c new file mode 100644 index 000000000000..cd130c3b72bc --- /dev/null +++ b/net/llc/llc_c_ev.c @@ -0,0 +1,769 @@ +/* + * llc_c_ev.c - Connection component state transition event qualifiers + * + * A 'state' consists of a number of possible event matching functions, + * the actions associated with each being executed when that event is + * matched; a 'state machine' accepts events in a serial fashion from an + * event queue. Each event is passed to each successive event matching + * function until a match is made (the event matching function returns + * success, or '0') or the list of event matching functions is exhausted. + * If a match is made, the actions associated with the event are executed + * and the state is changed to that event's transition state. Before some + * events are recognized, even after a match has been made, a certain + * number of 'event qualifier' functions must also be executed. If these + * all execute successfully, then the event is finally executed. + * + * These event functions must return 0 for success, to show a matched + * event, of 1 if the event does not match. Event qualifier functions + * must return a 0 for success or a non-zero for failure. Each function + * is simply responsible for verifying one single thing and returning + * either a success or failure. + * + * All of followed event functions are described in 802.2 LLC Protocol + * standard document except two functions that we added that will explain + * in their comments, at below. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/netdevice.h> +#include <net/llc_conn.h> +#include <net/llc_sap.h> +#include <net/sock.h> +#include <net/llc_c_ev.h> +#include <net/llc_pdu.h> + +#if 1 +#define dprintk(args...) printk(KERN_DEBUG args) +#else +#define dprintk(args...) +#endif + +extern u16 llc_circular_between(u8 a, u8 b, u8 c); + +/** + *	llc_util_ns_inside_rx_window - check if sequence number is in rx window + *	@ns: sequence number of received pdu. + *	@vr: sequence number which receiver expects to receive. + *	@rw: receive window size of receiver. + * + *	Checks if sequence number of received PDU is in range of receive + *	window. Returns 0 for success, 1 otherwise + */ +static u16 llc_util_ns_inside_rx_window(u8 ns, u8 vr, u8 rw) +{ +	return !llc_circular_between(vr, ns, +				     (vr + rw - 1) % LLC_2_SEQ_NBR_MODULO); +} + +/** + *	llc_util_nr_inside_tx_window - check if sequence number is in tx window + *	@sk: current connection. + *	@nr: N(R) of received PDU. + * + *	This routine checks if N(R) of received PDU is in range of transmit + *	window; on the other hand checks if received PDU acknowledges some + *	outstanding PDUs that are in transmit window. Returns 0 for success, 1 + *	otherwise. + */ +static u16 llc_util_nr_inside_tx_window(struct sock *sk, u8 nr) +{ +	u8 nr1, nr2; +	struct sk_buff *skb; +	struct llc_pdu_sn *pdu; +	struct llc_sock *llc = llc_sk(sk); +	int rc = 0; + +	if (llc->dev->flags & IFF_LOOPBACK) +		goto out; +	rc = 1; +	if (!skb_queue_len(&llc->pdu_unack_q)) +		goto out; +	skb = skb_peek(&llc->pdu_unack_q); +	pdu = llc_pdu_sn_hdr(skb); +	nr1 = LLC_I_GET_NS(pdu); +	skb = skb_peek_tail(&llc->pdu_unack_q); +	pdu = llc_pdu_sn_hdr(skb); +	nr2 = LLC_I_GET_NS(pdu); +	rc = !llc_circular_between(nr1, nr, (nr2 + 1) % LLC_2_SEQ_NBR_MODULO); +out: +	return rc; +} + +int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->prim == LLC_CONN_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->prim == LLC_DATA_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->prim == LLC_DISC_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->prim == LLC_RESET_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type == LLC_CONN_EV_TYPE_SIMPLE && +	       ev->prim_type == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1; +} + +int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type == LLC_CONN_EV_TYPE_SIMPLE && +	       ev->prim_type == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1; +} + +int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb) +{ +	return 1; +} + +int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC ? 0 : 1; +} + +int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM ? 0 : 1; +} + +int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return llc_conn_space(sk, skb) && +	       LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_0(pdu) && +	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return llc_conn_space(sk, skb) && +	       LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_1(pdu) && +	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk, +					      struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_0(pdu) && ns != vr && +	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk, +					      struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_1(pdu) && ns != vr && +	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, +					     struct sk_buff *skb) +{ +	struct llc_pdu_sn * pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); +	u16 rc = LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && +		 llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +	if (!rc) +		dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", +			__FUNCTION__, llc_sk(sk)->state, ns, vr); +	return rc; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return llc_conn_space(sk, skb) && +	       LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_0(pdu) && +	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_1(pdu) && +	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return llc_conn_space(sk, skb) && +	       LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk, +					      struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_0(pdu) && ns != vr && +	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk, +					      struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && +	       LLC_I_PF_IS_1(pdu) && ns != vr && +	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk, +					      struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && +	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, +					     struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vr = llc_sk(sk)->vR; +	u8 ns = LLC_I_GET_NS(pdu); +	u16 rc = LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && +		 llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +	if (!rc) +		dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", +			__FUNCTION__, llc_sk(sk)->state, ns, vr); +	return rc; +} + +int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_0(pdu) && +	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_1(pdu) && +	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_0(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_1(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_0(pdu) && +	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_1(pdu) && +	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_0(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_1(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_0(pdu) && +	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_1(pdu) && +	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return llc_conn_space(sk, skb) && +	       LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_0(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	return llc_conn_space(sk, skb) && +	       LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && +	       LLC_S_PF_IS_1(pdu) && +	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; +} + +int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME ? 0 : 1; +} + +int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_UA ? 0 : 1; +} + +int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	if (LLC_PDU_IS_CMD(pdu)) { +		if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { +			if (LLC_I_PF_IS_1(pdu)) +				rc = 0; +		} else if (LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PF_IS_1(pdu)) +			rc = 0; +	} +	return rc; +} + +int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	if (LLC_PDU_IS_CMD(pdu)) { +		if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) +			rc = 0; +		else if (LLC_PDU_TYPE_IS_U(pdu)) +			switch (LLC_U_PDU_CMD(pdu)) { +			case LLC_2_PDU_CMD_SABME: +			case LLC_2_PDU_CMD_DISC: +				rc = 0; +				break; +			} +	} +	return rc; +} + +int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	if (LLC_PDU_IS_RSP(pdu)) { +		if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { +			if (LLC_I_PF_IS_1(pdu)) +				rc = 0; +		} else if (LLC_PDU_TYPE_IS_U(pdu)) +			switch (LLC_U_PDU_RSP(pdu)) { +			case LLC_2_PDU_RSP_UA: +			case LLC_2_PDU_RSP_DM: +			case LLC_2_PDU_RSP_FRMR: +				if (LLC_U_PF_IS_1(pdu)) +					rc = 0; +				break; +			} +	} +	return rc; +} + +int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	if (LLC_PDU_IS_RSP(pdu)) { +		if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) +			rc = 0; +		else if (LLC_PDU_TYPE_IS_U(pdu)) +			switch (LLC_U_PDU_RSP(pdu)) { +			case LLC_2_PDU_RSP_UA: +			case LLC_2_PDU_RSP_DM: +			case LLC_2_PDU_RSP_FRMR: +				rc = 0; +				break; +			} +	} + +	return rc; +} + +int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, +					       struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vs = llc_sk(sk)->vS; +	u8 nr = LLC_I_GET_NR(pdu); + +	if (LLC_PDU_IS_CMD(pdu) && +	    (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && +	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { +		dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", +			__FUNCTION__, llc_sk(sk)->state, vs, nr); +		rc = 0; +	} +	return rc; +} + +int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, +					       struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +	u8 vs = llc_sk(sk)->vS; +	u8 nr = LLC_I_GET_NR(pdu); + +	if (LLC_PDU_IS_RSP(pdu) && +	    (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && +	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { +		rc = 0; +		dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", +			__FUNCTION__, llc_sk(sk)->state, vs, nr); +	} +	return rc; +} + +int llc_conn_ev_rx_any_frame(struct sock *sk, struct sk_buff *skb) +{ +	return 0; +} + +int llc_conn_ev_p_tmr_exp(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type != LLC_CONN_EV_TYPE_P_TMR; +} + +int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type != LLC_CONN_EV_TYPE_ACK_TMR; +} + +int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type != LLC_CONN_EV_TYPE_REJ_TMR; +} + +int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type != LLC_CONN_EV_TYPE_BUSY_TMR; +} + +int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct sk_buff *skb) +{ +	return 1; +} + +int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	return ev->type == LLC_CONN_EV_TYPE_SIMPLE && +	       ev->prim_type == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1; +} + +/* Event qualifier functions + * + * these functions simply verify the value of a state flag associated with + * the connection and return either a 0 for success or a non-zero value + * for not-success; verify the event is the type we expect + */ +int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->data_flag != 1; +} + +int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->data_flag; +} + +int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->data_flag != 2; +} + +int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->p_flag != 1; +} + +/** + *	conn_ev_qlfy_last_frame_eq_1 - checks if frame is last in tx window + *	@sk: current connection structure. + *	@skb: current event. + * + *	This function determines when frame which is sent, is last frame of + *	transmit window, if it is then this function return zero else return + *	one.  This function is used for sending last frame of transmit window + *	as I-format command with p-bit set to one. Returns 0 if frame is last + *	frame, 1 otherwise. + */ +int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk, struct sk_buff *skb) +{ +	return !(skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k); +} + +/** + *	conn_ev_qlfy_last_frame_eq_0 - checks if frame isn't last in tx window + *	@sk: current connection structure. + *	@skb: current event. + * + *	This function determines when frame which is sent, isn't last frame of + *	transmit window, if it isn't then this function return zero else return + *	one. Returns 0 if frame isn't last frame, 1 otherwise. + */ +int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk, struct sk_buff *skb) +{ +	return skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k; +} + +int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->p_flag; +} + +int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct sk_buff *skb) +{ +	u8 f_bit; + +	llc_pdu_decode_pf_bit(skb, &f_bit); +	return llc_sk(sk)->p_flag == f_bit ? 0 : 1; +} + +int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->remote_busy_flag; +} + +int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk, struct sk_buff *skb) +{ +	return !llc_sk(sk)->remote_busy_flag; +} + +int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk, struct sk_buff *skb) +{ +	return !(llc_sk(sk)->retry_count < llc_sk(sk)->n2); +} + +int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk, struct sk_buff *skb) +{ +	return !(llc_sk(sk)->retry_count >= llc_sk(sk)->n2); +} + +int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct sk_buff *skb) +{ +	return !llc_sk(sk)->s_flag; +} + +int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->s_flag; +} + +int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk, struct sk_buff *skb) +{ +	return !llc_sk(sk)->cause_flag; +} + +int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk, struct sk_buff *skb) +{ +	return llc_sk(sk)->cause_flag; +} + +int llc_conn_ev_qlfy_set_status_conn(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_CONN; +	return 0; +} + +int llc_conn_ev_qlfy_set_status_disc(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_DISC; +	return 0; +} + +int llc_conn_ev_qlfy_set_status_failed(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_FAILED; +	return 0; +} + +int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk, +					    struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_REMOTE_BUSY; +	return 0; +} + +int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_REFUSE; +	return 0; +} + +int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_CONFLICT; +	return 0; +} + +int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->status = LLC_STATUS_RESET_DONE; +	return 0; +} diff --git a/net/llc/llc_c_st.c b/net/llc/llc_c_st.c new file mode 100644 index 000000000000..818a9428823b --- /dev/null +++ b/net/llc/llc_c_st.c @@ -0,0 +1,4946 @@ +/* + * llc_c_st.c - This module contains state transition of connection component. + * + * Description of event functions and actions there is in 802.2 LLC standard, + * or in "llc_c_ac.c" and "llc_c_ev.c" modules. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/types.h> +#include <net/llc_if.h> +#include <net/llc_sap.h> +#include <net/llc_c_ev.h> +#include <net/llc_c_ac.h> +#include <net/llc_c_st.h> + +#define NONE NULL + +/* COMMON CONNECTION STATE transitions + * Common transitions for + * LLC_CONN_STATE_NORMAL, + * LLC_CONN_STATE_BUSY, + * LLC_CONN_STATE_REJ, + * LLC_CONN_STATE_AWAIT, + * LLC_CONN_STATE_AWAIT_BUSY and + * LLC_CONN_STATE_AWAIT_REJ states + */ +/* State transitions for LLC_CONN_EV_DISC_REQ event */ +static llc_conn_action_t llc_common_actions_1[] = { +	[0] = llc_conn_ac_send_disc_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_1 = { +	.ev	       = llc_conn_ev_disc_req, +	.next_state    = LLC_CONN_STATE_D_CONN, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RESET_REQ event */ +static llc_conn_action_t llc_common_actions_2[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_2 = { +	.ev	       = llc_conn_ev_rst_req, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_2, +}; + +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_common_actions_3[] = { +	[0] = llc_conn_ac_stop_all_timers, +	[1] = llc_conn_ac_set_vs_0, +	[2] = llc_conn_ac_set_vr_0, +	[3] = llc_conn_ac_send_ua_rsp_f_set_p, +	[4] = llc_conn_ac_rst_ind, +	[5] = llc_conn_ac_set_p_flag_0, +	[6] = llc_conn_ac_set_remote_busy_0, +	[7] = llc_conn_reset, +	[8] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_3 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_common_actions_4[] = { +	[0] = llc_conn_ac_stop_all_timers, +	[1] = llc_conn_ac_send_ua_rsp_f_set_p, +	[2] = llc_conn_ac_disc_ind, +	[3] = llc_conn_disc, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_common_actions_5[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_rst_ind, +	[5] = llc_conn_ac_set_cause_flag_0, +	[6] = llc_conn_reset, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_5 = { +	.ev	       = llc_conn_ev_rx_frmr_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_5, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_common_actions_6[] = { +	[0] = llc_conn_ac_disc_ind, +	[1] = llc_conn_ac_stop_all_timers, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_6 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_6, +}; + +/* State transitions for LLC_CONN_EV_RX_ZZZ_CMD_Pbit_SET_X_INVAL_Nr event */ +static llc_conn_action_t llc_common_actions_7a[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_7a = { +	.ev	       = llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_7a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_INVAL_Ns event */ +static llc_conn_action_t llc_common_actions_7b[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_7b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_7b, +}; + +/* State transitions for LLC_CONN_EV_RX_ZZZ_RSP_Fbit_SET_X_INVAL_Nr event */ +static llc_conn_action_t llc_common_actions_8a[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_8a = { +	.ev	       = llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_8a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_INVAL_Ns event */ +static llc_conn_action_t llc_common_actions_8b[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_8b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_8b, +}; + +/* State transitions for LLC_CONN_EV_RX_BAD_PDU event */ +static llc_conn_action_t llc_common_actions_8c[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_8c = { +	.ev	       = llc_conn_ev_rx_bad_pdu, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_8c, +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_common_actions_9[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_9 = { +	.ev	       = llc_conn_ev_rx_ua_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_common_actions_9, +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_1 event */ +#if 0 +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_10[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_common_actions_10[] = { +	[0] = llc_conn_ac_send_frmr_rsp_f_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_10 = { +	.ev	       = llc_conn_ev_rx_xxx_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = llc_common_ev_qfyrs_10, +	.ev_actions    = llc_common_actions_10, +}; +#endif + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11a[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_common_actions_11a[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_0, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_11a = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_common_ev_qfyrs_11a, +	.ev_actions    = llc_common_actions_11a, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11b[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_common_actions_11b[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_0, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_11b = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_common_ev_qfyrs_11b, +	.ev_actions    = llc_common_actions_11b, +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11c[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_common_actions_11c[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_0, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_11c = { +	.ev	       = llc_conn_ev_rej_tmr_exp, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_common_ev_qfyrs_11c, +	.ev_actions    = llc_common_actions_11c, +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11d[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_common_actions_11d[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_stop_other_timers, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_0, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_common_state_trans_11d = { +	.ev	       = llc_conn_ev_busy_tmr_exp, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_common_ev_qfyrs_11d, +	.ev_actions    = llc_common_actions_11d, +}; + +/* + * Common dummy state transition; must be last entry for all state + * transition groups - it'll be on .bss, so will be zeroed. + */ +static struct llc_conn_state_trans llc_common_state_trans_end; + +/* LLC_CONN_STATE_ADM transitions */ +/* State transitions for LLC_CONN_EV_CONN_REQ event */ +static llc_conn_action_t llc_adm_actions_1[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_set_retry_cnt_0, +	[3] = llc_conn_ac_set_s_flag_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_adm_state_trans_1 = { +	.ev	       = llc_conn_ev_conn_req, +	.next_state    = LLC_CONN_STATE_SETUP, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_adm_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_adm_actions_2[] = { +	[0] = llc_conn_ac_send_ua_rsp_f_set_p, +	[1] = llc_conn_ac_set_vs_0, +	[2] = llc_conn_ac_set_vr_0, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_p_flag_0, +	[5] = llc_conn_ac_set_remote_busy_0, +	[6] = llc_conn_ac_conn_ind, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_adm_state_trans_2 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_adm_actions_2, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_adm_actions_3[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_p, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_adm_state_trans_3 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_adm_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_adm_actions_4[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_1, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_adm_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_xxx_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_adm_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_YYY event */ +static llc_conn_action_t llc_adm_actions_5[] = { +	[0] = llc_conn_disc, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_adm_state_trans_5 = { +	.ev	       = llc_conn_ev_rx_any_frame, +	.next_state    = LLC_CONN_OUT_OF_SVC, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_adm_actions_5, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_adm_state_transitions[] = { +	[0] = &llc_adm_state_trans_1,		/* Request */ +	[1] = &llc_common_state_trans_end, +	[2] = &llc_common_state_trans_end,	/* local_busy */ +	[3] = &llc_common_state_trans_end,	/* init_pf_cycle */ +	[4] = &llc_common_state_trans_end,	/* timer */ +	[5] = &llc_adm_state_trans_2,		/* Receive frame */ +	[6] = &llc_adm_state_trans_3, +	[7] = &llc_adm_state_trans_4, +	[8] = &llc_adm_state_trans_5, +	[9] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_SETUP transitions */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_setup_actions_1[] = { +	[0] = llc_conn_ac_send_ua_rsp_f_set_p, +	[1] = llc_conn_ac_set_vs_0, +	[2] = llc_conn_ac_set_vr_0, +	[3] = llc_conn_ac_set_s_flag_1, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_1 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_SETUP, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_setup_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = llc_conn_ev_qlfy_set_status_conn, +	[2] = NULL, +}; + +static llc_conn_action_t llc_setup_actions_2[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_ac_set_vs_0, +	[2] = llc_conn_ac_set_vr_0, +	[3] = llc_conn_ac_upd_p_flag, +	[4] = llc_conn_ac_set_remote_busy_0, +	[5] = llc_conn_ac_conn_confirm, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_2 = { +	.ev	       = llc_conn_ev_rx_ua_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_setup_ev_qfyrs_2, +	.ev_actions    = llc_setup_actions_2, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_3[] = { +	[0] = llc_conn_ev_qlfy_s_flag_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_conn, +	[2] = NULL, +}; + +static llc_conn_action_t llc_setup_actions_3[] = { +	[0] = llc_conn_ac_set_p_flag_0, +	[1] = llc_conn_ac_set_remote_busy_0, +	[2] = llc_conn_ac_conn_confirm, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_3 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_setup_ev_qfyrs_3, +	.ev_actions    = llc_setup_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_4[] = { +	[0] = llc_conn_ev_qlfy_set_status_disc, +	[1] = NULL, +}; + +static llc_conn_action_t llc_setup_actions_4[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_p, +	[1] = llc_conn_ac_stop_ack_timer, +	[2] = llc_conn_ac_conn_confirm, +	[3] = llc_conn_disc, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_setup_ev_qfyrs_4, +	.ev_actions    = llc_setup_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_5[] = { +	[0] = llc_conn_ev_qlfy_set_status_disc, +	[1] = NULL, +}; + +static llc_conn_action_t llc_setup_actions_5[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_ac_conn_confirm, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_5 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_setup_ev_qfyrs_5, +	.ev_actions    = llc_setup_actions_5, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_7[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = llc_conn_ev_qlfy_s_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_setup_actions_7[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_7 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_SETUP, +	.ev_qualifiers = llc_setup_ev_qfyrs_7, +	.ev_actions    = llc_setup_actions_7, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_8[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = llc_conn_ev_qlfy_s_flag_eq_0, +	[2] = llc_conn_ev_qlfy_set_status_failed, +	[3] = NULL, +}; + +static llc_conn_action_t llc_setup_actions_8[] = { +	[0] = llc_conn_ac_conn_confirm, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_setup_state_trans_8 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_setup_ev_qfyrs_8, +	.ev_actions    = llc_setup_actions_8, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_setup_state_transitions[] = { +	 [0] = &llc_common_state_trans_end,	/* Request */ +	 [1] = &llc_common_state_trans_end,	/* local busy */ +	 [2] = &llc_common_state_trans_end,	/* init_pf_cycle */ +	 [3] = &llc_setup_state_trans_3,	/* Timer */ +	 [4] = &llc_setup_state_trans_7, +	 [5] = &llc_setup_state_trans_8, +	 [6] = &llc_common_state_trans_end, +	 [7] = &llc_setup_state_trans_1,	/* Receive frame */ +	 [8] = &llc_setup_state_trans_2, +	 [9] = &llc_setup_state_trans_4, +	[10] = &llc_setup_state_trans_5, +	[11] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_NORMAL transitions */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_1[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = llc_conn_ev_qlfy_last_frame_eq_0, +	[3] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_1[] = { +	[0] = llc_conn_ac_send_i_as_ack, +	[1] = llc_conn_ac_start_ack_tmr_if_not_running, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_1 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_1, +	.ev_actions    = llc_normal_actions_1, +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = llc_conn_ev_qlfy_last_frame_eq_1, +	[3] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_2[] = { +	[0] = llc_conn_ac_send_i_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_2 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_2, +	.ev_actions    = llc_normal_actions_2, +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_2_1[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_remote_busy, +	[2] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_normal_actions_2_1[1]; + +static struct llc_conn_state_trans llc_normal_state_trans_2_1 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_2_1, +	.ev_actions    = llc_normal_actions_2_1, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_3[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_3[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rnr_xxx_x_set_0, +	[2] = llc_conn_ac_set_data_flag_0, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_3 = { +	.ev	       = llc_conn_ev_local_busy_detected, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_normal_ev_qfyrs_3, +	.ev_actions    = llc_normal_actions_3, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_4[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_4[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rnr_xxx_x_set_0, +	[2] = llc_conn_ac_set_data_flag_0, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_4 = { +	.ev	       = llc_conn_ev_local_busy_detected, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_normal_ev_qfyrs_4, +	.ev_actions    = llc_normal_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_5a[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rej_xxx_x_set_0, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_upd_p_flag, +	[4] = llc_conn_ac_start_rej_timer, +	[5] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_5a = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_normal_ev_qfyrs_5a, +	.ev_actions    = llc_normal_actions_5a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_5b[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rej_xxx_x_set_0, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_upd_p_flag, +	[4] = llc_conn_ac_start_rej_timer, +	[5] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_5b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_normal_ev_qfyrs_5b, +	.ev_actions    = llc_normal_actions_5b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_5c[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rej_xxx_x_set_0, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_upd_p_flag, +	[4] = llc_conn_ac_start_rej_timer, +	[5] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_5c = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_normal_ev_qfyrs_5c, +	.ev_actions    = llc_normal_actions_5c, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_6a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_6a[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rej_xxx_x_set_0, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_start_rej_timer, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_6a = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_normal_ev_qfyrs_6a, +	.ev_actions    = llc_normal_actions_6a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_6b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_6b[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rej_xxx_x_set_0, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_start_rej_timer, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_6b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_normal_ev_qfyrs_6b, +	.ev_actions    = llc_normal_actions_6b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_normal_actions_7[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rej_rsp_f_set_1, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_start_rej_timer, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_7 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_7, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_8a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_8[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[5] = llc_conn_ac_send_ack_if_needed, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_8a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_8a, +	.ev_actions    = llc_normal_actions_8, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_8b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_8b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_8b, +	.ev_actions    = llc_normal_actions_8, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_9a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_9a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_data_ind, +	[3] = llc_conn_ac_send_ack_if_needed, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_9a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_9a, +	.ev_actions    = llc_normal_actions_9a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_9b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_9b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_data_ind, +	[3] = llc_conn_ac_send_ack_if_needed, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_9b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_9b, +	.ev_actions    = llc_normal_actions_9b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_10[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_send_ack_rsp_f_set_1, +	[2] = llc_conn_ac_rst_sendack_flag, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_data_ind, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_10 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_10, +}; + +/* State transitions for * LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_11a[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_11a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_11a, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_11b[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_11b = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_11b, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_11c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_11c[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_inc_tx_win_size, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_11c = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_11c, +	.ev_actions    = llc_normal_actions_11c, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_12[] = { +	[0] = llc_conn_ac_send_ack_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_adjust_npta_by_rr, +	[3] = llc_conn_ac_rst_sendack_flag, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_12 = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_12, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_13a[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_13a = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_13a, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_13b[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_13b = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_13b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_13c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_13c[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_13c = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_13c, +	.ev_actions    = llc_normal_actions_13c, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_14[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_adjust_npta_by_rnr, +	[3] = llc_conn_ac_rst_sendack_flag, +	[4] = llc_conn_ac_set_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_14 = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_14, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_15a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_15a[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_dec_tx_win_size, +	[4] = llc_conn_ac_resend_i_xxx_x_set_0, +	[5] = llc_conn_ac_clear_remote_busy, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_15a = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_15a, +	.ev_actions    = llc_normal_actions_15a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_15b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_15b[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_dec_tx_win_size, +	[4] = llc_conn_ac_resend_i_xxx_x_set_0, +	[5] = llc_conn_ac_clear_remote_busy, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_15b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_15b, +	.ev_actions    = llc_normal_actions_15b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_16a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_16a[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_dec_tx_win_size, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_16a = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_16a, +	.ev_actions    = llc_normal_actions_16a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_16b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_16b[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_dec_tx_win_size, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_16b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_16b, +	.ev_actions    = llc_normal_actions_16b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_17[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_dec_tx_win_size, +	[3] = llc_conn_ac_resend_i_rsp_f_set_1, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_17 = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_normal_actions_17, +}; + +/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_18[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_18[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_18 = { +	.ev	       = llc_conn_ev_init_p_f_cycle, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_18, +	.ev_actions    = llc_normal_actions_18, +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_19[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_19[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rr_cmd_p_set_1, +	[2] = llc_conn_ac_rst_vs, +	[3] = llc_conn_ac_start_p_timer, +	[4] = llc_conn_ac_inc_retry_cnt_by_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_19 = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = llc_normal_ev_qfyrs_19, +	.ev_actions    = llc_normal_actions_19, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_20a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_20a[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rr_cmd_p_set_1, +	[2] = llc_conn_ac_rst_vs, +	[3] = llc_conn_ac_start_p_timer, +	[4] = llc_conn_ac_inc_retry_cnt_by_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_20a = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = llc_normal_ev_qfyrs_20a, +	.ev_actions    = llc_normal_actions_20a, +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_20b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_20b[] = { +	[0] = llc_conn_ac_rst_sendack_flag, +	[1] = llc_conn_ac_send_rr_cmd_p_set_1, +	[2] = llc_conn_ac_rst_vs, +	[3] = llc_conn_ac_start_p_timer, +	[4] = llc_conn_ac_inc_retry_cnt_by_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_20b = { +	.ev	       = llc_conn_ev_busy_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = llc_normal_ev_qfyrs_20b, +	.ev_actions    = llc_normal_actions_20b, +}; + +/* State transitions for LLC_CONN_EV_TX_BUFF_FULL event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_21[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_normal_actions_21[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_normal_state_trans_21 = { +	.ev	       = llc_conn_ev_tx_buffer_full, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_normal_ev_qfyrs_21, +	.ev_actions    = llc_normal_actions_21, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_normal_state_transitions[] = { +	 [0] = &llc_normal_state_trans_1,	/* Requests */ +	 [1] = &llc_normal_state_trans_2, +	 [2] = &llc_normal_state_trans_2_1, +	 [3] = &llc_common_state_trans_1, +	 [4] = &llc_common_state_trans_2, +	 [5] = &llc_common_state_trans_end, +	 [6] = &llc_normal_state_trans_21, +	 [7] = &llc_normal_state_trans_3,	/* Local busy */ +	 [8] = &llc_normal_state_trans_4, +	 [9] = &llc_common_state_trans_end, +	[10] = &llc_normal_state_trans_18,	/* Init pf cycle */ +	[11] = &llc_common_state_trans_end, +	[12] = &llc_common_state_trans_11a,	/* Timers */ +	[13] = &llc_common_state_trans_11b, +	[14] = &llc_common_state_trans_11c, +	[15] = &llc_common_state_trans_11d, +	[16] = &llc_normal_state_trans_19, +	[17] = &llc_normal_state_trans_20a, +	[18] = &llc_normal_state_trans_20b, +	[19] = &llc_common_state_trans_end, +	[20] = &llc_normal_state_trans_8b,	/* Receive frames */ +	[21] = &llc_normal_state_trans_9b, +	[22] = &llc_normal_state_trans_10, +	[23] = &llc_normal_state_trans_11b, +	[24] = &llc_normal_state_trans_11c, +	[25] = &llc_normal_state_trans_5a, +	[26] = &llc_normal_state_trans_5b, +	[27] = &llc_normal_state_trans_5c, +	[28] = &llc_normal_state_trans_6a, +	[29] = &llc_normal_state_trans_6b, +	[30] = &llc_normal_state_trans_7, +	[31] = &llc_normal_state_trans_8a, +	[32] = &llc_normal_state_trans_9a, +	[33] = &llc_normal_state_trans_11a, +	[34] = &llc_normal_state_trans_12, +	[35] = &llc_normal_state_trans_13a, +	[36] = &llc_normal_state_trans_13b, +	[37] = &llc_normal_state_trans_13c, +	[38] = &llc_normal_state_trans_14, +	[39] = &llc_normal_state_trans_15a, +	[40] = &llc_normal_state_trans_15b, +	[41] = &llc_normal_state_trans_16a, +	[42] = &llc_normal_state_trans_16b, +	[43] = &llc_normal_state_trans_17, +	[44] = &llc_common_state_trans_3, +	[45] = &llc_common_state_trans_4, +	[46] = &llc_common_state_trans_5, +	[47] = &llc_common_state_trans_6, +	[48] = &llc_common_state_trans_7a, +	[49] = &llc_common_state_trans_7b, +	[50] = &llc_common_state_trans_8a, +	[51] = &llc_common_state_trans_8b, +	[52] = &llc_common_state_trans_8c, +	[53] = &llc_common_state_trans_9, +	/* [54] = &llc_common_state_trans_10, */ +	[54] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_BUSY transitions */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_1[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_1[] = { +	[0] = llc_conn_ac_send_i_xxx_x_set_0, +	[1] = llc_conn_ac_start_ack_tmr_if_not_running, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_1 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_1, +	.ev_actions    = llc_busy_actions_1, +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_1, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_2[] = { +	[0] = llc_conn_ac_send_i_xxx_x_set_0, +	[1] = llc_conn_ac_start_ack_tmr_if_not_running, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_2 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_2, +	.ev_actions    = llc_busy_actions_2, +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_2_1[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_remote_busy, +	[2] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_busy_actions_2_1[1]; + +static struct llc_conn_state_trans llc_busy_state_trans_2_1 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_2_1, +	.ev_actions    = llc_busy_actions_2_1, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_3[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_1, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_3[] = { +	[0] = llc_conn_ac_send_rej_xxx_x_set_0, +	[1] = llc_conn_ac_start_rej_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_3 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_busy_ev_qfyrs_3, +	.ev_actions    = llc_busy_actions_3, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_4[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_1, +	[1] = llc_conn_ev_qlfy_p_flag_eq_1, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_4[] = { +	[0] = llc_conn_ac_send_rej_xxx_x_set_0, +	[1] = llc_conn_ac_start_rej_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_4 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_busy_ev_qfyrs_4, +	.ev_actions    = llc_busy_actions_4, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_5[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_5[] = { +	[0] = llc_conn_ac_send_rr_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_5 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_busy_ev_qfyrs_5, +	.ev_actions    = llc_busy_actions_5, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_6[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_1, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_6[] = { +	[0] = llc_conn_ac_send_rr_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_6 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_busy_ev_qfyrs_6, +	.ev_actions    = llc_busy_actions_6, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_7[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_2, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_7[] = { +	[0] = llc_conn_ac_send_rr_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_7 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_busy_ev_qfyrs_7, +	.ev_actions    = llc_busy_actions_7, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_8[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_2, +	[1] = llc_conn_ev_qlfy_p_flag_eq_1, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_8[] = { +	[0] = llc_conn_ac_send_rr_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_8 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_busy_ev_qfyrs_8, +	.ev_actions    = llc_busy_actions_8, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_9a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_9a[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_p_flag, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, +	[4] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_9a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_9a, +	.ev_actions    = llc_busy_actions_9a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_9b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_9b[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_p_flag, +	[2] = llc_conn_ac_upd_nr_received, +	[3] = llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, +	[4] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_9b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_9b, +	.ev_actions    = llc_busy_actions_9b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_10a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_10a[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_10a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_10a, +	.ev_actions    = llc_busy_actions_10a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_10b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_10b[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_10b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_10b, +	.ev_actions    = llc_busy_actions_10b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_busy_actions_11[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_11 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_11, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_12[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, +	[5] = llc_conn_ac_set_data_flag_0, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_12 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_12, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_13a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_13a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, +	[6] = llc_conn_ac_set_data_flag_0, +	[7] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[8] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_13a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_13a, +	.ev_actions    = llc_busy_actions_13a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_13b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_13b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, +	[6] = llc_conn_ac_set_data_flag_0, +	[7] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[8] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_13b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_13b, +	.ev_actions    = llc_busy_actions_13b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_14a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_14a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, +	[5] = llc_conn_ac_set_data_flag_0, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_14a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_14a, +	.ev_actions    = llc_busy_actions_14a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_14b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_14b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, +	[5] = llc_conn_ac_set_data_flag_0, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_14b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_14b, +	.ev_actions    = llc_busy_actions_14b, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_15a[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_15a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_15a, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_15b[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_15b = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_15b, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_15c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_15c[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_15c = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_15c, +	.ev_actions    = llc_busy_actions_15c, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_16[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_16 = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_16, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_17a[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_17a = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_17a, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_17b[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_17b = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_17b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_17c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_17c[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_17c = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_17c, +	.ev_actions    = llc_busy_actions_17c, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_18[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_18 = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_18, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_19a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_19a[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_19a = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_19a, +	.ev_actions    = llc_busy_actions_19a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_19b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_19b[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_19b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_19b, +	.ev_actions    = llc_busy_actions_19b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_20a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_20a[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_resend_i_xxx_x_set_0, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_20a = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_20a, +	.ev_actions    = llc_busy_actions_20a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_20b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_20b[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_resend_i_xxx_x_set_0, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_20b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_20b, +	.ev_actions    = llc_busy_actions_20b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_21[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_21 = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_busy_actions_21, +}; + +/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_22[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_22[] = { +	[0] = llc_conn_ac_send_rnr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_22 = { +	.ev	       = llc_conn_ev_init_p_f_cycle, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_22, +	.ev_actions    = llc_busy_actions_22, +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_23[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_23[] = { +	[0] = llc_conn_ac_send_rnr_cmd_p_set_1, +	[1] = llc_conn_ac_rst_vs, +	[2] = llc_conn_ac_start_p_timer, +	[3] = llc_conn_ac_inc_retry_cnt_by_1, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_23 = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_23, +	.ev_actions    = llc_busy_actions_23, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_24a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_24a[] = { +	[0] = llc_conn_ac_send_rnr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = llc_conn_ac_rst_vs, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_24a = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_24a, +	.ev_actions    = llc_busy_actions_24a, +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_24b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_24b[] = { +	[0] = llc_conn_ac_send_rnr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = llc_conn_ac_rst_vs, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_24b = { +	.ev	       = llc_conn_ev_busy_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_24b, +	.ev_actions    = llc_busy_actions_24b, +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_25[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_25[] = { +	[0] = llc_conn_ac_send_rnr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = llc_conn_ac_rst_vs, +	[4] = llc_conn_ac_set_data_flag_1, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_25 = { +	.ev	       = llc_conn_ev_rej_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_25, +	.ev_actions    = llc_busy_actions_25, +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_26[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_busy_actions_26[] = { +	[0] = llc_conn_ac_set_data_flag_1, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_busy_state_trans_26 = { +	.ev	       = llc_conn_ev_rej_tmr_exp, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_busy_ev_qfyrs_26, +	.ev_actions    = llc_busy_actions_26, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_busy_state_transitions[] = { +	 [0] = &llc_common_state_trans_1,	/* Request */ +	 [1] = &llc_common_state_trans_2, +	 [2] = &llc_busy_state_trans_1, +	 [3] = &llc_busy_state_trans_2, +	 [4] = &llc_busy_state_trans_2_1, +	 [5] = &llc_common_state_trans_end, +	 [6] = &llc_busy_state_trans_3,		/* Local busy */ +	 [7] = &llc_busy_state_trans_4, +	 [8] = &llc_busy_state_trans_5, +	 [9] = &llc_busy_state_trans_6, +	[10] = &llc_busy_state_trans_7, +	[11] = &llc_busy_state_trans_8, +	[12] = &llc_common_state_trans_end, +	[13] = &llc_busy_state_trans_22,	/* Initiate PF cycle */ +	[14] = &llc_common_state_trans_end, +	[15] = &llc_common_state_trans_11a,	/* Timer */ +	[16] = &llc_common_state_trans_11b, +	[17] = &llc_common_state_trans_11c, +	[18] = &llc_common_state_trans_11d, +	[19] = &llc_busy_state_trans_23, +	[20] = &llc_busy_state_trans_24a, +	[21] = &llc_busy_state_trans_24b, +	[22] = &llc_busy_state_trans_25, +	[23] = &llc_busy_state_trans_26, +	[24] = &llc_common_state_trans_end, +	[25] = &llc_busy_state_trans_9a,	/* Receive frame */ +	[26] = &llc_busy_state_trans_9b, +	[27] = &llc_busy_state_trans_10a, +	[28] = &llc_busy_state_trans_10b, +	[29] = &llc_busy_state_trans_11, +	[30] = &llc_busy_state_trans_12, +	[31] = &llc_busy_state_trans_13a, +	[32] = &llc_busy_state_trans_13b, +	[33] = &llc_busy_state_trans_14a, +	[34] = &llc_busy_state_trans_14b, +	[35] = &llc_busy_state_trans_15a, +	[36] = &llc_busy_state_trans_15b, +	[37] = &llc_busy_state_trans_15c, +	[38] = &llc_busy_state_trans_16, +	[39] = &llc_busy_state_trans_17a, +	[40] = &llc_busy_state_trans_17b, +	[41] = &llc_busy_state_trans_17c, +	[42] = &llc_busy_state_trans_18, +	[43] = &llc_busy_state_trans_19a, +	[44] = &llc_busy_state_trans_19b, +	[45] = &llc_busy_state_trans_20a, +	[46] = &llc_busy_state_trans_20b, +	[47] = &llc_busy_state_trans_21, +	[48] = &llc_common_state_trans_3, +	[49] = &llc_common_state_trans_4, +	[50] = &llc_common_state_trans_5, +	[51] = &llc_common_state_trans_6, +	[52] = &llc_common_state_trans_7a, +	[53] = &llc_common_state_trans_7b, +	[54] = &llc_common_state_trans_8a, +	[55] = &llc_common_state_trans_8b, +	[56] = &llc_common_state_trans_8c, +	[57] = &llc_common_state_trans_9, +	/* [58] = &llc_common_state_trans_10, */ +	[58] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_REJ transitions */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_1[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_1[] = { +	[0] = llc_conn_ac_send_i_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_1 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_1, +	.ev_actions    = llc_reject_actions_1, +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_0, +	[1] = llc_conn_ev_qlfy_p_flag_eq_1, +	[2] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_2[] = { +	[0] = llc_conn_ac_send_i_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_2 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_2, +	.ev_actions    = llc_reject_actions_2, +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_2_1[] = { +	[0] = llc_conn_ev_qlfy_remote_busy_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_remote_busy, +	[2] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_reject_actions_2_1[1]; + +static struct llc_conn_state_trans llc_reject_state_trans_2_1 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_2_1, +	.ev_actions    = llc_reject_actions_2_1, +}; + + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_3[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_3[] = { +	[0] = llc_conn_ac_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_set_data_flag_2, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_3 = { +	.ev	       = llc_conn_ev_local_busy_detected, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_reject_ev_qfyrs_3, +	.ev_actions    = llc_reject_actions_3, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_4[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_4[] = { +	[0] = llc_conn_ac_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_set_data_flag_2, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_4 = { +	.ev	       = llc_conn_ev_local_busy_detected, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = llc_reject_ev_qfyrs_4, +	.ev_actions    = llc_reject_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_reject_actions_5a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_p_flag, +	[2] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_5a = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_5a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_reject_actions_5b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_p_flag, +	[2] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_5b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_5b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_5c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_5c[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_p_flag, +	[2] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_5c = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_5c, +	.ev_actions    = llc_reject_actions_5c, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_reject_actions_6[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_6 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_6, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_7a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_7a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_send_ack_xxx_x_set_0, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[6] = llc_conn_ac_stop_rej_timer, +	[7] = NULL, + +}; + +static struct llc_conn_state_trans llc_reject_state_trans_7a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_reject_ev_qfyrs_7a, +	.ev_actions    = llc_reject_actions_7a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_7b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_7b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_send_ack_xxx_x_set_0, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_clear_remote_busy_if_f_eq_1, +	[6] = llc_conn_ac_stop_rej_timer, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_7b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_reject_ev_qfyrs_7b, +	.ev_actions    = llc_reject_actions_7b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_8a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_8a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_ack_xxx_x_set_0, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_stop_rej_timer, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_8a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_reject_ev_qfyrs_8a, +	.ev_actions    = llc_reject_actions_8a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_8b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_8b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_ack_xxx_x_set_0, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_stop_rej_timer, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_8b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_reject_ev_qfyrs_8b, +	.ev_actions    = llc_reject_actions_8b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_9[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_ack_rsp_f_set_1, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_stop_rej_timer, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_9 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_9, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_10a[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_10a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_10a, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_10b[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_10b = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_10b, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_10c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_10c[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_10c = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_10c, +	.ev_actions    = llc_reject_actions_10c, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_11[] = { +	[0] = llc_conn_ac_send_ack_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_11 = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_11, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_12a[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_12a = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_12a, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_12b[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_12b = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_12b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_12c[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_12c[] = { +	[0] = llc_conn_ac_upd_p_flag, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_12c = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_12c, +	.ev_actions    = llc_reject_actions_12c, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_13[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_13 = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_13, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_14a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_14a[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_14a = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_14a, +	.ev_actions    = llc_reject_actions_14a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_14b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_14b[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_p_flag, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_14b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_14b, +	.ev_actions    = llc_reject_actions_14b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_15a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_15a[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_resend_i_xxx_x_set_0, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_15a = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_15a, +	.ev_actions    = llc_reject_actions_15a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_15b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_15b[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_resend_i_xxx_x_set_0, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_15b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_15b, +	.ev_actions    = llc_reject_actions_15b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_16[] = { +	[0] = llc_conn_ac_set_vs_nr, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_resend_i_rsp_f_set_1, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_16 = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_reject_actions_16, +}; + +/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_17[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_17[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_17 = { +	.ev	       = llc_conn_ev_init_p_f_cycle, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_17, +	.ev_actions    = llc_reject_actions_17, +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_18[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_18[] = { +	[0] = llc_conn_ac_send_rej_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_start_rej_timer, +	[3] = llc_conn_ac_inc_retry_cnt_by_1, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_18 = { +	.ev	       = llc_conn_ev_rej_tmr_exp, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_18, +	.ev_actions    = llc_reject_actions_18, +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_19[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_19[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_start_rej_timer, +	[3] = llc_conn_ac_inc_retry_cnt_by_1, +	[4] = llc_conn_ac_rst_vs, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_19 = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_19, +	.ev_actions    = llc_reject_actions_19, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_20a[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_20a[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_start_rej_timer, +	[3] = llc_conn_ac_inc_retry_cnt_by_1, +	[4] = llc_conn_ac_rst_vs, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_20a = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_20a, +	.ev_actions    = llc_reject_actions_20a, +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_20b[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_0, +	[1] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[2] = NULL, +}; + +static llc_conn_action_t llc_reject_actions_20b[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_start_rej_timer, +	[3] = llc_conn_ac_inc_retry_cnt_by_1, +	[4] = llc_conn_ac_rst_vs, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_reject_state_trans_20b = { +	.ev	       = llc_conn_ev_busy_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_reject_ev_qfyrs_20b, +	.ev_actions    = llc_reject_actions_20b, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_reject_state_transitions[] = { +	 [0] = &llc_common_state_trans_1,	/* Request */ +	 [1] = &llc_common_state_trans_2, +	 [2] = &llc_common_state_trans_end, +	 [3] = &llc_reject_state_trans_1, +	 [4] = &llc_reject_state_trans_2, +	 [5] = &llc_reject_state_trans_2_1, +	 [6] = &llc_reject_state_trans_3,	/* Local busy */ +	 [7] = &llc_reject_state_trans_4, +	 [8] = &llc_common_state_trans_end, +	 [9] = &llc_reject_state_trans_17,	/* Initiate PF cycle */ +	[10] = &llc_common_state_trans_end, +	[11] = &llc_common_state_trans_11a,	/* Timer */ +	[12] = &llc_common_state_trans_11b, +	[13] = &llc_common_state_trans_11c, +	[14] = &llc_common_state_trans_11d, +	[15] = &llc_reject_state_trans_18, +	[16] = &llc_reject_state_trans_19, +	[17] = &llc_reject_state_trans_20a, +	[18] = &llc_reject_state_trans_20b, +	[19] = &llc_common_state_trans_end, +	[20] = &llc_common_state_trans_3,	/* Receive frame */ +	[21] = &llc_common_state_trans_4, +	[22] = &llc_common_state_trans_5, +	[23] = &llc_common_state_trans_6, +	[24] = &llc_common_state_trans_7a, +	[25] = &llc_common_state_trans_7b, +	[26] = &llc_common_state_trans_8a, +	[27] = &llc_common_state_trans_8b, +	[28] = &llc_common_state_trans_8c, +	[29] = &llc_common_state_trans_9, +	/* [30] = &llc_common_state_trans_10, */ +	[30] = &llc_reject_state_trans_5a, +	[31] = &llc_reject_state_trans_5b, +	[32] = &llc_reject_state_trans_5c, +	[33] = &llc_reject_state_trans_6, +	[34] = &llc_reject_state_trans_7a, +	[35] = &llc_reject_state_trans_7b, +	[36] = &llc_reject_state_trans_8a, +	[37] = &llc_reject_state_trans_8b, +	[38] = &llc_reject_state_trans_9, +	[39] = &llc_reject_state_trans_10a, +	[40] = &llc_reject_state_trans_10b, +	[41] = &llc_reject_state_trans_10c, +	[42] = &llc_reject_state_trans_11, +	[43] = &llc_reject_state_trans_12a, +	[44] = &llc_reject_state_trans_12b, +	[45] = &llc_reject_state_trans_12c, +	[46] = &llc_reject_state_trans_13, +	[47] = &llc_reject_state_trans_14a, +	[48] = &llc_reject_state_trans_14b, +	[49] = &llc_reject_state_trans_15a, +	[50] = &llc_reject_state_trans_15b, +	[51] = &llc_reject_state_trans_16, +	[52] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_AWAIT transitions */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_await_ev_qfyrs_1_0[] = { +	[0] = llc_conn_ev_qlfy_set_status_refuse, +	[1] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_await_actions_1_0[1]; + +static struct llc_conn_state_trans llc_await_state_trans_1_0 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = llc_await_ev_qfyrs_1_0, +	.ev_actions    = llc_await_actions_1_0, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_action_t llc_await_actions_1[] = { +	[0] = llc_conn_ac_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_set_data_flag_0, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_1 = { +	.ev	       = llc_conn_ev_local_busy_detected, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_2[] = { +	[0] = llc_conn_ac_send_rej_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_stop_p_timer, +	[4] = llc_conn_ac_resend_i_xxx_x_set_0, +	[5] = llc_conn_ac_start_rej_timer, +	[6] = llc_conn_ac_clear_remote_busy, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_2 = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_2, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_3a[] = { +	[0] = llc_conn_ac_send_rej_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_start_rej_timer, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_3a = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_3a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_3b[] = { +	[0] = llc_conn_ac_send_rej_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_start_rej_timer, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_3b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_3b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_4[] = { +	[0] = llc_conn_ac_send_rej_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_start_rej_timer, +	[4] = llc_conn_ac_start_p_timer, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_5[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr, +	[6] = llc_conn_ac_clear_remote_busy, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_5 = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_5, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_6a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rr_xxx_x_set_0, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_6a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_6a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_6b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rr_xxx_x_set_0, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_6b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_6b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_7[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rr_rsp_f_set_1, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_7 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_7, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_8a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_8a = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_8a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_8b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_8b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_8b, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_9a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_9a, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_9b = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_9b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9c[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_9c = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_9c, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9d[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_9d = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_9d, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_10a[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_10a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_10a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_10b[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_10b = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_10b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_11[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_set_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_11 = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_11, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_12a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_12a = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_12a, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_12b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_12b = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_12b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_13[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_set_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_13 = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_actions_13, +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_await_ev_qfyrs_14[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_await_actions_14[] = { +	[0] = llc_conn_ac_send_rr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_state_trans_14 = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = llc_await_ev_qfyrs_14, +	.ev_actions    = llc_await_actions_14, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_await_state_transitions[] = { +	 [0] = &llc_common_state_trans_1,	/* Request */ +	 [1] = &llc_common_state_trans_2, +	 [2] = &llc_await_state_trans_1_0, +	 [3] = &llc_common_state_trans_end, +	 [4] = &llc_await_state_trans_1,	/* Local busy */ +	 [5] = &llc_common_state_trans_end, +	 [6] = &llc_common_state_trans_end,	/* Initiate PF Cycle */ +	 [7] = &llc_common_state_trans_11a,	/* Timer */ +	 [8] = &llc_common_state_trans_11b, +	 [9] = &llc_common_state_trans_11c, +	[10] = &llc_common_state_trans_11d, +	[11] = &llc_await_state_trans_14, +	[12] = &llc_common_state_trans_end, +	[13] = &llc_common_state_trans_3,	/* Receive frame */ +	[14] = &llc_common_state_trans_4, +	[15] = &llc_common_state_trans_5, +	[16] = &llc_common_state_trans_6, +	[17] = &llc_common_state_trans_7a, +	[18] = &llc_common_state_trans_7b, +	[19] = &llc_common_state_trans_8a, +	[20] = &llc_common_state_trans_8b, +	[21] = &llc_common_state_trans_8c, +	[22] = &llc_common_state_trans_9, +	/* [23] = &llc_common_state_trans_10, */ +	[23] = &llc_await_state_trans_2, +	[24] = &llc_await_state_trans_3a, +	[25] = &llc_await_state_trans_3b, +	[26] = &llc_await_state_trans_4, +	[27] = &llc_await_state_trans_5, +	[28] = &llc_await_state_trans_6a, +	[29] = &llc_await_state_trans_6b, +	[30] = &llc_await_state_trans_7, +	[31] = &llc_await_state_trans_8a, +	[32] = &llc_await_state_trans_8b, +	[33] = &llc_await_state_trans_9a, +	[34] = &llc_await_state_trans_9b, +	[35] = &llc_await_state_trans_9c, +	[36] = &llc_await_state_trans_9d, +	[37] = &llc_await_state_trans_10a, +	[38] = &llc_await_state_trans_10b, +	[39] = &llc_await_state_trans_11, +	[40] = &llc_await_state_trans_12a, +	[41] = &llc_await_state_trans_12b, +	[42] = &llc_await_state_trans_13, +	[43] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_AWAIT_BUSY transitions */ +/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_1_0[] = { +	[0] = llc_conn_ev_qlfy_set_status_refuse, +	[1] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_await_busy_actions_1_0[1]; + +static struct llc_conn_state_trans llc_await_busy_state_trans_1_0 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = llc_await_busy_ev_qfyrs_1_0, +	.ev_actions    = llc_await_busy_actions_1_0, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_1[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_1, +	[1] = NULL, +}; + +static llc_conn_action_t llc_await_busy_actions_1[] = { +	[0] = llc_conn_ac_send_rej_xxx_x_set_0, +	[1] = llc_conn_ac_start_rej_timer, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_1 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_await_busy_ev_qfyrs_1, +	.ev_actions    = llc_await_busy_actions_1, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_0, +	[1] = NULL, +}; + +static llc_conn_action_t llc_await_busy_actions_2[] = { +	[0] = llc_conn_ac_send_rr_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_2 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = llc_await_busy_ev_qfyrs_2, +	.ev_actions    = llc_await_busy_actions_2, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_3[] = { +	[0] = llc_conn_ev_qlfy_data_flag_eq_2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_await_busy_actions_3[] = { +	[0] = llc_conn_ac_send_rr_xxx_x_set_0, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_3 = { +	.ev	       = llc_conn_ev_local_busy_cleared, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_await_busy_ev_qfyrs_3, +	.ev_actions    = llc_await_busy_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_4[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_stop_p_timer, +	[4] = llc_conn_ac_set_data_flag_1, +	[5] = llc_conn_ac_clear_remote_busy, +	[6] = llc_conn_ac_resend_i_xxx_x_set_0, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_5a[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_set_data_flag_1, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_5a = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_5a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_5b[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_set_data_flag_1, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_5b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_5b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_6[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_set_data_flag_1, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_6 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_6, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_7[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_inc_vr_by_1, +	[2] = llc_conn_ac_data_ind, +	[3] = llc_conn_ac_stop_p_timer, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_upd_vs, +	[6] = llc_conn_ac_set_data_flag_0, +	[7] = llc_conn_ac_clear_remote_busy, +	[8] = llc_conn_ac_resend_i_xxx_x_set_0, +	[9] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_7 = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_7, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_8a[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_inc_vr_by_1, +	[2] = llc_conn_ac_data_ind, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = llc_conn_ac_set_data_flag_0, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_8a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_8a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_8b[] = { +	[0] = llc_conn_ac_opt_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_inc_vr_by_1, +	[2] = llc_conn_ac_data_ind, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = llc_conn_ac_set_data_flag_0, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_8b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_8b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_9[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_inc_vr_by_1, +	[2] = llc_conn_ac_data_ind, +	[3] = llc_conn_ac_upd_nr_received, +	[4] = llc_conn_ac_upd_vs, +	[5] = llc_conn_ac_set_data_flag_0, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_9 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_9, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_10a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_10a = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_10a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_10b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_10b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_10b, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_11a, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11b = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_11b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11c[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11c = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_11c, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11d[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11d = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_11d, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_12a[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_12a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_12a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_12b[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_12b = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_12b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_13[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_set_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_13 = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_13, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_14a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_14a = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_14a, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_14b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_14b = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_14b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_15[] = { +	[0] = llc_conn_ac_send_rnr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_set_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_15 = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_busy_actions_15, +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_16[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_await_busy_actions_16[] = { +	[0] = llc_conn_ac_send_rnr_cmd_p_set_1, +	[1] = llc_conn_ac_start_p_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_16 = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = llc_await_busy_ev_qfyrs_16, +	.ev_actions    = llc_await_busy_actions_16, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_await_busy_state_transitions[] = { +	 [0] = &llc_common_state_trans_1,		/* Request */ +	 [1] = &llc_common_state_trans_2, +	 [2] = &llc_await_busy_state_trans_1_0, +	 [3] = &llc_common_state_trans_end, +	 [4] = &llc_await_busy_state_trans_1,		/* Local busy */ +	 [5] = &llc_await_busy_state_trans_2, +	 [6] = &llc_await_busy_state_trans_3, +	 [7] = &llc_common_state_trans_end, +	 [8] = &llc_common_state_trans_end,		/* Initiate PF cycle */ +	 [9] = &llc_common_state_trans_11a,		/* Timer */ +	[10] = &llc_common_state_trans_11b, +	[11] = &llc_common_state_trans_11c, +	[12] = &llc_common_state_trans_11d, +	[13] = &llc_await_busy_state_trans_16, +	[14] = &llc_common_state_trans_end, +	[15] = &llc_await_busy_state_trans_4,		/* Receive frame */ +	[16] = &llc_await_busy_state_trans_5a, +	[17] = &llc_await_busy_state_trans_5b, +	[18] = &llc_await_busy_state_trans_6, +	[19] = &llc_await_busy_state_trans_7, +	[20] = &llc_await_busy_state_trans_8a, +	[21] = &llc_await_busy_state_trans_8b, +	[22] = &llc_await_busy_state_trans_9, +	[23] = &llc_await_busy_state_trans_10a, +	[24] = &llc_await_busy_state_trans_10b, +	[25] = &llc_await_busy_state_trans_11a, +	[26] = &llc_await_busy_state_trans_11b, +	[27] = &llc_await_busy_state_trans_11c, +	[28] = &llc_await_busy_state_trans_11d, +	[29] = &llc_await_busy_state_trans_12a, +	[30] = &llc_await_busy_state_trans_12b, +	[31] = &llc_await_busy_state_trans_13, +	[32] = &llc_await_busy_state_trans_14a, +	[33] = &llc_await_busy_state_trans_14b, +	[34] = &llc_await_busy_state_trans_15, +	[35] = &llc_common_state_trans_3, +	[36] = &llc_common_state_trans_4, +	[37] = &llc_common_state_trans_5, +	[38] = &llc_common_state_trans_6, +	[39] = &llc_common_state_trans_7a, +	[40] = &llc_common_state_trans_7b, +	[41] = &llc_common_state_trans_8a, +	[42] = &llc_common_state_trans_8b, +	[43] = &llc_common_state_trans_8c, +	[44] = &llc_common_state_trans_9, +	/* [45] = &llc_common_state_trans_10, */ +	[45] = &llc_common_state_trans_end, +}; + +/* ----------------- LLC_CONN_STATE_AWAIT_REJ transitions --------------- */ +/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_await_reject_ev_qfyrs_1_0[] = { +	[0] = llc_conn_ev_qlfy_set_status_refuse, +	[1] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_await_reject_actions_1_0[1]; + +static struct llc_conn_state_trans llc_await_reject_state_trans_1_0 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_await_reject_ev_qfyrs_1_0, +	.ev_actions    = llc_await_reject_actions_1_0, +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_action_t llc_await_rejct_actions_1[] = { +	[0] = llc_conn_ac_send_rnr_xxx_x_set_0, +	[1] = llc_conn_ac_set_data_flag_2, +	[2] = NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_1 = { +	.ev	       = llc_conn_ev_local_busy_detected, +	.next_state    = LLC_CONN_STATE_AWAIT_BUSY, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_2a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_2a = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_2a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_2b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_2b = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_2b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_3[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_3 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_4[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_stop_rej_timer, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_upd_vs, +	[6] = llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr, +	[7] = llc_conn_ac_clear_remote_busy, +	[8] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_5a[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rr_xxx_x_set_0, +	[3] = llc_conn_ac_stop_rej_timer, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_upd_vs, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_5a = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_5a, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_5b[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rr_xxx_x_set_0, +	[3] = llc_conn_ac_stop_rej_timer, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_upd_vs, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_5b = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_5b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_6[] = { +	[0] = llc_conn_ac_inc_vr_by_1, +	[1] = llc_conn_ac_data_ind, +	[2] = llc_conn_ac_send_rr_rsp_f_set_1, +	[3] = llc_conn_ac_stop_rej_timer, +	[4] = llc_conn_ac_upd_nr_received, +	[5] = llc_conn_ac_upd_vs, +	[6] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_6 = { +	.ev	       = llc_conn_ev_rx_i_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_6, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_7a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_7a = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_7a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_7b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_7b = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_7b, +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_7c[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_resend_i_xxx_x_set_0, +	[4] = llc_conn_ac_clear_remote_busy, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_7c = { +	.ev	       = llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_7c, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_8a, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8b = { +	.ev	       = llc_conn_ev_rx_rr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_8b, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8c[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8c = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_8c, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8d[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_clear_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8d = { +	.ev	       = llc_conn_ev_rx_rej_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_8d, +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_9a[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_9a = { +	.ev	       = llc_conn_ev_rx_rr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_9a, +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_9b[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_clear_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_9b = { +	.ev	       = llc_conn_ev_rx_rej_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_9b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_10[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_stop_p_timer, +	[3] = llc_conn_ac_set_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_10 = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_1, +	.next_state    = LLC_CONN_STATE_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_10, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_11a[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_11a = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_11a, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_11b[] = { +	[0] = llc_conn_ac_upd_nr_received, +	[1] = llc_conn_ac_upd_vs, +	[2] = llc_conn_ac_set_remote_busy, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_11b = { +	.ev	       = llc_conn_ev_rx_rnr_rsp_fbit_set_0, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_11b, +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_12[] = { +	[0] = llc_conn_ac_send_rr_rsp_f_set_1, +	[1] = llc_conn_ac_upd_nr_received, +	[2] = llc_conn_ac_upd_vs, +	[3] = llc_conn_ac_set_remote_busy, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_12 = { +	.ev	       = llc_conn_ev_rx_rnr_cmd_pbit_set_1, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_await_rejct_actions_12, +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_await_rejct_ev_qfyrs_13[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_await_rejct_actions_13[] = { +	[0] = llc_conn_ac_send_rej_cmd_p_set_1, +	[1] = llc_conn_ac_stop_p_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_13 = { +	.ev	       = llc_conn_ev_p_tmr_exp, +	.next_state    = LLC_CONN_STATE_AWAIT_REJ, +	.ev_qualifiers = llc_await_rejct_ev_qfyrs_13, +	.ev_actions    = llc_await_rejct_actions_13, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_await_rejct_state_transitions[] = { +	 [0] = &llc_await_reject_state_trans_1_0, +	 [1] = &llc_common_state_trans_1,		/* requests */ +	 [2] = &llc_common_state_trans_2, +	 [3] = &llc_common_state_trans_end, +	 [4] = &llc_await_rejct_state_trans_1,		/* local busy */ +	 [5] = &llc_common_state_trans_end, +	 [6] = &llc_common_state_trans_end,		/* Initiate PF cycle */ +	 [7] = &llc_await_rejct_state_trans_13,	/* timers */ +	 [8] = &llc_common_state_trans_11a, +	 [9] = &llc_common_state_trans_11b, +	[10] = &llc_common_state_trans_11c, +	[11] = &llc_common_state_trans_11d, +	[12] = &llc_common_state_trans_end, +	[13] = &llc_await_rejct_state_trans_2a,	/* receive frames */ +	[14] = &llc_await_rejct_state_trans_2b, +	[15] = &llc_await_rejct_state_trans_3, +	[16] = &llc_await_rejct_state_trans_4, +	[17] = &llc_await_rejct_state_trans_5a, +	[18] = &llc_await_rejct_state_trans_5b, +	[19] = &llc_await_rejct_state_trans_6, +	[20] = &llc_await_rejct_state_trans_7a, +	[21] = &llc_await_rejct_state_trans_7b, +	[22] = &llc_await_rejct_state_trans_7c, +	[23] = &llc_await_rejct_state_trans_8a, +	[24] = &llc_await_rejct_state_trans_8b, +	[25] = &llc_await_rejct_state_trans_8c, +	[26] = &llc_await_rejct_state_trans_8d, +	[27] = &llc_await_rejct_state_trans_9a, +	[28] = &llc_await_rejct_state_trans_9b, +	[29] = &llc_await_rejct_state_trans_10, +	[30] = &llc_await_rejct_state_trans_11a, +	[31] = &llc_await_rejct_state_trans_11b, +	[32] = &llc_await_rejct_state_trans_12, +	[33] = &llc_common_state_trans_3, +	[34] = &llc_common_state_trans_4, +	[35] = &llc_common_state_trans_5, +	[36] = &llc_common_state_trans_6, +	[37] = &llc_common_state_trans_7a, +	[38] = &llc_common_state_trans_7b, +	[39] = &llc_common_state_trans_8a, +	[40] = &llc_common_state_trans_8b, +	[41] = &llc_common_state_trans_8c, +	[42] = &llc_common_state_trans_9, +	/* [43] = &llc_common_state_trans_10, */ +	[43] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_D_CONN transitions */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_1[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_conflict, +	[2] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_1[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_p, +	[1] = llc_conn_ac_stop_ack_timer, +	[2] = llc_conn_ac_disc_confirm, +	[3] = llc_conn_disc, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_1 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_1, +	.ev_actions    = llc_d_conn_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_1_1[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[1] = llc_conn_ev_qlfy_set_status_conflict, +	[2] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_1_1[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_p, +	[1] = llc_conn_ac_stop_ack_timer, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_1_1 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_1_1, +	.ev_actions    = llc_d_conn_actions_1_1, +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 1 + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[2] = llc_conn_ev_qlfy_set_status_disc, +	[3] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_2[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_ac_disc_confirm, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_2 = { +	.ev	       = llc_conn_ev_rx_ua_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_2, +	.ev_actions    = llc_d_conn_actions_2, +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_2_1[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[2] = llc_conn_ev_qlfy_set_status_disc, +	[3] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_2_1[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_2_1 = { +	.ev	       = llc_conn_ev_rx_ua_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_2_1, +	.ev_actions    = llc_d_conn_actions_2_1, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_d_conn_actions_3[] = { +	[0] = llc_conn_ac_send_ua_rsp_f_set_p, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_3 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_D_CONN, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_d_conn_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 1 + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_4[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_disc, +	[2] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_4[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_ac_disc_confirm, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_4, +	.ev_actions    = llc_d_conn_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_4_1[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[1] = llc_conn_ev_qlfy_set_status_disc, +	[2] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_4_1[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_4_1 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_4_1, +	.ev_actions    = llc_d_conn_actions_4_1, +}; + +/* + * State transition for + * LLC_CONN_EV_DATA_CONN_REQ event + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_5[] = { +	[0] = llc_conn_ev_qlfy_set_status_refuse, +	[1] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_d_conn_actions_5[1]; + +static struct llc_conn_state_trans llc_d_conn_state_trans_5 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_D_CONN, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_5, +	.ev_actions    = llc_d_conn_actions_5, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_6[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_6[] = { +	[0] = llc_conn_ac_send_disc_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_6 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_D_CONN, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_6, +	.ev_actions    = llc_d_conn_actions_6, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event, cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_7[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[2] = llc_conn_ev_qlfy_set_status_failed, +	[3] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_7[] = { +	[0] = llc_conn_ac_disc_confirm, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_7 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_7, +	.ev_actions    = llc_d_conn_actions_7, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event, cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_8[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[2] = llc_conn_ev_qlfy_set_status_failed, +	[3] = NULL, +}; + +static llc_conn_action_t llc_d_conn_actions_8[] = { +	[0] = llc_conn_disc, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_8 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_d_conn_ev_qfyrs_8, +	.ev_actions    = llc_d_conn_actions_8, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_d_conn_state_transitions[] = { +	 [0] = &llc_d_conn_state_trans_5,	/* Request */ +	 [1] = &llc_common_state_trans_end, +	 [2] = &llc_common_state_trans_end,	/* Local busy */ +	 [3] = &llc_common_state_trans_end,	/* Initiate PF cycle */ +	 [4] = &llc_d_conn_state_trans_6,	/* Timer */ +	 [5] = &llc_d_conn_state_trans_7, +	 [6] = &llc_d_conn_state_trans_8, +	 [7] = &llc_common_state_trans_end, +	 [8] = &llc_d_conn_state_trans_1,	/* Receive frame */ +	 [9] = &llc_d_conn_state_trans_1_1, +	[10] = &llc_d_conn_state_trans_2, +	[11] = &llc_d_conn_state_trans_2_1, +	[12] = &llc_d_conn_state_trans_3, +	[13] = &llc_d_conn_state_trans_4, +	[14] = &llc_d_conn_state_trans_4_1, +	[15] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_RESET transitions */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_rst_actions_1[] = { +	[0] = llc_conn_ac_set_vs_0, +	[1] = llc_conn_ac_set_vr_0, +	[2] = llc_conn_ac_set_s_flag_1, +	[3] = llc_conn_ac_send_ua_rsp_f_set_p, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_1 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_rst_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 1 + */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_2[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[2] = llc_conn_ev_qlfy_set_status_conn, +	[3] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_2[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_ac_set_vs_0, +	[2] = llc_conn_ac_set_vr_0, +	[3] = llc_conn_ac_upd_p_flag, +	[4] = llc_conn_ac_rst_confirm, +	[5] = llc_conn_ac_set_remote_busy_0, +	[6] = llc_conn_reset, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_2 = { +	.ev	       = llc_conn_ev_rx_ua_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_rst_ev_qfyrs_2, +	.ev_actions    = llc_rst_actions_2, +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_2_1[] = { +	[0] = llc_conn_ev_qlfy_p_flag_eq_f, +	[1] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[2] = llc_conn_ev_qlfy_set_status_rst_done, +	[3] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_2_1[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_ac_set_vs_0, +	[2] = llc_conn_ac_set_vr_0, +	[3] = llc_conn_ac_upd_p_flag, +	[4] = llc_conn_ac_rst_confirm, +	[5] = llc_conn_ac_set_remote_busy_0, +	[6] = llc_conn_reset, +	[7] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_2_1 = { +	.ev	       = llc_conn_ev_rx_ua_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_rst_ev_qfyrs_2_1, +	.ev_actions    = llc_rst_actions_2_1, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_3[] = { +	[0] = llc_conn_ev_qlfy_s_flag_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_rst_done, +	[2] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_3[] = { +	[0] = llc_conn_ac_set_p_flag_0, +	[1] = llc_conn_ac_set_remote_busy_0, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_3 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = llc_rst_ev_qfyrs_3, +	.ev_actions    = llc_rst_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event, + * cause_flag = 1 + */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_4[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_disc, +	[2] = NULL, +}; +static llc_conn_action_t llc_rst_actions_4[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_p, +	[1] = llc_conn_ac_disc_ind, +	[2] = llc_conn_ac_stop_ack_timer, +	[3] = llc_conn_disc, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_rst_ev_qfyrs_4, +	.ev_actions    = llc_rst_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_4_1[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[1] = llc_conn_ev_qlfy_set_status_refuse, +	[2] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_4_1[] = { +	[0] = llc_conn_ac_send_dm_rsp_f_set_p, +	[1] = llc_conn_ac_stop_ack_timer, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_4_1 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_rst_ev_qfyrs_4_1, +	.ev_actions    = llc_rst_actions_4_1, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 1 + */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_5[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[1] = llc_conn_ev_qlfy_set_status_disc, +	[2] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_5[] = { +	[0] = llc_conn_ac_disc_ind, +	[1] = llc_conn_ac_stop_ack_timer, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_5 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_rst_ev_qfyrs_5, +	.ev_actions    = llc_rst_actions_5, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_5_1[] = { +	[0] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[1] = llc_conn_ev_qlfy_set_status_refuse, +	[2] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_5_1[] = { +	[0] = llc_conn_ac_stop_ack_timer, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_5_1 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_rst_ev_qfyrs_5_1, +	.ev_actions    = llc_rst_actions_5_1, +}; + +/* State transitions for DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_6[] = { +	[0] = llc_conn_ev_qlfy_set_status_refuse, +	[1] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_rst_actions_6[1]; + +static struct llc_conn_state_trans llc_rst_state_trans_6 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_rst_ev_qfyrs_6, +	.ev_actions    = llc_rst_actions_6, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_7[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = llc_conn_ev_qlfy_s_flag_eq_0, +	[2] = NULL, +}; + +static llc_conn_action_t llc_rst_actions_7[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_7 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_rst_ev_qfyrs_7, +	.ev_actions    = llc_rst_actions_7, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_8[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = llc_conn_ev_qlfy_s_flag_eq_0, +	[2] = llc_conn_ev_qlfy_cause_flag_eq_1, +	[3] = llc_conn_ev_qlfy_set_status_failed, +	[4] = NULL, +}; +static llc_conn_action_t llc_rst_actions_8[] = { +	[0] = llc_conn_ac_disc_ind, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_8 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_rst_ev_qfyrs_8, +	.ev_actions    = llc_rst_actions_8, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_8_1[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = llc_conn_ev_qlfy_s_flag_eq_0, +	[2] = llc_conn_ev_qlfy_cause_flag_eq_0, +	[3] = llc_conn_ev_qlfy_set_status_failed, +	[4] = NULL, +}; +static llc_conn_action_t llc_rst_actions_8_1[] = { +	[0] = llc_conn_ac_disc_ind, +	[1] = llc_conn_disc, +	[2] = NULL, +}; + +static struct llc_conn_state_trans llc_rst_state_trans_8_1 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = llc_rst_ev_qfyrs_8_1, +	.ev_actions    = llc_rst_actions_8_1, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_rst_state_transitions[] = { +	 [0] = &llc_rst_state_trans_6,		/* Request */ +	 [1] = &llc_common_state_trans_end, +	 [2] = &llc_common_state_trans_end,	/* Local busy */ +	 [3] = &llc_common_state_trans_end,	/* Initiate PF cycle */ +	 [4] = &llc_rst_state_trans_3,		/* Timer */ +	 [5] = &llc_rst_state_trans_7, +	 [6] = &llc_rst_state_trans_8, +	 [7] = &llc_rst_state_trans_8_1, +	 [8] = &llc_common_state_trans_end, +	 [9] = &llc_rst_state_trans_1,		/* Receive frame */ +	[10] = &llc_rst_state_trans_2, +	[11] = &llc_rst_state_trans_2_1, +	[12] = &llc_rst_state_trans_4, +	[13] = &llc_rst_state_trans_4_1, +	[14] = &llc_rst_state_trans_5, +	[15] = &llc_rst_state_trans_5_1, +	[16] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_ERROR transitions */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_error_actions_1[] = { +	[0] = llc_conn_ac_set_vs_0, +	[1] = llc_conn_ac_set_vr_0, +	[2] = llc_conn_ac_send_ua_rsp_f_set_p, +	[3] = llc_conn_ac_rst_ind, +	[4] = llc_conn_ac_set_p_flag_0, +	[5] = llc_conn_ac_set_remote_busy_0, +	[6] = llc_conn_ac_stop_ack_timer, +	[7] = llc_conn_reset, +	[8] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_1 = { +	.ev	       = llc_conn_ev_rx_sabme_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_NORMAL, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_error_actions_1, +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_error_actions_2[] = { +	[0] = llc_conn_ac_send_ua_rsp_f_set_p, +	[1] = llc_conn_ac_disc_ind, +	[2] = llc_conn_ac_stop_ack_timer, +	[3] = llc_conn_disc, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_2 = { +	.ev	       = llc_conn_ev_rx_disc_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_error_actions_2, +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_error_actions_3[] = { +	[0] = llc_conn_ac_disc_ind, +	[1] = llc_conn_ac_stop_ack_timer, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_3 = { +	.ev	       = llc_conn_ev_rx_dm_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_error_actions_3, +}; + +/* State transitions for LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_error_actions_4[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_set_retry_cnt_0, +	[3] = llc_conn_ac_set_cause_flag_0, +	[4] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_4 = { +	.ev	       = llc_conn_ev_rx_frmr_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_error_actions_4, +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_error_actions_5[] = { +	[0] = llc_conn_ac_resend_frmr_rsp_f_set_p, +	[1] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_5 = { +	.ev	       = llc_conn_ev_rx_xxx_cmd_pbit_set_x, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_error_actions_5, +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_X event */ +static struct llc_conn_state_trans llc_error_state_trans_6 = { +	.ev	       = llc_conn_ev_rx_xxx_rsp_fbit_set_x, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = NONE, +	.ev_actions    = NONE, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_7[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_lt_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_error_actions_7[] = { +	[0] = llc_conn_ac_resend_frmr_rsp_f_set_0, +	[1] = llc_conn_ac_start_ack_timer, +	[2] = llc_conn_ac_inc_retry_cnt_by_1, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_7 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = llc_error_ev_qfyrs_7, +	.ev_actions    = llc_error_actions_7, +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_8[] = { +	[0] = llc_conn_ev_qlfy_retry_cnt_gte_n2, +	[1] = NULL, +}; + +static llc_conn_action_t llc_error_actions_8[] = { +	[0] = llc_conn_ac_send_sabme_cmd_p_set_x, +	[1] = llc_conn_ac_set_s_flag_0, +	[2] = llc_conn_ac_start_ack_timer, +	[3] = llc_conn_ac_set_retry_cnt_0, +	[4] = llc_conn_ac_set_cause_flag_0, +	[5] = NULL, +}; + +static struct llc_conn_state_trans llc_error_state_trans_8 = { +	.ev	       = llc_conn_ev_ack_tmr_exp, +	.next_state    = LLC_CONN_STATE_RESET, +	.ev_qualifiers = llc_error_ev_qfyrs_8, +	.ev_actions    = llc_error_actions_8, +}; + +/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_9[] = { +	[0] = llc_conn_ev_qlfy_set_status_refuse, +	[1] = NULL, +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_error_actions_9[1]; + +static struct llc_conn_state_trans llc_error_state_trans_9 = { +	.ev	       = llc_conn_ev_data_req, +	.next_state    = LLC_CONN_STATE_ERROR, +	.ev_qualifiers = llc_error_ev_qfyrs_9, +	.ev_actions    = llc_error_actions_9, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_error_state_transitions[] = { +	 [0] = &llc_error_state_trans_9,	/* Request */ +	 [1] = &llc_common_state_trans_end, +	 [2] = &llc_common_state_trans_end,	/* Local busy */ +	 [3] = &llc_common_state_trans_end,	/* Initiate PF cycle */ +	 [4] = &llc_error_state_trans_7,	/* Timer */ +	 [5] = &llc_error_state_trans_8, +	 [6] = &llc_common_state_trans_end, +	 [7] = &llc_error_state_trans_1,	/* Receive frame */ +	 [8] = &llc_error_state_trans_2, +	 [9] = &llc_error_state_trans_3, +	[10] = &llc_error_state_trans_4, +	[11] = &llc_error_state_trans_5, +	[12] = &llc_error_state_trans_6, +	[13] = &llc_common_state_trans_end, +}; + +/* LLC_CONN_STATE_TEMP transitions */ +/* State transitions for LLC_CONN_EV_DISC_REQ event */ +static llc_conn_action_t llc_temp_actions_1[] = { +	[0] = llc_conn_ac_stop_all_timers, +	[1] = llc_conn_ac_send_disc_cmd_p_set_x, +	[2] = llc_conn_disc, +	[3] = NULL, +}; + +static struct llc_conn_state_trans llc_temp_state_trans_1 = { +	.ev	       = llc_conn_ev_disc_req, +	.next_state    = LLC_CONN_STATE_ADM, +	.ev_qualifiers = NONE, +	.ev_actions    = llc_temp_actions_1, +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_temp_state_transitions[] = { +	[0] = &llc_temp_state_trans_1,		/* requests */ +	[1] = &llc_common_state_trans_end, +	[2] = &llc_common_state_trans_end,	/* local busy */ +	[3] = &llc_common_state_trans_end,	/* init_pf_cycle */ +	[4] = &llc_common_state_trans_end,	/* timer */ +	[5] = &llc_common_state_trans_end,	/* receive */ +}; + +/* Connection State Transition Table */ +struct llc_conn_state llc_conn_state_table[NBR_CONN_STATES] = { +	[LLC_CONN_STATE_ADM - 1] = { +		.current_state	= LLC_CONN_STATE_ADM, +		.transitions	= llc_adm_state_transitions, +	}, +	[LLC_CONN_STATE_SETUP - 1] = { +		.current_state	= LLC_CONN_STATE_SETUP, +		.transitions	= llc_setup_state_transitions, +	}, +	[LLC_CONN_STATE_NORMAL - 1] = { +		.current_state	= LLC_CONN_STATE_NORMAL, +		.transitions	= llc_normal_state_transitions, +	}, +	[LLC_CONN_STATE_BUSY - 1] = { +		.current_state	= LLC_CONN_STATE_BUSY, +		.transitions	= llc_busy_state_transitions, +	}, +	[LLC_CONN_STATE_REJ - 1] = { +		.current_state	= LLC_CONN_STATE_REJ, +		.transitions	= llc_reject_state_transitions, +	}, +	[LLC_CONN_STATE_AWAIT - 1] = { +		.current_state	= LLC_CONN_STATE_AWAIT, +		.transitions	= llc_await_state_transitions, +	}, +	[LLC_CONN_STATE_AWAIT_BUSY - 1] = { +		.current_state	= LLC_CONN_STATE_AWAIT_BUSY, +		.transitions	= llc_await_busy_state_transitions, +	}, +	[LLC_CONN_STATE_AWAIT_REJ - 1] = { +		.current_state	= LLC_CONN_STATE_AWAIT_REJ, +		.transitions	= llc_await_rejct_state_transitions, +	}, +	[LLC_CONN_STATE_D_CONN - 1] = { +		.current_state	= LLC_CONN_STATE_D_CONN, +		.transitions	= llc_d_conn_state_transitions, +	}, +	[LLC_CONN_STATE_RESET - 1] = { +		.current_state	= LLC_CONN_STATE_RESET, +		.transitions	= llc_rst_state_transitions, +	}, +	[LLC_CONN_STATE_ERROR - 1] = { +		.current_state	= LLC_CONN_STATE_ERROR, +		.transitions	= llc_error_state_transitions, +	}, +	[LLC_CONN_STATE_TEMP - 1] = { +		.current_state	= LLC_CONN_STATE_TEMP, +		.transitions	= llc_temp_state_transitions, +	}, +}; diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c new file mode 100644 index 000000000000..eba812a9c69c --- /dev/null +++ b/net/llc/llc_conn.c @@ -0,0 +1,915 @@ +/* + * llc_conn.c - Driver routines for connection component. + * + * Copyright (c) 1997 by Procom Technology, Inc. + *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/init.h> +#include <net/llc_sap.h> +#include <net/llc_conn.h> +#include <net/sock.h> +#include <linux/tcp.h> +#include <net/llc_c_ev.h> +#include <net/llc_c_ac.h> +#include <net/llc_c_st.h> +#include <net/llc_pdu.h> + +#if 0 +#define dprintk(args...) printk(KERN_DEBUG args) +#else +#define dprintk(args...) +#endif + +static int llc_find_offset(int state, int ev_type); +static void llc_conn_send_pdus(struct sock *sk); +static int llc_conn_service(struct sock *sk, struct sk_buff *skb); +static int llc_exec_conn_trans_actions(struct sock *sk, +				       struct llc_conn_state_trans *trans, +				       struct sk_buff *ev); +static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, +							struct sk_buff *skb); + +/* Offset table on connection states transition diagram */ +static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; + +/** + *	llc_conn_state_process - sends event to connection state machine + *	@sk: connection + *	@skb: occurred event + * + *	Sends an event to connection state machine. After processing event + *	(executing it's actions and changing state), upper layer will be + *	indicated or confirmed, if needed. Returns 0 for success, 1 for + *	failure. The socket lock has to be held before calling this function. + */ +int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) +{ +	int rc; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	/* +	 * We have to hold the skb, because llc_conn_service will kfree it in +	 * the sending path and we need to look at the skb->cb, where we encode +	 * llc_conn_state_ev. +	 */ +	skb_get(skb); +	ev->ind_prim = ev->cfm_prim = 0; +	rc = llc_conn_service(sk, skb); /* sending event to state machine */ +	if (rc) { +		printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__); +		goto out_kfree_skb; +	} + +	if (!ev->ind_prim && !ev->cfm_prim) { +		/* indicate or confirm not required */ +		if (!skb->list) +			goto out_kfree_skb; +		goto out_skb_put; +	} + +	if (ev->ind_prim && ev->cfm_prim) /* Paranoia */ +		skb_get(skb); + +	switch (ev->ind_prim) { +	case LLC_DATA_PRIM: +		llc_save_primitive(skb, LLC_DATA_PRIM); +		if (sock_queue_rcv_skb(sk, skb)) { +			/* +			 * shouldn't happen +			 */ +			printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n", +			       __FUNCTION__); +			kfree_skb(skb); +		} +		break; +	case LLC_CONN_PRIM: { +		struct sock *parent = skb->sk; + +		skb->sk = sk; +		skb_queue_tail(&parent->sk_receive_queue, skb); +		sk->sk_state_change(parent); +	} +		break; +	case LLC_DISC_PRIM: +		sock_hold(sk); +		if (sk->sk_type == SOCK_STREAM && +		    sk->sk_state == TCP_ESTABLISHED) { +			sk->sk_shutdown       = SHUTDOWN_MASK; +			sk->sk_socket->state  = SS_UNCONNECTED; +			sk->sk_state          = TCP_CLOSE; +			if (!sock_flag(sk, SOCK_DEAD)) { +				sk->sk_state_change(sk); +				sock_set_flag(sk, SOCK_DEAD); +			} +		} +		kfree_skb(skb); +		sock_put(sk); +		break; +	case LLC_RESET_PRIM: +		/* +		 * FIXME: +		 * RESET is not being notified to upper layers for now +		 */ +		printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__); +		kfree_skb(skb); +		break; +	default: +		if (ev->ind_prim) { +			printk(KERN_INFO "%s: received unknown %d prim!\n", +				__FUNCTION__, ev->ind_prim); +			kfree_skb(skb); +		} +		/* No indication */ +		break; +	} + +	switch (ev->cfm_prim) { +	case LLC_DATA_PRIM: +		if (!llc_data_accept_state(llc->state)) +			sk->sk_write_space(sk); +		else +			rc = llc->failed_data_req = 1; +		break; +	case LLC_CONN_PRIM: +		if (sk->sk_type == SOCK_STREAM && +		    sk->sk_state == TCP_SYN_SENT) { +			if (ev->status) { +				sk->sk_socket->state = SS_UNCONNECTED; +				sk->sk_state         = TCP_CLOSE; +			} else { +				sk->sk_socket->state = SS_CONNECTED; +				sk->sk_state         = TCP_ESTABLISHED; +			} +			sk->sk_state_change(sk); +		} +		break; +	case LLC_DISC_PRIM: +		sock_hold(sk); +		if (sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_CLOSING) { +			sk->sk_socket->state = SS_UNCONNECTED; +			sk->sk_state         = TCP_CLOSE; +			sk->sk_state_change(sk); +		} +		sock_put(sk); +		break; +	case LLC_RESET_PRIM: +		/* +		 * FIXME: +		 * RESET is not being notified to upper layers for now +		 */ +		printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__); +		break; +	default: +		if (ev->cfm_prim) { +			printk(KERN_INFO "%s: received unknown %d prim!\n", +					__FUNCTION__, ev->cfm_prim); +			break; +		} +		goto out_skb_put; /* No confirmation */ +	} +out_kfree_skb: +	kfree_skb(skb); +out_skb_put: +	kfree_skb(skb); +	return rc; +} + +void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) +{ +	/* queue PDU to send to MAC layer */ +	skb_queue_tail(&sk->sk_write_queue, skb); +	llc_conn_send_pdus(sk); +} + +/** + *	llc_conn_rtn_pdu - sends received data pdu to upper layer + *	@sk: Active connection + *	@skb: Received data frame + * + *	Sends received data pdu to upper layer (by using indicate function). + *	Prepares service parameters (prim and prim_data). calling indication + *	function will be done in llc_conn_state_process. + */ +void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +	ev->ind_prim = LLC_DATA_PRIM; +} + +/** + *	llc_conn_resend_i_pdu_as_cmd - resend all all unacknowledged I PDUs + *	@sk: active connection + *	@nr: NR + *	@first_p_bit: p_bit value of first pdu + * + *	Resend all unacknowledged I PDUs, starting with the NR; send first as + *	command PDU with P bit equal first_p_bit; if more than one send + *	subsequent as command PDUs with P bit equal zero (0). + */ +void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit) +{ +	struct sk_buff *skb; +	struct llc_pdu_sn *pdu; +	u16 nbr_unack_pdus; +	struct llc_sock *llc; +	u8 howmany_resend = 0; + +	llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus); +	if (!nbr_unack_pdus) +		goto out; +	/* +	 * Process unack PDUs only if unack queue is not empty; remove +	 * appropriate PDUs, fix them up, and put them on mac_pdu_q. +	 */ +	llc = llc_sk(sk); + +	while ((skb = skb_dequeue(&llc->pdu_unack_q)) != NULL) { +		pdu = llc_pdu_sn_hdr(skb); +		llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD); +		llc_pdu_set_pf_bit(skb, first_p_bit); +		skb_queue_tail(&sk->sk_write_queue, skb); +		first_p_bit = 0; +		llc->vS = LLC_I_GET_NS(pdu); +		howmany_resend++; +	} +	if (howmany_resend > 0) +		llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; +	/* any PDUs to re-send are queued up; start sending to MAC */ +	llc_conn_send_pdus(sk); +out:; +} + +/** + *	llc_conn_resend_i_pdu_as_rsp - Resend all unacknowledged I PDUs + *	@sk: active connection. + *	@nr: NR + *	@first_f_bit: f_bit value of first pdu. + * + *	Resend all unacknowledged I PDUs, starting with the NR; send first as + *	response PDU with F bit equal first_f_bit; if more than one send + *	subsequent as response PDUs with F bit equal zero (0). + */ +void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit) +{ +	struct sk_buff *skb; +	u16 nbr_unack_pdus; +	struct llc_sock *llc = llc_sk(sk); +	u8 howmany_resend = 0; + +	llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus); +	if (!nbr_unack_pdus) +		goto out; +	/* +	 * Process unack PDUs only if unack queue is not empty; remove +	 * appropriate PDUs, fix them up, and put them on mac_pdu_q +	 */ +	while ((skb = skb_dequeue(&llc->pdu_unack_q)) != NULL) { +		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +		llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP); +		llc_pdu_set_pf_bit(skb, first_f_bit); +		skb_queue_tail(&sk->sk_write_queue, skb); +		first_f_bit = 0; +		llc->vS = LLC_I_GET_NS(pdu); +		howmany_resend++; +	} +	if (howmany_resend > 0) +		llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; +	/* any PDUs to re-send are queued up; start sending to MAC */ +	llc_conn_send_pdus(sk); +out:; +} + +/** + *	llc_conn_remove_acked_pdus - Removes acknowledged pdus from tx queue + *	@sk: active connection + *	nr: NR + *	how_many_unacked: size of pdu_unack_q after removing acked pdus + * + *	Removes acknowledged pdus from transmit queue (pdu_unack_q). Returns + *	the number of pdus that removed from queue. + */ +int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked) +{ +	int pdu_pos, i; +	struct sk_buff *skb; +	struct llc_pdu_sn *pdu; +	int nbr_acked = 0; +	struct llc_sock *llc = llc_sk(sk); +	int q_len = skb_queue_len(&llc->pdu_unack_q); + +	if (!q_len) +		goto out; +	skb = skb_peek(&llc->pdu_unack_q); +	pdu = llc_pdu_sn_hdr(skb); + +	/* finding position of last acked pdu in queue */ +	pdu_pos = ((int)LLC_2_SEQ_NBR_MODULO + (int)nr - +			(int)LLC_I_GET_NS(pdu)) % LLC_2_SEQ_NBR_MODULO; + +	for (i = 0; i < pdu_pos && i < q_len; i++) { +		skb = skb_dequeue(&llc->pdu_unack_q); +		if (skb) +			kfree_skb(skb); +		nbr_acked++; +	} +out: +	*how_many_unacked = skb_queue_len(&llc->pdu_unack_q); +	return nbr_acked; +} + +/** + *	llc_conn_send_pdus - Sends queued PDUs + *	@sk: active connection + * + *	Sends queued pdus to MAC layer for transmission. + */ +static void llc_conn_send_pdus(struct sock *sk) +{ +	struct sk_buff *skb; + +	while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { +		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +		if (LLC_PDU_TYPE_IS_I(pdu) && +		    !(skb->dev->flags & IFF_LOOPBACK)) { +			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + +			skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb); +			if (!skb2) +				break; +			skb = skb2; +		} +		dev_queue_xmit(skb); +	} +} + +/** + *	llc_conn_service - finds transition and changes state of connection + *	@sk: connection + *	@skb: happened event + * + *	This function finds transition that matches with happened event, then + *	executes related actions and finally changes state of connection. + *	Returns 0 for success, 1 for failure. + */ +static int llc_conn_service(struct sock *sk, struct sk_buff *skb) +{ +	int rc = 1; +	struct llc_sock *llc = llc_sk(sk); +	struct llc_conn_state_trans *trans; + +	if (llc->state > NBR_CONN_STATES) +		goto out; +	rc = 0; +	trans = llc_qualify_conn_ev(sk, skb); +	if (trans) { +		rc = llc_exec_conn_trans_actions(sk, trans, skb); +		if (!rc && trans->next_state != NO_STATE_CHANGE) { +			llc->state = trans->next_state; +			if (!llc_data_accept_state(llc->state)) +				sk->sk_state_change(sk); +		} +	} +out: +	return rc; +} + +/** + *	llc_qualify_conn_ev - finds transition for event + *	@sk: connection + *	@skb: happened event + * + *	This function finds transition that matches with happened event. + *	Returns pointer to found transition on success, %NULL otherwise. + */ +static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, +							struct sk_buff *skb) +{ +	struct llc_conn_state_trans **next_trans; +	llc_conn_ev_qfyr_t *next_qualifier; +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); +	struct llc_sock *llc = llc_sk(sk); +	struct llc_conn_state *curr_state = +					&llc_conn_state_table[llc->state - 1]; + +	/* search thru events for this state until +	 * list exhausted or until no more +	 */ +	for (next_trans = curr_state->transitions + +		llc_find_offset(llc->state - 1, ev->type); +	     (*next_trans)->ev; next_trans++) { +		if (!((*next_trans)->ev)(sk, skb)) { +			/* got POSSIBLE event match; the event may require +			 * qualification based on the values of a number of +			 * state flags; if all qualifications are met (i.e., +			 * if all qualifying functions return success, or 0, +			 * then this is THE event we're looking for +			 */ +			for (next_qualifier = (*next_trans)->ev_qualifiers; +			     next_qualifier && *next_qualifier && +			     !(*next_qualifier)(sk, skb); next_qualifier++) +				/* nothing */; +			if (!next_qualifier || !*next_qualifier) +				/* all qualifiers executed successfully; this is +				 * our transition; return it so we can perform +				 * the associated actions & change the state +				 */ +				return *next_trans; +		} +	} +	return NULL; +} + +/** + *	llc_exec_conn_trans_actions - executes related actions + *	@sk: connection + *	@trans: transition that it's actions must be performed + *	@skb: event + * + *	Executes actions that is related to happened event. Returns 0 for + *	success, 1 to indicate failure of at least one action. + */ +static int llc_exec_conn_trans_actions(struct sock *sk, +				       struct llc_conn_state_trans *trans, +				       struct sk_buff *skb) +{ +	int rc = 0; +	llc_conn_action_t *next_action; + +	for (next_action = trans->ev_actions; +	     next_action && *next_action; next_action++) { +		int rc2 = (*next_action)(sk, skb); + +		if (rc2 == 2) { +			rc = rc2; +			break; +		} else if (rc2) +			rc = 1; +	} +	return rc; +} + +/** + *	llc_lookup_established - Finds connection for the remote/local sap/mac + *	@sap: SAP + *	@daddr: address of remote LLC (MAC + SAP) + *	@laddr: address of local LLC (MAC + SAP) + * + *	Search connection list of the SAP and finds connection using the remote + *	mac, remote sap, local mac, and local sap. Returns pointer for + *	connection found, %NULL otherwise. + */ +struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr, +				    struct llc_addr *laddr) +{ +	struct sock *rc; +	struct hlist_node *node; + +	read_lock_bh(&sap->sk_list.lock); +	sk_for_each(rc, node, &sap->sk_list.list) { +		struct llc_sock *llc = llc_sk(rc); + +		if (llc->laddr.lsap == laddr->lsap && +		    llc->daddr.lsap == daddr->lsap && +		    llc_mac_match(llc->laddr.mac, laddr->mac) && +		    llc_mac_match(llc->daddr.mac, daddr->mac)) { +			sock_hold(rc); +			goto found; +		} +	} +	rc = NULL; +found: +	read_unlock_bh(&sap->sk_list.lock); +	return rc; +} + +/** + *	llc_lookup_listener - Finds listener for local MAC + SAP + *	@sap: SAP + *	@laddr: address of local LLC (MAC + SAP) + * + *	Search connection list of the SAP and finds connection listening on + *	local mac, and local sap. Returns pointer for parent socket found, + *	%NULL otherwise. + */ +static struct sock *llc_lookup_listener(struct llc_sap *sap, +					struct llc_addr *laddr) +{ +	struct sock *rc; +	struct hlist_node *node; + +	read_lock_bh(&sap->sk_list.lock); +	sk_for_each(rc, node, &sap->sk_list.list) { +		struct llc_sock *llc = llc_sk(rc); + +		if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN && +		    llc->laddr.lsap == laddr->lsap && +		    (llc_mac_match(llc->laddr.mac, laddr->mac) || +		     llc_mac_null(llc->laddr.mac))) { +			sock_hold(rc); +			goto found; +		} +	} +	rc = NULL; +found: +	read_unlock_bh(&sap->sk_list.lock); +	return rc; +} + +/** + *	llc_data_accept_state - designates if in this state data can be sent. + *	@state: state of connection. + * + *	Returns 0 if data can be sent, 1 otherwise. + */ +u8 llc_data_accept_state(u8 state) +{ +	return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY && +	       state != LLC_CONN_STATE_REJ; +} + +/** + *	find_next_offset - finds offset for next category of transitions + *	@state: state table. + *	@offset: start offset. + * + *	Finds offset of next category of transitions in transition table. + *	Returns the start index of next category. + */ +static u16 find_next_offset(struct llc_conn_state *state, u16 offset) +{ +	u16 cnt = 0; +	struct llc_conn_state_trans **next_trans; + +	for (next_trans = state->transitions + offset; +	     (*next_trans)->ev; next_trans++) +		++cnt; +	return cnt; +} + +/** + *	llc_build_offset_table - builds offset table of connection + * + *	Fills offset table of connection state transition table + *	(llc_offset_table). + */ +void __init llc_build_offset_table(void) +{ +	struct llc_conn_state *curr_state; +	int state, ev_type, next_offset; + +	for (state = 0; state < NBR_CONN_STATES; state++) { +		curr_state = &llc_conn_state_table[state]; +		next_offset = 0; +		for (ev_type = 0; ev_type < NBR_CONN_EV; ev_type++) { +			llc_offset_table[state][ev_type] = next_offset; +			next_offset += find_next_offset(curr_state, +							next_offset) + 1; +		} +	} +} + +/** + *	llc_find_offset - finds start offset of category of transitions + *	@state: state of connection + *	@ev_type: type of happened event + * + *	Finds start offset of desired category of transitions. Returns the + *	desired start offset. + */ +static int llc_find_offset(int state, int ev_type) +{ +	int rc = 0; +	/* at this stage, llc_offset_table[..][2] is not important. it is for +	 * init_pf_cycle and I don't know what is it. +	 */ +	switch (ev_type) { +	case LLC_CONN_EV_TYPE_PRIM: +		rc = llc_offset_table[state][0]; break; +	case LLC_CONN_EV_TYPE_PDU: +		rc = llc_offset_table[state][4]; break; +	case LLC_CONN_EV_TYPE_SIMPLE: +		rc = llc_offset_table[state][1]; break; +	case LLC_CONN_EV_TYPE_P_TMR: +	case LLC_CONN_EV_TYPE_ACK_TMR: +	case LLC_CONN_EV_TYPE_REJ_TMR: +	case LLC_CONN_EV_TYPE_BUSY_TMR: +		rc = llc_offset_table[state][3]; break; +	} +	return rc; +} + +/** + *	llc_sap_add_socket - adds a socket to a SAP + *	@sap: SAP + *	@sk: socket + * + *	This function adds a socket to sk_list of a SAP. + */ +void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) +{ +	write_lock_bh(&sap->sk_list.lock); +	llc_sk(sk)->sap = sap; +	sk_add_node(sk, &sap->sk_list.list); +	write_unlock_bh(&sap->sk_list.lock); +} + +/** + *	llc_sap_remove_socket - removes a socket from SAP + *	@sap: SAP + *	@sk: socket + * + *	This function removes a connection from sk_list.list of a SAP if + *	the connection was in this list. + */ +void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) +{ +	write_lock_bh(&sap->sk_list.lock); +	sk_del_node_init(sk); +	write_unlock_bh(&sap->sk_list.lock); +} + +/** + *	llc_conn_rcv - sends received pdus to the connection state machine + *	@sk: current connection structure. + *	@skb: received frame. + * + *	Sends received pdus to the connection state machine. + */ +static int llc_conn_rcv(struct sock* sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev = llc_conn_ev(skb); +	struct llc_sock *llc = llc_sk(sk); + +	if (!llc->dev) +		llc->dev = skb->dev; +	ev->type   = LLC_CONN_EV_TYPE_PDU; +	ev->reason = 0; +	return llc_conn_state_process(sk, skb); +} + +void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_addr saddr, daddr; +	struct sock *sk; + +	llc_pdu_decode_sa(skb, saddr.mac); +	llc_pdu_decode_ssap(skb, &saddr.lsap); +	llc_pdu_decode_da(skb, daddr.mac); +	llc_pdu_decode_dsap(skb, &daddr.lsap); + +	sk = llc_lookup_established(sap, &saddr, &daddr); +	if (!sk) { +		/* +		 * Didn't find an active connection; verify if there +		 * is a listening socket for this llc addr +		 */ +		struct llc_sock *llc; +		struct sock *parent = llc_lookup_listener(sap, &daddr); + +		if (!parent) { +			dprintk("llc_lookup_listener failed!\n"); +			goto drop; +		} + +		sk = llc_sk_alloc(parent->sk_family, GFP_ATOMIC, parent->sk_prot); +		if (!sk) { +			sock_put(parent); +			goto drop; +		} +		llc = llc_sk(sk); +		memcpy(&llc->laddr, &daddr, sizeof(llc->laddr)); +		memcpy(&llc->daddr, &saddr, sizeof(llc->daddr)); +		llc_sap_add_socket(sap, sk); +		sock_hold(sk); +		sock_put(parent); +		skb->sk = parent; +	} else +		skb->sk = sk; +	bh_lock_sock(sk); +	if (!sock_owned_by_user(sk)) +		llc_conn_rcv(sk, skb); +	else { +		dprintk("%s: adding to backlog...\n", __FUNCTION__); +		llc_set_backlog_type(skb, LLC_PACKET); +		sk_add_backlog(sk, skb); +	} +	bh_unlock_sock(sk); +	sock_put(sk); +	return; +drop: +	kfree_skb(skb); +} + +#undef LLC_REFCNT_DEBUG +#ifdef LLC_REFCNT_DEBUG +static atomic_t llc_sock_nr; +#endif + +/** + *	llc_release_sockets - releases all sockets in a sap + *	@sap: sap to release its sockets + * + *	Releases all connections of a sap. Returns 0 if all actions complete + *	successfully, nonzero otherwise + */ +int llc_release_sockets(struct llc_sap *sap) +{ +	int rc = 0; +	struct sock *sk; +	struct hlist_node *node; + +	write_lock_bh(&sap->sk_list.lock); + +	sk_for_each(sk, node, &sap->sk_list.list) { +		llc_sk(sk)->state = LLC_CONN_STATE_TEMP; + +		if (llc_send_disc(sk)) +			rc = 1; +	} + +	write_unlock_bh(&sap->sk_list.lock); +	return rc; +} + +/** + *	llc_backlog_rcv - Processes rx frames and expired timers. + *	@sk: LLC sock (p8022 connection) + *	@skb: queued rx frame or event + * + *	This function processes frames that has received and timers that has + *	expired during sending an I pdu (refer to data_req_handler).  frames + *	queue by llc_rcv function (llc_mac.c) and timers queue by timer + *	callback functions(llc_c_ac.c). + */ +static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) +{ +	int rc = 0; +	struct llc_sock *llc = llc_sk(sk); + +	if (llc_backlog_type(skb) == LLC_PACKET) { +		if (llc->state > 1) /* not closed */ +			rc = llc_conn_rcv(sk, skb); +		else +			goto out_kfree_skb; +	} else if (llc_backlog_type(skb) == LLC_EVENT) { +		/* timer expiration event */ +		if (llc->state > 1)  /* not closed */ +			rc = llc_conn_state_process(sk, skb); +		else +			goto out_kfree_skb; +	} else { +		printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__); +		goto out_kfree_skb; +	} +out: +	return rc; +out_kfree_skb: +	kfree_skb(skb); +	goto out; +} + +/** + *     llc_sk_init - Initializes a socket with default llc values. + *     @sk: socket to initialize. + * + *     Initializes a socket with default llc values. + */ +static void llc_sk_init(struct sock* sk) +{ +	struct llc_sock *llc = llc_sk(sk); + +	llc->state    = LLC_CONN_STATE_ADM; +	llc->inc_cntr = llc->dec_cntr = 2; +	llc->dec_step = llc->connect_step = 1; + +	init_timer(&llc->ack_timer.timer); +	llc->ack_timer.expire	      = LLC_ACK_TIME; +	llc->ack_timer.timer.data     = (unsigned long)sk; +	llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; + +	init_timer(&llc->pf_cycle_timer.timer); +	llc->pf_cycle_timer.expire	   = LLC_P_TIME; +	llc->pf_cycle_timer.timer.data     = (unsigned long)sk; +	llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb; + +	init_timer(&llc->rej_sent_timer.timer); +	llc->rej_sent_timer.expire	   = LLC_REJ_TIME; +	llc->rej_sent_timer.timer.data     = (unsigned long)sk; +	llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb; + +	init_timer(&llc->busy_state_timer.timer); +	llc->busy_state_timer.expire	     = LLC_BUSY_TIME; +	llc->busy_state_timer.timer.data     = (unsigned long)sk; +	llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb; + +	llc->n2 = 2;   /* max retransmit */ +	llc->k  = 2;   /* tx win size, will adjust dynam */ +	llc->rw = 128; /* rx win size (opt and equal to +		        * tx_win of remote LLC) */ +	skb_queue_head_init(&llc->pdu_unack_q); +	sk->sk_backlog_rcv = llc_backlog_rcv; +} + +/** + *	llc_sk_alloc - Allocates LLC sock + *	@family: upper layer protocol family + *	@priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) + * + *	Allocates a LLC sock and initializes it. Returns the new LLC sock + *	or %NULL if there's no memory available for one + */ +struct sock *llc_sk_alloc(int family, int priority, struct proto *prot) +{ +	struct sock *sk = sk_alloc(family, priority, prot, 1); + +	if (!sk) +		goto out; +	llc_sk_init(sk); +	sock_init_data(NULL, sk); +#ifdef LLC_REFCNT_DEBUG +	atomic_inc(&llc_sock_nr); +	printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk, +		__FUNCTION__, atomic_read(&llc_sock_nr)); +#endif +out: +	return sk; +} + +/** + *	llc_sk_free - Frees a LLC socket + *	@sk - socket to free + * + *	Frees a LLC socket + */ +void llc_sk_free(struct sock *sk) +{ +	struct llc_sock *llc = llc_sk(sk); + +	llc->state = LLC_CONN_OUT_OF_SVC; +	/* Stop all (possibly) running timers */ +	llc_conn_ac_stop_all_timers(sk, NULL); +#ifdef DEBUG_LLC_CONN_ALLOC +	printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__, +		skb_queue_len(&llc->pdu_unack_q), +		skb_queue_len(&sk->sk_write_queue)); +#endif +	skb_queue_purge(&sk->sk_receive_queue); +	skb_queue_purge(&sk->sk_write_queue); +	skb_queue_purge(&llc->pdu_unack_q); +#ifdef LLC_REFCNT_DEBUG +	if (atomic_read(&sk->sk_refcnt) != 1) { +		printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n", +			sk, __FUNCTION__, atomic_read(&sk->sk_refcnt)); +		printk(KERN_DEBUG "%d LLC sockets are still alive\n", +			atomic_read(&llc_sock_nr)); +	} else { +		atomic_dec(&llc_sock_nr); +		printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk, +			__FUNCTION__, atomic_read(&llc_sock_nr)); +	} +#endif +	sock_put(sk); +} + +/** + *	llc_sk_reset - resets a connection + *	@sk: LLC socket to reset + * + *	Resets a connection to the out of service state. Stops its timers + *	and frees any frames in the queues of the connection. + */ +void llc_sk_reset(struct sock *sk) +{ +	struct llc_sock *llc = llc_sk(sk); + +	llc_conn_ac_stop_all_timers(sk, NULL); +	skb_queue_purge(&sk->sk_write_queue); +	skb_queue_purge(&llc->pdu_unack_q); +	llc->remote_busy_flag	= 0; +	llc->cause_flag		= 0; +	llc->retry_count	= 0; +	llc_conn_set_p_flag(sk, 0); +	llc->f_flag		= 0; +	llc->s_flag		= 0; +	llc->ack_pf		= 0; +	llc->first_pdu_Ns	= 0; +	llc->ack_must_be_send	= 0; +	llc->dec_step		= 1; +	llc->inc_cntr		= 2; +	llc->dec_cntr		= 2; +	llc->X			= 0; +	llc->failed_data_req	= 0 ; +	llc->last_nr		= 0; +} diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c new file mode 100644 index 000000000000..5ff02c080a0b --- /dev/null +++ b/net/llc/llc_core.c @@ -0,0 +1,179 @@ +/* + * llc_core.c - Minimum needed routines for sap handling and module init/exit + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/if_ether.h> +#include <linux/netdevice.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/init.h> +#include <net/llc.h> + +LIST_HEAD(llc_sap_list); +DEFINE_RWLOCK(llc_sap_list_lock); + +unsigned char llc_station_mac_sa[ETH_ALEN]; + +/** + *	llc_sap_alloc - allocates and initializes sap. + * + *	Allocates and initializes sap. + */ +static struct llc_sap *llc_sap_alloc(void) +{ +	struct llc_sap *sap = kmalloc(sizeof(*sap), GFP_ATOMIC); + +	if (sap) { +		memset(sap, 0, sizeof(*sap)); +		sap->state = LLC_SAP_STATE_ACTIVE; +		memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN); +		rwlock_init(&sap->sk_list.lock); +	} +	return sap; +} + +/** + *	llc_add_sap - add sap to station list + *	@sap: Address of the sap + * + *	Adds a sap to the LLC's station sap list. + */ +static void llc_add_sap(struct llc_sap *sap) +{ +	write_lock_bh(&llc_sap_list_lock); +	list_add_tail(&sap->node, &llc_sap_list); +	write_unlock_bh(&llc_sap_list_lock); +} + +/** + *	llc_del_sap - del sap from station list + *	@sap: Address of the sap + * + *	Removes a sap to the LLC's station sap list. + */ +static void llc_del_sap(struct llc_sap *sap) +{ +	write_lock_bh(&llc_sap_list_lock); +	list_del(&sap->node); +	write_unlock_bh(&llc_sap_list_lock); +} + +/** + *	llc_sap_find - searchs a SAP in station + *	@sap_value: sap to be found + * + *	Searchs for a sap in the sap list of the LLC's station upon the sap ID. + *	Returns the sap or %NULL if not found. + */ +struct llc_sap *llc_sap_find(unsigned char sap_value) +{ +	struct llc_sap* sap; + +	read_lock_bh(&llc_sap_list_lock); +	list_for_each_entry(sap, &llc_sap_list, node) +		if (sap->laddr.lsap == sap_value) +			goto out; +	sap = NULL; +out: +	read_unlock_bh(&llc_sap_list_lock); +	return sap; +} + +/** + *	llc_sap_open - open interface to the upper layers. + *	@lsap: SAP number. + *	@func: rcv func for datalink protos + * + *	Interface function to upper layer. Each one who wants to get a SAP + *	(for example NetBEUI) should call this function. Returns the opened + *	SAP for success, NULL for failure. + */ +struct llc_sap *llc_sap_open(unsigned char lsap, +			     int (*func)(struct sk_buff *skb, +					 struct net_device *dev, +					 struct packet_type *pt)) +{ +	struct llc_sap *sap = llc_sap_find(lsap); + +	if (sap) { /* SAP already exists */ +		sap = NULL; +		goto out; +	} +	sap = llc_sap_alloc(); +	if (!sap) +		goto out; +	sap->laddr.lsap = lsap; +	sap->rcv_func	= func; +	llc_add_sap(sap); +out: +	return sap; +} + +/** + *	llc_sap_close - close interface for upper layers. + *	@sap: SAP to be closed. + * + *	Close interface function to upper layer. Each one who wants to + *	close an open SAP (for example NetBEUI) should call this function. + * 	Removes this sap from the list of saps in the station and then + * 	frees the memory for this sap. + */ +void llc_sap_close(struct llc_sap *sap) +{ +	WARN_ON(!hlist_empty(&sap->sk_list.list)); +	llc_del_sap(sap); +	kfree(sap); +} + +static struct packet_type llc_packet_type = { +	.type = __constant_htons(ETH_P_802_2), +	.func = llc_rcv, +}; + +static struct packet_type llc_tr_packet_type = { +	.type = __constant_htons(ETH_P_TR_802_2), +	.func = llc_rcv, +}; + +static int __init llc_init(void) +{ +	if (dev_base->next) +		memcpy(llc_station_mac_sa, dev_base->next->dev_addr, ETH_ALEN); +	else +		memset(llc_station_mac_sa, 0, ETH_ALEN); +	dev_add_pack(&llc_packet_type); +	dev_add_pack(&llc_tr_packet_type); +	return 0; +} + +static void __exit llc_exit(void) +{ +	dev_remove_pack(&llc_packet_type); +	dev_remove_pack(&llc_tr_packet_type); +} + +module_init(llc_init); +module_exit(llc_exit); + +EXPORT_SYMBOL(llc_station_mac_sa); +EXPORT_SYMBOL(llc_sap_list); +EXPORT_SYMBOL(llc_sap_list_lock); +EXPORT_SYMBOL(llc_sap_find); +EXPORT_SYMBOL(llc_sap_open); +EXPORT_SYMBOL(llc_sap_close); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003"); +MODULE_DESCRIPTION("LLC IEEE 802.2 core support"); diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c new file mode 100644 index 000000000000..0f9fc48aeaf9 --- /dev/null +++ b/net/llc/llc_if.c @@ -0,0 +1,157 @@ +/* + * llc_if.c - Defines LLC interface to upper layer + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/tcp.h> +#include <asm/errno.h> +#include <net/llc_if.h> +#include <net/llc_sap.h> +#include <net/llc_s_ev.h> +#include <net/llc_conn.h> +#include <net/sock.h> +#include <net/llc_c_ev.h> +#include <net/llc_c_ac.h> +#include <net/llc_c_st.h> + +u8 llc_mac_null_var[IFHWADDRLEN]; + +/** + *	llc_build_and_send_pkt - Connection data sending for upper layers. + *	@sk: connection + *	@skb: packet to send + * + *	This function is called when upper layer wants to send data using + *	connection oriented communication mode. During sending data, connection + *	will be locked and received frames and expired timers will be queued. + *	Returns 0 for success, -ECONNABORTED when the connection already + *	closed and -EBUSY when sending data is not permitted in this state or + *	LLC has send an I pdu with p bit set to 1 and is waiting for it's + *	response. + */ +int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) +{ +	struct llc_conn_state_ev *ev; +	int rc = -ECONNABORTED; +	struct llc_sock *llc = llc_sk(sk); + +	if (llc->state == LLC_CONN_STATE_ADM) +		goto out; +	rc = -EBUSY; +	if (llc_data_accept_state(llc->state)) { /* data_conn_refuse */ +		llc->failed_data_req = 1; +		goto out; +	} +	if (llc->p_flag) { +		llc->failed_data_req = 1; +		goto out; +	} +	ev = llc_conn_ev(skb); +	ev->type      = LLC_CONN_EV_TYPE_PRIM; +	ev->prim      = LLC_DATA_PRIM; +	ev->prim_type = LLC_PRIM_TYPE_REQ; +	skb->dev      = llc->dev; +	rc = llc_conn_state_process(sk, skb); +out: +	return rc; +} + +/** + *	llc_establish_connection - Called by upper layer to establish a conn + *	@sk: connection + *	@lmac: local mac address + *	@dmac: destination mac address + *	@dsap: destination sap + * + *	Upper layer calls this to establish an LLC connection with a remote + *	machine. This function packages a proper event and sends it connection + *	component state machine. Success or failure of connection + *	establishment will inform to upper layer via calling it's confirm + *	function and passing proper information. + */ +int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap) +{ +	int rc = -EISCONN; +	struct llc_addr laddr, daddr; +	struct sk_buff *skb; +	struct llc_sock *llc = llc_sk(sk); +	struct sock *existing; + +	laddr.lsap = llc->sap->laddr.lsap; +	daddr.lsap = dsap; +	memcpy(daddr.mac, dmac, sizeof(daddr.mac)); +	memcpy(laddr.mac, lmac, sizeof(laddr.mac)); +	existing = llc_lookup_established(llc->sap, &daddr, &laddr); +	if (existing) { +		if (existing->sk_state == TCP_ESTABLISHED) { +			sk = existing; +			goto out_put; +		} else +			sock_put(existing); +	} +	sock_hold(sk); +	rc = -ENOMEM; +	skb = alloc_skb(0, GFP_ATOMIC); +	if (skb) { +		struct llc_conn_state_ev *ev = llc_conn_ev(skb); + +		ev->type      = LLC_CONN_EV_TYPE_PRIM; +		ev->prim      = LLC_CONN_PRIM; +		ev->prim_type = LLC_PRIM_TYPE_REQ; +		rc = llc_conn_state_process(sk, skb); +	} +out_put: +	sock_put(sk); +	return rc; +} + +/** + *	llc_send_disc - Called by upper layer to close a connection + *	@sk: connection to be closed + * + *	Upper layer calls this when it wants to close an established LLC + *	connection with a remote machine. This function packages a proper event + *	and sends it to connection component state machine. Returns 0 for + *	success, 1 otherwise. + */ +int llc_send_disc(struct sock *sk) +{ +	u16 rc = 1; +	struct llc_conn_state_ev *ev; +	struct sk_buff *skb; + +	sock_hold(sk); +	if (sk->sk_type != SOCK_STREAM || sk->sk_state != TCP_ESTABLISHED || +	    llc_sk(sk)->state == LLC_CONN_STATE_ADM || +	    llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) +		goto out; +	/* +	 * Postpone unassigning the connection from its SAP and returning the +	 * connection until all ACTIONs have been completely executed +	 */ +	skb = alloc_skb(0, GFP_ATOMIC); +	if (!skb) +		goto out; +	sk->sk_state  = TCP_CLOSING; +	ev	      = llc_conn_ev(skb); +	ev->type      = LLC_CONN_EV_TYPE_PRIM; +	ev->prim      = LLC_DISC_PRIM; +	ev->prim_type = LLC_PRIM_TYPE_REQ; +	rc = llc_conn_state_process(sk, skb); +out: +	sock_put(sk); +	return rc; +} + diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c new file mode 100644 index 000000000000..4da6976efc9c --- /dev/null +++ b/net/llc/llc_input.c @@ -0,0 +1,189 @@ +/* + * llc_input.c - Minimal input path for LLC + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/netdevice.h> +#include <net/llc.h> +#include <net/llc_pdu.h> +#include <net/llc_sap.h> + +#if 0 +#define dprintk(args...) printk(KERN_DEBUG args) +#else +#define dprintk(args...) +#endif + +/* + * Packet handler for the station, registerable because in the minimal + * LLC core that is taking shape only the very minimal subset of LLC that + * is needed for things like IPX, Appletalk, etc will stay, with all the + * rest in the llc1 and llc2 modules. + */ +static void (*llc_station_handler)(struct sk_buff *skb); + +/* + * Packet handlers for LLC_DEST_SAP and LLC_DEST_CONN. + */ +static void (*llc_type_handlers[2])(struct llc_sap *sap, +				    struct sk_buff *skb); + +void llc_add_pack(int type, void (*handler)(struct llc_sap *sap, +					    struct sk_buff *skb)) +{ +	if (type == LLC_DEST_SAP || type == LLC_DEST_CONN) +		llc_type_handlers[type - 1] = handler; +} + +void llc_remove_pack(int type) +{ +	if (type == LLC_DEST_SAP || type == LLC_DEST_CONN) +		llc_type_handlers[type - 1] = NULL; +} + +void llc_set_station_handler(void (*handler)(struct sk_buff *skb)) +{ +	llc_station_handler = handler; +} + +/** + *	llc_pdu_type - returns which LLC component must handle for PDU + *	@skb: input skb + * + *	This function returns which LLC component must handle this PDU. + */ +static __inline__ int llc_pdu_type(struct sk_buff *skb) +{ +	int type = LLC_DEST_CONN; /* I-PDU or S-PDU type */ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) != LLC_PDU_TYPE_U) +		goto out; +	switch (LLC_U_PDU_CMD(pdu)) { +	case LLC_1_PDU_CMD_XID: +	case LLC_1_PDU_CMD_UI: +	case LLC_1_PDU_CMD_TEST: +		type = LLC_DEST_SAP; +		break; +	case LLC_2_PDU_CMD_SABME: +	case LLC_2_PDU_CMD_DISC: +	case LLC_2_PDU_RSP_UA: +	case LLC_2_PDU_RSP_DM: +	case LLC_2_PDU_RSP_FRMR: +		break; +	default: +		type = LLC_DEST_INVALID; +		break; +	} +out: +	return type; +} + +/** + *	llc_fixup_skb - initializes skb pointers + *	@skb: This argument points to incoming skb + * + *	Initializes internal skb pointer to start of network layer by deriving + *	length of LLC header; finds length of LLC control field in LLC header + *	by looking at the two lowest-order bits of the first control field + *	byte; field is either 3 or 4 bytes long. + */ +static inline int llc_fixup_skb(struct sk_buff *skb) +{ +	u8 llc_len = 2; +	struct llc_pdu_sn *pdu; + +	if (!pskb_may_pull(skb, sizeof(*pdu))) +		return 0; + +	pdu = (struct llc_pdu_sn *)skb->data; +	if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U) +		llc_len = 1; +	llc_len += 2; +	skb->h.raw += llc_len; +	skb_pull(skb, llc_len); +	if (skb->protocol == htons(ETH_P_802_2)) { +		u16 pdulen = eth_hdr(skb)->h_proto, +		    data_size = ntohs(pdulen) - llc_len; + +		skb_trim(skb, data_size); +	} +	return 1; +} + +/** + *	llc_rcv - 802.2 entry point from net lower layers + *	@skb: received pdu + *	@dev: device that receive pdu + *	@pt: packet type + * + *	When the system receives a 802.2 frame this function is called. It + *	checks SAP and connection of received pdu and passes frame to + *	llc_{station,sap,conn}_rcv for sending to proper state machine. If + *	the frame is related to a busy connection (a connection is sending + *	data now), it queues this frame in the connection's backlog. + */ +int llc_rcv(struct sk_buff *skb, struct net_device *dev, +	    struct packet_type *pt) +{ +	struct llc_sap *sap; +	struct llc_pdu_sn *pdu; +	int dest; + +	/* +	 * When the interface is in promisc. mode, drop all the crap that it +	 * receives, do not try to analyse it. +	 */ +	if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) { +		dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__); +		goto drop; +	} +	skb = skb_share_check(skb, GFP_ATOMIC); +	if (unlikely(!skb)) +		goto out; +	if (unlikely(!llc_fixup_skb(skb))) +		goto drop; +	pdu = llc_pdu_sn_hdr(skb); +	if (unlikely(!pdu->dsap)) /* NULL DSAP, refer to station */ +	       goto handle_station; +	sap = llc_sap_find(pdu->dsap); +	if (unlikely(!sap)) {/* unknown SAP */ +		dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, +		        pdu->dsap); +		goto drop; +	} +	/* +	 * First the upper layer protocols that don't need the full +	 * LLC functionality +	 */ +	if (sap->rcv_func) { +		sap->rcv_func(skb, dev, pt); +		goto out; +	} +	dest = llc_pdu_type(skb); +	if (unlikely(!dest || !llc_type_handlers[dest - 1])) +		goto drop; +	llc_type_handlers[dest - 1](sap, skb); +out: +	return 0; +drop: +	kfree_skb(skb); +	goto out; +handle_station: +	if (!llc_station_handler) +		goto drop; +	llc_station_handler(skb); +	goto out; +} + +EXPORT_SYMBOL(llc_add_pack); +EXPORT_SYMBOL(llc_remove_pack); +EXPORT_SYMBOL(llc_set_station_handler); diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c new file mode 100644 index 000000000000..ab5784cf163e --- /dev/null +++ b/net/llc/llc_output.c @@ -0,0 +1,107 @@ +/* + * llc_output.c - LLC minimal output path + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License version 2 for more details. + */ + +#include <linux/if_arp.h> +#include <linux/if_tr.h> +#include <linux/netdevice.h> +#include <linux/trdevice.h> +#include <linux/skbuff.h> +#include <net/llc.h> +#include <net/llc_pdu.h> + +/** + *	llc_mac_hdr_init - fills MAC header fields + *	@skb: Address of the frame to initialize its MAC header + *	@sa: The MAC source address + *	@da: The MAC destination address + * + *	Fills MAC header fields, depending on MAC type. Returns 0, If MAC type + *	is a valid type and initialization completes correctly 1, otherwise. + */ +int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da) +{ +	int rc = 0; + +	switch (skb->dev->type) { +#ifdef CONFIG_TR +	case ARPHRD_IEEE802_TR: { +		struct net_device *dev = skb->dev; +		struct trh_hdr *trh; +		 +		skb->mac.raw = skb_push(skb, sizeof(*trh)); +		trh = tr_hdr(skb); +		trh->ac = AC; +		trh->fc = LLC_FRAME; +		if (sa) +			memcpy(trh->saddr, sa, dev->addr_len); +		else +			memset(trh->saddr, 0, dev->addr_len); +		if (da) { +			memcpy(trh->daddr, da, dev->addr_len); +			tr_source_route(skb, trh, dev); +			skb->mac.raw = skb->data; +		} +		break; +	} +#endif +	case ARPHRD_ETHER: +	case ARPHRD_LOOPBACK: { +		unsigned short len = skb->len; +		struct ethhdr *eth; + +		skb->mac.raw = skb_push(skb, sizeof(*eth)); +		eth = eth_hdr(skb); +		eth->h_proto = htons(len); +		memcpy(eth->h_dest, da, ETH_ALEN); +		memcpy(eth->h_source, sa, ETH_ALEN); +		break; +	} +	default: +		printk(KERN_WARNING "device type not supported: %d\n", +		       skb->dev->type); +		rc = -EINVAL; +	} +	return rc; +} + +/** + *	llc_build_and_send_ui_pkt - unitdata request interface for upper layers + *	@sap: sap to use + *	@skb: packet to send + *	@dmac: destination mac address + *	@dsap: destination sap + * + *	Upper layers calls this function when upper layer wants to send data + *	using connection-less mode communication (UI pdu). + * + *	Accept data frame from network layer to be sent using connection- + *	less mode communication; timeout/retries handled by network layer; + *	package primitive as an event and send to SAP event handler + */ +int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb, +			      unsigned char *dmac, unsigned char dsap) +{ +	int rc; +	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, +			    dsap, LLC_PDU_CMD); +	llc_pdu_init_as_ui_cmd(skb); +	rc = llc_mac_hdr_init(skb, skb->dev->dev_addr, dmac); +	if (!rc) +		rc = dev_queue_xmit(skb); +	return rc; +} + +EXPORT_SYMBOL(llc_mac_hdr_init); +EXPORT_SYMBOL(llc_build_and_send_ui_pkt); diff --git a/net/llc/llc_output.h b/net/llc/llc_output.h new file mode 100644 index 000000000000..179edf753f00 --- /dev/null +++ b/net/llc/llc_output.h @@ -0,0 +1,20 @@ +#ifndef LLC_OUTPUT_H +#define LLC_OUTPUT_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License version 2 for more details. + */ + +struct sk_buff; + +int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da); + +#endif /* LLC_OUTPUT_H */ diff --git a/net/llc/llc_pdu.c b/net/llc/llc_pdu.c new file mode 100644 index 000000000000..a28ce525d201 --- /dev/null +++ b/net/llc/llc_pdu.c @@ -0,0 +1,372 @@ +/* + * llc_pdu.c - access to PDU internals + * + * Copyright (c) 1997 by Procom Technology, Inc. + *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/netdevice.h> +#include <net/llc_pdu.h> + +static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); +static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu); + +void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type) +{ +	llc_pdu_un_hdr(skb)->ssap |= pdu_type; +} + +/** + *	pdu_set_pf_bit - sets poll/final bit in LLC header + *	@pdu_frame: input frame that p/f bit must be set into it. + *	@bit_value: poll/final bit (0 or 1). + * + *	This function sets poll/final bit in LLC header (based on type of PDU). + *	in I or S pdus, p/f bit is right bit of fourth byte in header. in U + *	pdus p/f bit is fifth bit of third byte. + */ +void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) +{ +	u8 pdu_type; +	struct llc_pdu_sn *pdu; + +	llc_pdu_decode_pdu_type(skb, &pdu_type); +	pdu = llc_pdu_sn_hdr(skb); +	 +	switch (pdu_type) { +	case LLC_PDU_TYPE_I: +	case LLC_PDU_TYPE_S: +		pdu->ctrl_2 = (pdu->ctrl_2 & 0xFE) | bit_value; +		break; +	case LLC_PDU_TYPE_U: +		pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4); +		break; +	} +} + +/** + *	llc_pdu_decode_pf_bit - extracs poll/final bit from LLC header + *	@skb: input skb that p/f bit must be extracted from it + *	@pf_bit: poll/final bit (0 or 1) + * + *	This function extracts poll/final bit from LLC header (based on type of + *	PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In + *	U pdus p/f bit is fifth bit of third byte. + */ +void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) +{ +	u8 pdu_type; +	struct llc_pdu_sn *pdu; + +	llc_pdu_decode_pdu_type(skb, &pdu_type); +	pdu = llc_pdu_sn_hdr(skb); + +	switch (pdu_type) { +	case LLC_PDU_TYPE_I: +	case LLC_PDU_TYPE_S: +		*pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK; +		break; +	case LLC_PDU_TYPE_U: +		*pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; +		break; +	} +} + +/** + *	llc_pdu_init_as_disc_cmd - Builds DISC PDU + *	@skb: Address of the skb to build + *	@p_bit: The P bit to set in the PDU + * + *	Builds a pdu frame as a DISC command. + */ +void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_U; +	pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC; +	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; +} + +/** + *	llc_pdu_init_as_i_cmd - builds I pdu + *	@skb: Address of the skb to build + *	@p_bit: The P bit to set in the PDU + *	@ns: The sequence number of the data PDU + *	@nr: The seq. number of the expected I PDU from the remote + * + *	Builds a pdu frame as an I command. + */ +void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_I; +	pdu->ctrl_2  = 0; +	pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */ +	pdu->ctrl_1 |= (ns << 1) & 0xFE;   /* set N(S) in bits 2..8 */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE;   /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_rej_cmd - builds REJ PDU + *	@skb: Address of the skb to build + *	@p_bit: The P bit to set in the PDU + *	@nr: The seq. number of the expected I PDU from the remote + * + *	Builds a pdu frame as a REJ command. + */ +void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_S; +	pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ; +	pdu->ctrl_2  = 0; +	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; +	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_rnr_cmd - builds RNR pdu + *	@skb: Address of the skb to build + *	@p_bit: The P bit to set in the PDU + *	@nr: The seq. number of the expected I PDU from the remote + * + *	Builds a pdu frame as an RNR command. + */ +void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_S; +	pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR; +	pdu->ctrl_2  = 0; +	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; +	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_rr_cmd - Builds RR pdu + *	@skb: Address of the skb to build + *	@p_bit: The P bit to set in the PDU + *	@nr: The seq. number of the expected I PDU from the remote + * + *	Builds a pdu frame as an RR command. + */ +void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_S; +	pdu->ctrl_1 |= LLC_2_PDU_CMD_RR; +	pdu->ctrl_2  = p_bit & LLC_S_PF_BIT_MASK; +	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_sabme_cmd - builds SABME pdu + *	@skb: Address of the skb to build + *	@p_bit: The P bit to set in the PDU + * + *	Builds a pdu frame as an SABME command. + */ +void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_U; +	pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME; +	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; +} + +/** + *	llc_pdu_init_as_dm_rsp - builds DM response pdu + *	@skb: Address of the skb to build + *	@f_bit: The F bit to set in the PDU + * + *	Builds a pdu frame as a DM response. + */ +void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_U; +	pdu->ctrl_1 |= LLC_2_PDU_RSP_DM; +	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; +} + +/** + *	llc_pdu_init_as_frmr_rsp - builds FRMR response PDU + *	@skb: Address of the frame to build + *	@prev_pdu: The rejected PDU frame + *	@f_bit: The F bit to set in the PDU + *	@vs: tx state vari value for the data link conn at the rejecting LLC + *	@vr: rx state var value for the data link conn at the rejecting LLC + *	@vzyxw: completely described in the IEEE Std 802.2 document (Pg 55) + * + *	Builds a pdu frame as a FRMR response. + */ +void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, +			      u8 f_bit, u8 vs, u8 vr, u8 vzyxw) +{ +	struct llc_frmr_info *frmr_info; +	u8 prev_pf = 0; +	u8 *ctrl; +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_U; +	pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR; +	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; + +	frmr_info = (struct llc_frmr_info *)&pdu->ctrl_2; +	ctrl = (u8 *)&prev_pdu->ctrl_1; +	FRMR_INFO_SET_REJ_CNTRL(frmr_info,ctrl); +	FRMR_INFO_SET_Vs(frmr_info, vs); +	FRMR_INFO_SET_Vr(frmr_info, vr); +	prev_pf = llc_pdu_get_pf_bit(prev_pdu); +	FRMR_INFO_SET_C_R_BIT(frmr_info, prev_pf); +	FRMR_INFO_SET_INVALID_PDU_CTRL_IND(frmr_info, vzyxw); +	FRMR_INFO_SET_INVALID_PDU_INFO_IND(frmr_info, vzyxw); +	FRMR_INFO_SET_PDU_INFO_2LONG_IND(frmr_info, vzyxw); +	FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw); +	FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw); +	skb_put(skb, 5); +} + +/** + *	llc_pdu_init_as_rr_rsp - builds RR response pdu + *	@skb: Address of the skb to build + *	@f_bit: The F bit to set in the PDU + *	@nr: The seq. number of the expected data PDU from the remote + * + *	Builds a pdu frame as an RR response. + */ +void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_S; +	pdu->ctrl_1 |= LLC_2_PDU_RSP_RR; +	pdu->ctrl_2  = 0; +	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; +	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_rej_rsp - builds REJ response pdu + *	@skb: Address of the skb to build + *	@f_bit: The F bit to set in the PDU + *	@nr: The seq. number of the expected data PDU from the remote + * + *	Builds a pdu frame as a REJ response. + */ +void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_S; +	pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ; +	pdu->ctrl_2  = 0; +	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; +	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_rnr_rsp - builds RNR response pdu + *	@skb: Address of the frame to build + *	@f_bit: The F bit to set in the PDU + *	@nr: The seq. number of the expected data PDU from the remote + * + *	Builds a pdu frame as an RNR response. + */ +void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +{ +	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_S; +	pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR; +	pdu->ctrl_2  = 0; +	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; +	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ +	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */ +} + +/** + *	llc_pdu_init_as_ua_rsp - builds UA response pdu + *	@skb: Address of the frame to build + *	@f_bit: The F bit to set in the PDU + * + *	Builds a pdu frame as a UA response. + */ +void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	pdu->ctrl_1  = LLC_PDU_TYPE_U; +	pdu->ctrl_1 |= LLC_2_PDU_RSP_UA; +	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; +} + +/** + *	llc_pdu_decode_pdu_type - designates PDU type + *	@skb: input skb that type of it must be designated. + *	@type: type of PDU (output argument). + * + *	This function designates type of PDU (I, S or U). + */ +static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) +{ +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	if (pdu->ctrl_1 & 1) { +		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U) +			*type = LLC_PDU_TYPE_U; +		else +			*type = LLC_PDU_TYPE_S; +	} else +		*type = LLC_PDU_TYPE_I; +} + +/** + *	llc_pdu_get_pf_bit - extracts p/f bit of input PDU + *	@pdu: pointer to LLC header. + * + *	This function extracts p/f bit of input PDU. at first examines type of + *	PDU and then extracts p/f bit. Returns the p/f bit. + */ +static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu) +{ +	u8 pdu_type; +	u8 pf_bit = 0; + +	if (pdu->ctrl_1 & 1) { +		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U) +			pdu_type = LLC_PDU_TYPE_U; +		else +			pdu_type = LLC_PDU_TYPE_S; +	} else +		pdu_type = LLC_PDU_TYPE_I; +	switch (pdu_type) { +	case LLC_PDU_TYPE_I: +	case LLC_PDU_TYPE_S: +		pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK; +		break; +	case LLC_PDU_TYPE_U: +		pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; +		break; +	} +	return pf_bit; +} diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c new file mode 100644 index 000000000000..36e8db3fa1a2 --- /dev/null +++ b/net/llc/llc_proc.c @@ -0,0 +1,267 @@ +/* + * proc_llc.c - proc interface for LLC + * + * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org> + *		 2002-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/errno.h> +#include <linux/seq_file.h> +#include <net/sock.h> +#include <net/llc.h> +#include <net/llc_c_ac.h> +#include <net/llc_c_ev.h> +#include <net/llc_c_st.h> +#include <net/llc_conn.h> + +static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac) +{ +	seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", +		   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static struct sock *llc_get_sk_idx(loff_t pos) +{ +	struct list_head *sap_entry; +	struct llc_sap *sap; +	struct hlist_node *node; +	struct sock *sk = NULL; + +	list_for_each(sap_entry, &llc_sap_list) { +		sap = list_entry(sap_entry, struct llc_sap, node); + +		read_lock_bh(&sap->sk_list.lock); +		sk_for_each(sk, node, &sap->sk_list.list) { +			if (!pos) +				goto found; +			--pos; +		} +		read_unlock_bh(&sap->sk_list.lock); +	} +	sk = NULL; +found: +	return sk; +} + +static void *llc_seq_start(struct seq_file *seq, loff_t *pos) +{ +	loff_t l = *pos; + +	read_lock_bh(&llc_sap_list_lock); +	return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN; +} + +static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ +	struct sock* sk, *next; +	struct llc_sock *llc; +	struct llc_sap *sap; + +	++*pos; +	if (v == SEQ_START_TOKEN) { +		sk = llc_get_sk_idx(0); +		goto out; +	} +	sk = v; +	next = sk_next(sk); +	if (next) { +		sk = next; +		goto out; +	} +	llc = llc_sk(sk); +	sap = llc->sap; +	read_unlock_bh(&sap->sk_list.lock); +	sk = NULL; +	for (;;) { +		if (sap->node.next == &llc_sap_list) +			break; +		sap = list_entry(sap->node.next, struct llc_sap, node); +		read_lock_bh(&sap->sk_list.lock); +		if (!hlist_empty(&sap->sk_list.list)) { +			sk = sk_head(&sap->sk_list.list); +			break; +		} +		read_unlock_bh(&sap->sk_list.lock); +	} +out: +	return sk; +} + +static void llc_seq_stop(struct seq_file *seq, void *v) +{ +	if (v && v != SEQ_START_TOKEN) { +		struct sock *sk = v; +		struct llc_sock *llc = llc_sk(sk); +		struct llc_sap *sap = llc->sap; + +		read_unlock_bh(&sap->sk_list.lock); +	} +	read_unlock_bh(&llc_sap_list_lock); +} + +static int llc_seq_socket_show(struct seq_file *seq, void *v) +{ +	struct sock* sk; +	struct llc_sock *llc; + +	if (v == SEQ_START_TOKEN) { +		seq_puts(seq, "SKt Mc local_mac_sap        remote_mac_sap   " +			      "    tx_queue rx_queue st uid link\n"); +		goto out; +	} +	sk = v; +	llc = llc_sk(sk); + +	/* FIXME: check if the address is multicast */ +	seq_printf(seq, "%2X  %2X ", sk->sk_type, 0); + +	if (llc->dev) +		llc_ui_format_mac(seq, llc->dev->dev_addr); +	else +		seq_printf(seq, "00:00:00:00:00:00"); +	seq_printf(seq, "@%02X ", llc->sap->laddr.lsap); +	llc_ui_format_mac(seq, llc->daddr.mac); +	seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, +		   atomic_read(&sk->sk_wmem_alloc), +		   atomic_read(&sk->sk_rmem_alloc), +		   sk->sk_state, +		   sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1, +		   llc->link); +out: +	return 0; +} + +static char *llc_conn_state_names[] = { +	[LLC_CONN_STATE_ADM] =        "adm",  +	[LLC_CONN_STATE_SETUP] =      "setup",  +	[LLC_CONN_STATE_NORMAL] =     "normal", +	[LLC_CONN_STATE_BUSY] =       "busy",  +	[LLC_CONN_STATE_REJ] =        "rej",  +	[LLC_CONN_STATE_AWAIT] =      "await",  +	[LLC_CONN_STATE_AWAIT_BUSY] = "await_busy", +	[LLC_CONN_STATE_AWAIT_REJ] =  "await_rej", +	[LLC_CONN_STATE_D_CONN]	=     "d_conn", +	[LLC_CONN_STATE_RESET] =      "reset",  +	[LLC_CONN_STATE_ERROR] =      "error",  +	[LLC_CONN_STATE_TEMP] =       "temp",  +}; + +static int llc_seq_core_show(struct seq_file *seq, void *v) +{ +	struct sock* sk; +	struct llc_sock *llc; + +	if (v == SEQ_START_TOKEN) { +		seq_puts(seq, "Connection list:\n" +			      "dsap state      retr txw rxw pf ff sf df rs cs " +			      "tack tpfc trs tbs blog busr\n"); +		goto out; +	} +	sk = v; +	llc = llc_sk(sk); + +	seq_printf(seq, " %02X  %-10s %3d  %3d %3d %2d %2d %2d %2d %2d %2d " +			"%4d %4d %3d %3d %4d %4d\n", +		   llc->daddr.lsap, llc_conn_state_names[llc->state], +		   llc->retry_count, llc->k, llc->rw, llc->p_flag, llc->f_flag, +		   llc->s_flag, llc->data_flag, llc->remote_busy_flag, +		   llc->cause_flag, timer_pending(&llc->ack_timer.timer), +		   timer_pending(&llc->pf_cycle_timer.timer), +		   timer_pending(&llc->rej_sent_timer.timer), +		   timer_pending(&llc->busy_state_timer.timer), +		   !!sk->sk_backlog.tail, !!sock_owned_by_user(sk)); +out: +	return 0; +} + +static struct seq_operations llc_seq_socket_ops = { +	.start  = llc_seq_start, +	.next   = llc_seq_next, +	.stop   = llc_seq_stop, +	.show   = llc_seq_socket_show, +}; + +static struct seq_operations llc_seq_core_ops = { +	.start  = llc_seq_start, +	.next   = llc_seq_next, +	.stop   = llc_seq_stop, +	.show   = llc_seq_core_show, +}; + +static int llc_seq_socket_open(struct inode *inode, struct file *file) +{ +	return seq_open(file, &llc_seq_socket_ops); +} + +static int llc_seq_core_open(struct inode *inode, struct file *file) +{ +	return seq_open(file, &llc_seq_core_ops); +} + +static struct file_operations llc_seq_socket_fops = { +	.owner		= THIS_MODULE, +	.open		= llc_seq_socket_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; + +static struct file_operations llc_seq_core_fops = { +	.owner		= THIS_MODULE, +	.open		= llc_seq_core_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; + +static struct proc_dir_entry *llc_proc_dir; + +int __init llc_proc_init(void) +{ +	int rc = -ENOMEM; +	struct proc_dir_entry *p; + +	llc_proc_dir = proc_mkdir("llc", proc_net); +	if (!llc_proc_dir) +		goto out; +	llc_proc_dir->owner = THIS_MODULE; + +	p = create_proc_entry("socket", S_IRUGO, llc_proc_dir); +	if (!p) +		goto out_socket; + +	p->proc_fops = &llc_seq_socket_fops; + +	p = create_proc_entry("core", S_IRUGO, llc_proc_dir); +	if (!p) +		goto out_core; + +	p->proc_fops = &llc_seq_core_fops; + +	rc = 0; +out: +	return rc; +out_core: +	remove_proc_entry("socket", llc_proc_dir); +out_socket: +	remove_proc_entry("llc", proc_net); +	goto out; +} + +void llc_proc_exit(void) +{ +	remove_proc_entry("socket", llc_proc_dir); +	remove_proc_entry("core", llc_proc_dir); +	remove_proc_entry("llc", proc_net); +} diff --git a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c new file mode 100644 index 000000000000..ed8ba7de6122 --- /dev/null +++ b/net/llc/llc_s_ac.c @@ -0,0 +1,205 @@ +/* + * llc_s_ac.c - actions performed during sap state transition. + * + * Description : + *   Functions in this module are implementation of sap component actions. + *   Details of actions can be found in IEEE-802.2 standard document. + *   All functions have one sap and one event as input argument. All of + *   them return 0 On success and 1 otherwise. + * + * Copyright (c) 1997 by Procom Technology, Inc. + *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/netdevice.h> +#include <net/llc.h> +#include <net/llc_pdu.h> +#include <net/llc_s_ac.h> +#include <net/llc_s_ev.h> +#include <net/llc_sap.h> +#include "llc_output.h" + +/** + *	llc_sap_action_unit_data_ind - forward UI PDU to network layer + *	@sap: SAP + *	@skb: the event to forward + * + *	Received a UI PDU from MAC layer; forward to network layer as a + *	UNITDATA INDICATION; verify our event is the kind we expect + */ +int llc_sap_action_unitdata_ind(struct llc_sap *sap, struct sk_buff *skb) +{ +	llc_sap_rtn_pdu(sap, skb); +	return 0; +} + +/** + *	llc_sap_action_send_ui - sends UI PDU resp to UNITDATA REQ to MAC layer + *	@sap: SAP + *	@skb: the event to send + * + *	Sends a UI PDU to the MAC layer in response to a UNITDATA REQUEST + *	primitive from the network layer. Verifies event is a primitive type of + *	event. Verify the primitive is a UNITDATA REQUEST. + */ +int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	int rc; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap, +			    ev->daddr.lsap, LLC_PDU_CMD); +	llc_pdu_init_as_ui_cmd(skb); +	rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac); +	if (!rc) +		rc = dev_queue_xmit(skb); +	return rc; +} + +/** + *	llc_sap_action_send_xid_c - send XID PDU as response to XID REQ + *	@sap: SAP + *	@skb: the event to send + * + *	Send a XID command PDU to MAC layer in response to a XID REQUEST + *	primitive from the network layer. Verify event is a primitive type + *	event. Verify the primitive is a XID REQUEST. + */ +int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	int rc; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap, +			    ev->daddr.lsap, LLC_PDU_CMD); +	llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0); +	rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac); +	if (!rc) +		rc = dev_queue_xmit(skb); +	return rc; +} + +/** + *	llc_sap_action_send_xid_r - send XID PDU resp to MAC for received XID + *	@sap: SAP + *	@skb: the event to send + * + *	Send XID response PDU to MAC in response to an earlier received XID + *	command PDU. Verify event is a PDU type event + */ +int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb) +{ +	u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap; +	int rc = 1; +	struct sk_buff *nskb; + +	llc_pdu_decode_sa(skb, mac_da); +	llc_pdu_decode_da(skb, mac_sa); +	llc_pdu_decode_ssap(skb, &dsap); +	nskb = llc_alloc_frame(); +	if (!nskb) +		goto out; +	nskb->dev = skb->dev; +	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, +			    LLC_PDU_RSP); +	llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0); +	rc = llc_mac_hdr_init(nskb, mac_sa, mac_da); +	if (!rc) +		rc = dev_queue_xmit(nskb); +out: +	return rc; +} + +/** + *	llc_sap_action_send_test_c - send TEST PDU to MAC in resp to TEST REQ + *	@sap: SAP + *	@skb: the event to send + * + *	Send a TEST command PDU to the MAC layer in response to a TEST REQUEST + *	primitive from the network layer. Verify event is a primitive type + *	event; verify the primitive is a TEST REQUEST. + */ +int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	int rc; + +	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap, +			    ev->daddr.lsap, LLC_PDU_CMD); +	llc_pdu_init_as_test_cmd(skb); +	rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac); +	if (!rc) +		rc = dev_queue_xmit(skb); +	return rc; +} + +int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb) +{ +	u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap; +	struct sk_buff *nskb; +	int rc = 1; + +	llc_pdu_decode_sa(skb, mac_da); +	llc_pdu_decode_da(skb, mac_sa); +	llc_pdu_decode_ssap(skb, &dsap); +	nskb = llc_alloc_frame(); +	if (!nskb) +		goto out; +	nskb->dev = skb->dev; +	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, +			    LLC_PDU_RSP); +	llc_pdu_init_as_test_rsp(nskb, skb); +	rc = llc_mac_hdr_init(nskb, mac_sa, mac_da); +	if (!rc) +		rc = dev_queue_xmit(nskb); +out: +	return rc; +} + +/** + *	llc_sap_action_report_status - report data link status to layer mgmt + *	@sap: SAP + *	@skb: the event to send + * + *	Report data link status to layer management. Verify our event is the + *	kind we expect. + */ +int llc_sap_action_report_status(struct llc_sap *sap, struct sk_buff *skb) +{ +	return 0; +} + +/** + *	llc_sap_action_xid_ind - send XID PDU resp to net layer via XID IND + *	@sap: SAP + *	@skb: the event to send + * + *	Send a XID response PDU to the network layer via a XID INDICATION + *	primitive. + */ +int llc_sap_action_xid_ind(struct llc_sap *sap, struct sk_buff *skb) +{ +	llc_sap_rtn_pdu(sap, skb); +	return 0; +} + +/** + *	llc_sap_action_test_ind - send TEST PDU to net layer via TEST IND + *	@sap: SAP + *	@skb: the event to send + * + *	Send a TEST response PDU to the network layer via a TEST INDICATION + *	primitive. Verify our event is a PDU type event. + */ +int llc_sap_action_test_ind(struct llc_sap *sap, struct sk_buff *skb) +{ +	llc_sap_rtn_pdu(sap, skb); +	return 0; +} diff --git a/net/llc/llc_s_ev.c b/net/llc/llc_s_ev.c new file mode 100644 index 000000000000..a74d2a1d6581 --- /dev/null +++ b/net/llc/llc_s_ev.c @@ -0,0 +1,115 @@ +/* + * llc_s_ev.c - Defines SAP component events + * + * The followed event functions are SAP component events which are described + * in 802.2 LLC protocol standard document. + * + * Copyright (c) 1997 by Procom Technology, Inc. + *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/socket.h> +#include <net/sock.h> +#include <net/llc_if.h> +#include <net/llc_s_ev.h> +#include <net/llc_pdu.h> + +int llc_sap_ev_activation_req(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	return ev->type == LLC_SAP_EV_TYPE_SIMPLE && +	       ev->prim_type == LLC_SAP_EV_ACTIVATION_REQ ? 0 : 1; +} + +int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && +	       LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_UI ? 0 : 1; +} + +int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PRIM && +	       ev->prim == LLC_DATAUNIT_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; + +} + +int llc_sap_ev_xid_req(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PRIM && +	       ev->prim == LLC_XID_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && +	       LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; +} + +int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_RSP(pdu) && +	       LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; +} + +int llc_sap_ev_test_req(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PRIM && +	       ev->prim == LLC_TEST_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && +	       LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; +} + +int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_RSP(pdu) && +	       LLC_PDU_TYPE_IS_U(pdu) && +	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; +} + +int llc_sap_ev_deactivation_req(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	return ev->type == LLC_SAP_EV_TYPE_SIMPLE && +	       ev->prim_type == LLC_SAP_EV_DEACTIVATION_REQ ? 0 : 1; +} diff --git a/net/llc/llc_s_st.c b/net/llc/llc_s_st.c new file mode 100644 index 000000000000..6a43201aa32e --- /dev/null +++ b/net/llc/llc_s_st.c @@ -0,0 +1,183 @@ +/* + * llc_s_st.c - Defines SAP component state machine transitions. + * + * The followed transitions are SAP component state machine transitions + * which are described in 802.2 LLC protocol standard document. + * + * Copyright (c) 1997 by Procom Technology, Inc. + *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/types.h> +#include <net/llc_if.h> +#include <net/llc_s_ev.h> +#include <net/llc_s_ac.h> +#include <net/llc_s_st.h> + +/* dummy last-transition indicator; common to all state transition groups + * last entry for this state + * all members are zeros, .bss zeroes it + */ +static struct llc_sap_state_trans llc_sap_state_trans_end; + +/* state LLC_SAP_STATE_INACTIVE transition for + * LLC_SAP_EV_ACTIVATION_REQ event + */ +static llc_sap_action_t llc_sap_inactive_state_actions_1[] = { +	[0] = llc_sap_action_report_status, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_inactive_state_trans_1 = { +	.ev =		llc_sap_ev_activation_req, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_inactive_state_actions_1, +}; + +/* array of pointers; one to each transition */ +static struct llc_sap_state_trans *llc_sap_inactive_state_transitions[] = { +	[0] = &llc_sap_inactive_state_trans_1, +	[1] = &llc_sap_state_trans_end, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_UI event */ +static llc_sap_action_t llc_sap_active_state_actions_1[] = { +	[0] = llc_sap_action_unitdata_ind, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_1 = { +	.ev =		llc_sap_ev_rx_ui, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_1, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_UNITDATA_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_2[] = { +	[0] = llc_sap_action_send_ui, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_2 = { +	.ev =		llc_sap_ev_unitdata_req, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_2, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_XID_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_3[] = { +	[0] = llc_sap_action_send_xid_c, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_3 = { +	.ev =		llc_sap_ev_xid_req, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_3, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_XID_C event */ +static llc_sap_action_t llc_sap_active_state_actions_4[] = { +	[0] = llc_sap_action_send_xid_r, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_4 = { +	.ev =		llc_sap_ev_rx_xid_c, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_4, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_XID_R event */ +static llc_sap_action_t llc_sap_active_state_actions_5[] = { +	[0] = llc_sap_action_xid_ind, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_5 = { +	.ev =		llc_sap_ev_rx_xid_r, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_5, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_TEST_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_6[] = { +	[0] = llc_sap_action_send_test_c, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_6 = { +	.ev =		llc_sap_ev_test_req, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_6, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_TEST_C event */ +static llc_sap_action_t llc_sap_active_state_actions_7[] = { +	[0] = llc_sap_action_send_test_r, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_7 = { +	.ev =		llc_sap_ev_rx_test_c, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_7 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_TEST_R event */ +static llc_sap_action_t llc_sap_active_state_actions_8[] = { +	[0] = llc_sap_action_test_ind, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_8 = { +	.ev =		llc_sap_ev_rx_test_r, +	.next_state =	LLC_SAP_STATE_ACTIVE, +	.ev_actions =	llc_sap_active_state_actions_8, +}; + +/* state LLC_SAP_STATE_ACTIVE transition for + * LLC_SAP_EV_DEACTIVATION_REQ event + */ +static llc_sap_action_t llc_sap_active_state_actions_9[] = { +	[0] = llc_sap_action_report_status, +	[1] = NULL, +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_9 = { +	.ev =		llc_sap_ev_deactivation_req, +	.next_state =	LLC_SAP_STATE_INACTIVE, +	.ev_actions =	llc_sap_active_state_actions_9 +}; + +/* array of pointers; one to each transition */ +static struct llc_sap_state_trans *llc_sap_active_state_transitions[] = { +	[0] = &llc_sap_active_state_trans_2, +	[1] = &llc_sap_active_state_trans_1, +	[2] = &llc_sap_active_state_trans_3, +	[3] = &llc_sap_active_state_trans_4, +	[4] = &llc_sap_active_state_trans_5, +	[5] = &llc_sap_active_state_trans_6, +	[6] = &llc_sap_active_state_trans_7, +	[7] = &llc_sap_active_state_trans_8, +	[8] = &llc_sap_active_state_trans_9, +	[9] = &llc_sap_state_trans_end, +}; + +/* SAP state transition table */ +struct llc_sap_state llc_sap_state_table[LLC_NR_SAP_STATES] = { +	[LLC_SAP_STATE_INACTIVE - 1] = { +		.curr_state	= LLC_SAP_STATE_INACTIVE, +		.transitions	= llc_sap_inactive_state_transitions, +       	}, +	[LLC_SAP_STATE_ACTIVE - 1] = { +		.curr_state	= LLC_SAP_STATE_ACTIVE, +		.transitions	= llc_sap_active_state_transitions, +	}, +}; diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c new file mode 100644 index 000000000000..965c94eb4bbc --- /dev/null +++ b/net/llc/llc_sap.c @@ -0,0 +1,316 @@ +/* + * llc_sap.c - driver routines for SAP component. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <net/llc.h> +#include <net/llc_if.h> +#include <net/llc_conn.h> +#include <net/llc_pdu.h> +#include <net/llc_sap.h> +#include <net/llc_s_ac.h> +#include <net/llc_s_ev.h> +#include <net/llc_s_st.h> +#include <net/sock.h> +#include <linux/tcp.h> +#include <linux/llc.h> + +/** + *	llc_alloc_frame - allocates sk_buff for frame + * + *	Allocates an sk_buff for frame and initializes sk_buff fields. + *	Returns allocated skb or %NULL when out of memory. + */ +struct sk_buff *llc_alloc_frame(void) +{ +	struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC); + +	if (skb) { +		skb_reserve(skb, 50); +		skb->nh.raw   = skb->h.raw = skb->data; +		skb->protocol = htons(ETH_P_802_2); +		skb->dev      = dev_base->next; +		skb->mac.raw  = skb->head; +	} +	return skb; +} + +void llc_save_primitive(struct sk_buff* skb, u8 prim) +{ +	struct sockaddr_llc *addr = llc_ui_skb_cb(skb); + +       /* save primitive for use by the user. */ +	addr->sllc_family = skb->sk->sk_family; +	addr->sllc_arphrd = skb->dev->type; +	addr->sllc_test   = prim == LLC_TEST_PRIM; +	addr->sllc_xid    = prim == LLC_XID_PRIM; +	addr->sllc_ua     = prim == LLC_DATAUNIT_PRIM; +	llc_pdu_decode_sa(skb, addr->sllc_mac); +	llc_pdu_decode_ssap(skb, &addr->sllc_sap); +} + +/** + *	llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu. + *	@sap: pointer to SAP + *	@skb: received pdu + */ +void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	switch (LLC_U_PDU_RSP(pdu)) { +	case LLC_1_PDU_CMD_TEST: +		ev->prim = LLC_TEST_PRIM;	break; +	case LLC_1_PDU_CMD_XID: +		ev->prim = LLC_XID_PRIM;	break; +	case LLC_1_PDU_CMD_UI: +		ev->prim = LLC_DATAUNIT_PRIM;	break; +	} +	ev->ind_cfm_flag = LLC_IND; +} + +/** + *	llc_find_sap_trans - finds transition for event + *	@sap: pointer to SAP + *	@skb: happened event + * + *	This function finds transition that matches with happened event. + *	Returns the pointer to found transition on success or %NULL for + *	failure. + */ +static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, +						      struct sk_buff* skb) +{ +	int i = 0; +	struct llc_sap_state_trans *rc = NULL; +	struct llc_sap_state_trans **next_trans; +	struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1]; +	/* +	 * Search thru events for this state until list exhausted or until +	 * its obvious the event is not valid for the current state +	 */ +	for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) +		if (!next_trans[i]->ev(sap, skb)) { +			rc = next_trans[i]; /* got event match; return it */ +			break; +		} +	return rc; +} + +/** + *	llc_exec_sap_trans_actions - execute actions related to event + *	@sap: pointer to SAP + *	@trans: pointer to transition that it's actions must be performed + *	@skb: happened event. + * + *	This function executes actions that is related to happened event. + *	Returns 0 for success and 1 for failure of at least one action. + */ +static int llc_exec_sap_trans_actions(struct llc_sap *sap, +				      struct llc_sap_state_trans *trans, +				      struct sk_buff *skb) +{ +	int rc = 0; +	llc_sap_action_t *next_action = trans->ev_actions; + +	for (; next_action && *next_action; next_action++) +		if ((*next_action)(sap, skb)) +			rc = 1; +	return rc; +} + +/** + *	llc_sap_next_state - finds transition, execs actions & change SAP state + *	@sap: pointer to SAP + *	@skb: happened event + * + *	This function finds transition that matches with happened event, then + *	executes related actions and finally changes state of SAP. It returns + *	0 on success and 1 for failure. + */ +static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb) +{ +	int rc = 1; +	struct llc_sap_state_trans *trans; + +	if (sap->state > LLC_NR_SAP_STATES) +		goto out; +	trans = llc_find_sap_trans(sap, skb); +	if (!trans) +		goto out; +	/* +	 * Got the state to which we next transition; perform the actions +	 * associated with this transition before actually transitioning to the +	 * next state +	 */ +	rc = llc_exec_sap_trans_actions(sap, trans, skb); +	if (rc) +		goto out; +	/* +	 * Transition SAP to next state if all actions execute successfully +	 */ +	sap->state = trans->next_state; +out: +	return rc; +} + +/** + *	llc_sap_state_process - sends event to SAP state machine + *	@sap: sap to use + *	@skb: pointer to occurred event + * + *	After executing actions of the event, upper layer will be indicated + *	if needed(on receiving an UI frame). sk can be null for the + *	datalink_proto case. + */ +static void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	/* +	 * We have to hold the skb, because llc_sap_next_state +	 * will kfree it in the sending path and we need to +	 * look at the skb->cb, where we encode llc_sap_state_ev. +	 */ +	skb_get(skb); +	ev->ind_cfm_flag = 0; +	llc_sap_next_state(sap, skb); +	if (ev->ind_cfm_flag == LLC_IND) { +		if (skb->sk->sk_state == TCP_LISTEN) +			kfree_skb(skb); +		else { +			llc_save_primitive(skb, ev->prim); + +			/* queue skb to the user. */ +			if (sock_queue_rcv_skb(skb->sk, skb)) +				kfree_skb(skb); +		} +	}  +	kfree_skb(skb); +} + +/** + *	llc_build_and_send_test_pkt - TEST interface for upper layers. + *	@sap: sap to use + *	@skb: packet to send + *	@dmac: destination mac address + *	@dsap: destination sap + * + *	This function is called when upper layer wants to send a TEST pdu. + *	Returns 0 for success, 1 otherwise. + */ +void llc_build_and_send_test_pkt(struct llc_sap *sap,  +				 struct sk_buff *skb, u8 *dmac, u8 dsap) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	ev->saddr.lsap = sap->laddr.lsap; +	ev->daddr.lsap = dsap; +	memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); +	memcpy(ev->daddr.mac, dmac, IFHWADDRLEN); +	 +	ev->type      = LLC_SAP_EV_TYPE_PRIM; +	ev->prim      = LLC_TEST_PRIM; +	ev->prim_type = LLC_PRIM_TYPE_REQ; +	llc_sap_state_process(sap, skb); +} + +/** + *	llc_build_and_send_xid_pkt - XID interface for upper layers + *	@sap: sap to use + *	@skb: packet to send + *	@dmac: destination mac address + *	@dsap: destination sap + * + *	This function is called when upper layer wants to send a XID pdu. + *	Returns 0 for success, 1 otherwise. + */ +void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb, +				u8 *dmac, u8 dsap) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	ev->saddr.lsap = sap->laddr.lsap; +	ev->daddr.lsap = dsap; +	memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); +	memcpy(ev->daddr.mac, dmac, IFHWADDRLEN); + +	ev->type      = LLC_SAP_EV_TYPE_PRIM; +	ev->prim      = LLC_XID_PRIM; +	ev->prim_type = LLC_PRIM_TYPE_REQ; +	llc_sap_state_process(sap, skb); +} + +/** + *	llc_sap_rcv - sends received pdus to the sap state machine + *	@sap: current sap component structure. + *	@skb: received frame. + * + *	Sends received pdus to the sap state machine. + */ +static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_sap_state_ev *ev = llc_sap_ev(skb); + +	ev->type   = LLC_SAP_EV_TYPE_PDU; +	ev->reason = 0; +	llc_sap_state_process(sap, skb); +} + +/** + *	llc_lookup_dgram - Finds dgram socket for the local sap/mac + *	@sap: SAP + *	@laddr: address of local LLC (MAC + SAP) + * + *	Search socket list of the SAP and finds connection using the local + *	mac, and local sap. Returns pointer for socket found, %NULL otherwise. + */ +static struct sock *llc_lookup_dgram(struct llc_sap *sap, +				     struct llc_addr *laddr) +{ +	struct sock *rc; +	struct hlist_node *node; + +	read_lock_bh(&sap->sk_list.lock); +	sk_for_each(rc, node, &sap->sk_list.list) { +		struct llc_sock *llc = llc_sk(rc); + +		if (rc->sk_type == SOCK_DGRAM && +		    llc->laddr.lsap == laddr->lsap && +		    llc_mac_match(llc->laddr.mac, laddr->mac)) { +			sock_hold(rc); +			goto found; +		} +	} +	rc = NULL; +found: +	read_unlock_bh(&sap->sk_list.lock); +	return rc; +} + +void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb) +{ +	struct llc_addr laddr; +	struct sock *sk; + +	llc_pdu_decode_da(skb, laddr.mac); +	llc_pdu_decode_dsap(skb, &laddr.lsap); + +	sk = llc_lookup_dgram(sap, &laddr); +	if (sk) { +		skb->sk = sk; +		llc_sap_rcv(sap, skb); +		sock_put(sk); +	} else +		kfree_skb(skb); +} diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c new file mode 100644 index 000000000000..8fe48a24bad5 --- /dev/null +++ b/net/llc/llc_station.c @@ -0,0 +1,713 @@ +/* + * llc_station.c - station component of LLC + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/module.h> +#include <net/llc.h> +#include <net/llc_sap.h> +#include <net/llc_conn.h> +#include <net/llc_c_ac.h> +#include <net/llc_s_ac.h> +#include <net/llc_c_ev.h> +#include <net/llc_c_st.h> +#include <net/llc_s_ev.h> +#include <net/llc_s_st.h> +#include <net/llc_pdu.h> + +/** + * struct llc_station - LLC station component + * + * SAP and connection resource manager, one per adapter. + * + * @state - state of station + * @xid_r_count - XID response PDU counter + * @mac_sa - MAC source address + * @sap_list - list of related SAPs + * @ev_q - events entering state mach. + * @mac_pdu_q - PDUs ready to send to MAC + */ +struct llc_station { +	u8			    state; +	u8			    xid_r_count; +	struct timer_list	    ack_timer; +	u8			    retry_count; +	u8			    maximum_retry; +	struct { +		struct sk_buff_head list; +		spinlock_t	    lock; +	} ev_q; +	struct sk_buff_head	    mac_pdu_q; +}; + +/* Types of events (possible values in 'ev->type') */ +#define LLC_STATION_EV_TYPE_SIMPLE	1 +#define LLC_STATION_EV_TYPE_CONDITION	2 +#define LLC_STATION_EV_TYPE_PRIM	3 +#define LLC_STATION_EV_TYPE_PDU		4       /* command/response PDU */ +#define LLC_STATION_EV_TYPE_ACK_TMR	5 +#define LLC_STATION_EV_TYPE_RPT_STATUS	6 + +/* Events */ +#define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK		1 +#define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK		2 +#define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY	3 +#define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY	4 +#define LLC_STATION_EV_RX_NULL_DSAP_XID_C			5 +#define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ	6 +#define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ	7 +#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C			8 +#define LLC_STATION_EV_DISABLE_REQ				9 + +struct llc_station_state_ev { +	u8		 type; +	u8		 prim; +	u8		 prim_type; +	u8		 reason; +	struct list_head node; /* node in station->ev_q.list */ +}; + +static __inline__ struct llc_station_state_ev * +					llc_station_ev(struct sk_buff *skb) +{ +	return (struct llc_station_state_ev *)skb->cb; +} + +typedef int (*llc_station_ev_t)(struct sk_buff *skb); + +#define LLC_STATION_STATE_DOWN		1	/* initial state */ +#define LLC_STATION_STATE_DUP_ADDR_CHK	2 +#define LLC_STATION_STATE_UP		3 + +#define LLC_NBR_STATION_STATES		3	/* size of state table */ + +typedef int (*llc_station_action_t)(struct sk_buff *skb); + +/* Station component state table structure */ +struct llc_station_state_trans { +	llc_station_ev_t ev; +	u8 next_state; +	llc_station_action_t *ev_actions; +}; + +struct llc_station_state { +	u8 curr_state; +	struct llc_station_state_trans **transitions; +}; + +static struct llc_station llc_main_station; + +static int llc_stat_ev_enable_with_dup_addr_check(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb);	 +	 +	return ev->type == LLC_STATION_EV_TYPE_SIMPLE && +	       ev->prim_type == +	       		      LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1; +} + +static int llc_stat_ev_enable_without_dup_addr_check(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb);	 +	 +	return ev->type == LLC_STATION_EV_TYPE_SIMPLE && +	       ev->prim_type == +			LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1; +} + +static int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb);	 +	 +	return ev->type == LLC_STATION_EV_TYPE_ACK_TMR && +		llc_main_station.retry_count < +		llc_main_station.maximum_retry ? 0 : 1; +} + +static int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb);	 +	 +	return ev->type == LLC_STATION_EV_TYPE_ACK_TMR && +		llc_main_station.retry_count == +		llc_main_station.maximum_retry ? 0 : 1; +} + +static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb);	 +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_STATION_EV_TYPE_PDU && +	       LLC_PDU_IS_CMD(pdu) &&			/* command PDU */ +	       LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */ +	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && +	       !pdu->dsap ? 0 : 1;			/* NULL DSAP value */ +} + +static int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_STATION_EV_TYPE_PDU && +	       LLC_PDU_IS_RSP(pdu) &&			/* response PDU */ +	       LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */ +	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && +	       !pdu->dsap &&				/* NULL DSAP value */ +	       !llc_main_station.xid_r_count ? 0 : 1; +} + +static int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_STATION_EV_TYPE_PDU && +	       LLC_PDU_IS_RSP(pdu) &&			/* response PDU */ +	       LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */ +	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && +	       !pdu->dsap &&				/* NULL DSAP value */ +	       llc_main_station.xid_r_count == 1 ? 0 : 1; +} + +static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb); +	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + +	return ev->type == LLC_STATION_EV_TYPE_PDU && +	       LLC_PDU_IS_CMD(pdu) &&			/* command PDU */ +	       LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */ +	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && +	       !pdu->dsap ? 0 : 1;			/* NULL DSAP */ +} + +static int llc_stat_ev_disable_req(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb); + +	return ev->type == LLC_STATION_EV_TYPE_PRIM && +	       ev->prim == LLC_DISABLE_PRIM && +	       ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +/** + *	llc_station_send_pdu - queues PDU to send + *	@skb: Address of the PDU + * + *	Queues a PDU to send to the MAC layer. + */ +static void llc_station_send_pdu(struct sk_buff *skb) +{ +	skb_queue_tail(&llc_main_station.mac_pdu_q, skb); +	while ((skb = skb_dequeue(&llc_main_station.mac_pdu_q)) != NULL) +		if (dev_queue_xmit(skb)) +			break; +} + +static int llc_station_ac_start_ack_timer(struct sk_buff *skb) +{ +	mod_timer(&llc_main_station.ack_timer, jiffies + LLC_ACK_TIME * HZ); +	return 0; +} + +static int llc_station_ac_set_retry_cnt_0(struct sk_buff *skb) +{ +	llc_main_station.retry_count = 0; +	return 0; +} + +static int llc_station_ac_inc_retry_cnt_by_1(struct sk_buff *skb) +{ +	llc_main_station.retry_count++; +	return 0; +} + +static int llc_station_ac_set_xid_r_cnt_0(struct sk_buff *skb) +{ +	llc_main_station.xid_r_count = 0; +	return 0; +} + +static int llc_station_ac_inc_xid_r_cnt_by_1(struct sk_buff *skb) +{ +	llc_main_station.xid_r_count++; +	return 0; +} + +static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb) +{ +	int rc = 1; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (!nskb) +		goto out; +	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD); +	llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127); +	rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, llc_station_mac_sa); +	if (rc) +		goto free; +	llc_station_send_pdu(nskb); +out: +	return rc; +free: +	kfree_skb(skb); +	goto out; +} + +static int llc_station_ac_send_xid_r(struct sk_buff *skb) +{ +	u8 mac_da[ETH_ALEN], dsap; +	int rc = 1; +	struct sk_buff* nskb = llc_alloc_frame(); + +	if (!nskb) +		goto out; +	rc = 0; +	nskb->dev = skb->dev; +	llc_pdu_decode_sa(skb, mac_da); +	llc_pdu_decode_ssap(skb, &dsap); +	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); +	llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127); +	rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da); +	if (rc) +		goto free; +	llc_station_send_pdu(nskb); +out: +	return rc; +free: +	kfree_skb(skb); +	goto out; +} + +static int llc_station_ac_send_test_r(struct sk_buff *skb) +{ +	u8 mac_da[ETH_ALEN], dsap; +	int rc = 1; +	struct sk_buff *nskb = llc_alloc_frame(); + +	if (!nskb) +		goto out; +	rc = 0; +	nskb->dev = skb->dev; +	llc_pdu_decode_sa(skb, mac_da); +	llc_pdu_decode_ssap(skb, &dsap); +	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); +       	llc_pdu_init_as_test_rsp(nskb, skb); +	rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da); +	if (rc) +		goto free; +	llc_station_send_pdu(nskb); +out: +	return rc; +free: +	kfree_skb(skb); +	goto out; +} + +static int llc_station_ac_report_status(struct sk_buff *skb) +{ +	return 0; +} + +/* COMMON STATION STATE transitions */ + +/* dummy last-transition indicator; common to all state transition groups + * last entry for this state + * all members are zeros, .bss zeroes it + */ +static struct llc_station_state_trans llc_stat_state_trans_end; + +/* DOWN STATE transitions */ + +/* state transition for LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK event */ +static llc_station_action_t llc_stat_down_state_actions_1[] = { +	[0] = llc_station_ac_start_ack_timer, +	[1] = llc_station_ac_set_retry_cnt_0, +	[2] = llc_station_ac_set_xid_r_cnt_0, +	[3] = llc_station_ac_send_null_dsap_xid_c, +	[4] = NULL, +}; + +static struct llc_station_state_trans llc_stat_down_state_trans_1 = { +	.ev	    = llc_stat_ev_enable_with_dup_addr_check, +	.next_state = LLC_STATION_STATE_DUP_ADDR_CHK, +	.ev_actions = llc_stat_down_state_actions_1, +}; + +/* state transition for LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK event */ +static llc_station_action_t llc_stat_down_state_actions_2[] = { +	[0] = llc_station_ac_report_status,	/* STATION UP */ +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_down_state_trans_2 = { +	.ev	    = llc_stat_ev_enable_without_dup_addr_check, +	.next_state = LLC_STATION_STATE_UP, +	.ev_actions = llc_stat_down_state_actions_2, +}; + +/* array of pointers; one to each transition */ +static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = { +	[0] = &llc_stat_down_state_trans_1, +	[1] = &llc_stat_down_state_trans_2, +	[2] = &llc_stat_state_trans_end, +}; + +/* UP STATE transitions */ +/* state transition for LLC_STATION_EV_DISABLE_REQ event */ +static llc_station_action_t llc_stat_up_state_actions_1[] = { +	[0] = llc_station_ac_report_status,	/* STATION DOWN */ +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_up_state_trans_1 = { +	.ev	    = llc_stat_ev_disable_req, +	.next_state = LLC_STATION_STATE_DOWN, +	.ev_actions = llc_stat_up_state_actions_1, +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */ +static llc_station_action_t llc_stat_up_state_actions_2[] = { +	[0] = llc_station_ac_send_xid_r, +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_up_state_trans_2 = { +	.ev	    = llc_stat_ev_rx_null_dsap_xid_c, +	.next_state = LLC_STATION_STATE_UP, +	.ev_actions = llc_stat_up_state_actions_2, +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */ +static llc_station_action_t llc_stat_up_state_actions_3[] = { +	[0] = llc_station_ac_send_test_r, +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_up_state_trans_3 = { +	.ev	    = llc_stat_ev_rx_null_dsap_test_c, +	.next_state = LLC_STATION_STATE_UP, +	.ev_actions = llc_stat_up_state_actions_3, +}; + +/* array of pointers; one to each transition */ +static struct llc_station_state_trans *llc_stat_up_state_trans [] = { +	[0] = &llc_stat_up_state_trans_1, +	[1] = &llc_stat_up_state_trans_2, +	[2] = &llc_stat_up_state_trans_3, +	[3] = &llc_stat_state_trans_end, +}; + +/* DUP ADDR CHK STATE transitions */ +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ + * event + */ +static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = { +	[0] = llc_station_ac_inc_xid_r_cnt_by_1, +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = { +	.ev	    = llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq, +	.next_state = LLC_STATION_STATE_DUP_ADDR_CHK, +	.ev_actions = llc_stat_dupaddr_state_actions_1, +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ + * event + */ +static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = { +	[0] = llc_station_ac_report_status,	/* DUPLICATE ADDRESS FOUND */ +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = { +	.ev	    = llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq, +	.next_state = LLC_STATION_STATE_DOWN, +	.ev_actions = llc_stat_dupaddr_state_actions_2, +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = { +	[0] = llc_station_ac_send_xid_r, +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = { +	.ev	    = llc_stat_ev_rx_null_dsap_xid_c, +	.next_state = LLC_STATION_STATE_DUP_ADDR_CHK, +	.ev_actions = llc_stat_dupaddr_state_actions_3, +}; + +/* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY + * event + */ +static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = { +	[0] = llc_station_ac_start_ack_timer, +	[1] = llc_station_ac_inc_retry_cnt_by_1, +	[2] = llc_station_ac_set_xid_r_cnt_0, +	[3] = llc_station_ac_send_null_dsap_xid_c, +	[4] = NULL, +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = { +	.ev	    = llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry, +	.next_state = LLC_STATION_STATE_DUP_ADDR_CHK, +	.ev_actions = llc_stat_dupaddr_state_actions_4, +}; + +/* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY + * event + */ +static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = { +	[0] = llc_station_ac_report_status,	/* STATION UP */ +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = { +	.ev	    = llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry, +	.next_state = LLC_STATION_STATE_UP, +	.ev_actions = llc_stat_dupaddr_state_actions_5, +}; + +/* state transition for LLC_STATION_EV_DISABLE_REQ event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = { +	[0] = llc_station_ac_report_status,	/* STATION DOWN */ +	[1] = NULL, +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = { +	.ev	    = llc_stat_ev_disable_req, +	.next_state = LLC_STATION_STATE_DOWN, +	.ev_actions = llc_stat_dupaddr_state_actions_6, +}; + +/* array of pointers; one to each transition */ +static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = { +	[0] = &llc_stat_dupaddr_state_trans_6,	/* Request */ +	[1] = &llc_stat_dupaddr_state_trans_4,	/* Timer */ +	[2] = &llc_stat_dupaddr_state_trans_5, +	[3] = &llc_stat_dupaddr_state_trans_1,	/* Receive frame */ +	[4] = &llc_stat_dupaddr_state_trans_2, +	[5] = &llc_stat_dupaddr_state_trans_3, +	[6] = &llc_stat_state_trans_end, +}; + +static struct llc_station_state +			llc_station_state_table[LLC_NBR_STATION_STATES] = { +	[LLC_STATION_STATE_DOWN - 1] = { +		.curr_state  = LLC_STATION_STATE_DOWN, +		.transitions = llc_stat_dwn_state_trans, +	}, +	[LLC_STATION_STATE_DUP_ADDR_CHK - 1] = { +		.curr_state  = LLC_STATION_STATE_DUP_ADDR_CHK, +		.transitions = llc_stat_dupaddr_state_trans, +	}, +	[LLC_STATION_STATE_UP - 1] = { +		.curr_state  = LLC_STATION_STATE_UP, +		.transitions = llc_stat_up_state_trans, +	}, +}; + +/** + *	llc_exec_station_trans_actions - executes actions for transition + *	@trans: Address of the transition + *	@skb: Address of the event that caused the transition + * + *	Executes actions of a transition of the station state machine. Returns + *	0 if all actions complete successfully, nonzero otherwise. + */ +static u16 llc_exec_station_trans_actions(struct llc_station_state_trans *trans, +					  struct sk_buff *skb) +{ +	u16 rc = 0; +	llc_station_action_t *next_action = trans->ev_actions; + +	for (; next_action && *next_action; next_action++) +		if ((*next_action)(skb)) +			rc = 1; +	return rc; +} + +/** + *	llc_find_station_trans - finds transition for this event + *	@skb: Address of the event + * + *	Search thru events of the current state of the station until list + *	exhausted or it's obvious that the event is not valid for the current + *	state. Returns the address of the transition if cound, %NULL otherwise. + */ +static struct llc_station_state_trans * +				llc_find_station_trans(struct sk_buff *skb) +{ +	int i = 0; +	struct llc_station_state_trans *rc = NULL; +	struct llc_station_state_trans **next_trans; +	struct llc_station_state *curr_state = +				&llc_station_state_table[llc_main_station.state - 1]; + +	for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) +		if (!next_trans[i]->ev(skb)) { +			rc = next_trans[i]; +			break; +		} +	return rc; +} + +/** + *	llc_station_free_ev - frees an event + *	@skb: Address of the event + * + *	Frees an event. + */ +static void llc_station_free_ev(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb); + +	if (ev->type == LLC_STATION_EV_TYPE_PDU) +		kfree_skb(skb); +} + +/** + *	llc_station_next_state - processes event and goes to the next state + *	@skb: Address of the event + * + *	Processes an event, executes any transitions related to that event and + *	updates the state of the station. + */ +static u16 llc_station_next_state(struct sk_buff *skb) +{ +	u16 rc = 1; +	struct llc_station_state_trans *trans; + +	if (llc_main_station.state > LLC_NBR_STATION_STATES) +		goto out; +	trans = llc_find_station_trans(skb); +	if (trans) { +		/* got the state to which we next transition; perform the +		 * actions associated with this transition before actually +		 * transitioning to the next state +		 */ +		rc = llc_exec_station_trans_actions(trans, skb); +		if (!rc) +			/* transition station to next state if all actions +			 * execute successfully; done; wait for next event +			 */ +			llc_main_station.state = trans->next_state; +	} else +		/* event not recognized in current state; re-queue it for +		 * processing again at a later time; return failure +		 */ +		rc = 0; +out: +	llc_station_free_ev(skb); +	return rc; +} + +/** + *	llc_station_service_events - service events in the queue + * + *	Get an event from the station event queue (if any); attempt to service + *	the event; if event serviced, get the next event (if any) on the event + *	queue; if event not service, re-queue the event on the event queue and + *	attempt to service the next event; when serviced all events in queue, + *	finished; if don't transition to different state, just service all + *	events once; if transition to new state, service all events again. + *	Caller must hold llc_main_station.ev_q.lock. + */ +static void llc_station_service_events(void) +{ +	struct sk_buff *skb; + +	while ((skb = skb_dequeue(&llc_main_station.ev_q.list)) != NULL) +		llc_station_next_state(skb); +} + +/** + *	llc_station_state_process: queue event and try to process queue. + *	@skb: Address of the event + * + *	Queues an event (on the station event queue) for handling by the + *	station state machine and attempts to process any queued-up events. + */ +static void llc_station_state_process(struct sk_buff *skb) +{ +	spin_lock_bh(&llc_main_station.ev_q.lock); +	skb_queue_tail(&llc_main_station.ev_q.list, skb); +	llc_station_service_events(); +	spin_unlock_bh(&llc_main_station.ev_q.lock); +} + +static void llc_station_ack_tmr_cb(unsigned long timeout_data) +{ +	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + +	if (skb) { +		struct llc_station_state_ev *ev = llc_station_ev(skb); + +		ev->type = LLC_STATION_EV_TYPE_ACK_TMR; +		llc_station_state_process(skb); +	} +} + +/* + *	llc_station_rcv - send received pdu to the station state machine + *	@skb: received frame. + * + *	Sends data unit to station state machine. + */ +static void llc_station_rcv(struct sk_buff *skb) +{ +	struct llc_station_state_ev *ev = llc_station_ev(skb); + +	ev->type   = LLC_STATION_EV_TYPE_PDU; +	ev->reason = 0; +	llc_station_state_process(skb); +} + +int __init llc_station_init(void) +{ +	u16 rc = -ENOBUFS; +	struct sk_buff *skb; +	struct llc_station_state_ev *ev; + +	skb_queue_head_init(&llc_main_station.mac_pdu_q); +	skb_queue_head_init(&llc_main_station.ev_q.list); +	spin_lock_init(&llc_main_station.ev_q.lock); +	init_timer(&llc_main_station.ack_timer); +	llc_main_station.ack_timer.data     = (unsigned long)&llc_main_station; +	llc_main_station.ack_timer.function = llc_station_ack_tmr_cb; + +	skb = alloc_skb(0, GFP_ATOMIC); +	if (!skb) +		goto out; +	rc = 0; +	llc_set_station_handler(llc_station_rcv); +	ev = llc_station_ev(skb); +	memset(ev, 0, sizeof(*ev)); +	llc_main_station.ack_timer.expires = jiffies + 3 * HZ; +	llc_main_station.maximum_retry	= 1; +	llc_main_station.state		= LLC_STATION_STATE_DOWN; +	ev->type	= LLC_STATION_EV_TYPE_SIMPLE; +	ev->prim_type	= LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK; +	rc = llc_station_next_state(skb); +out: +	return rc; +} + +void __exit llc_station_exit(void) +{ +	llc_set_station_handler(NULL); +} |