]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/llc-2.6
authorDavid S. Miller <davem@sunset.davemloft.net>
Mon, 26 Sep 2005 22:29:31 +0000 (15:29 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 26 Sep 2005 22:29:31 +0000 (15:29 -0700)
22 files changed:
include/linux/sysctl.h
include/net/llc.h
include/net/llc_conn.h
include/net/llc_sap.h
net/802/p8022.c
net/802/psnap.c
net/802/tr.c
net/core/dev.c
net/llc/Makefile
net/llc/af_llc.c
net/llc/llc_c_ac.c
net/llc/llc_c_ev.c
net/llc/llc_conn.c
net/llc/llc_core.c
net/llc/llc_if.c
net/llc/llc_input.c
net/llc/llc_output.c
net/llc/llc_proc.c
net/llc/llc_s_ac.c
net/llc/llc_sap.c
net/llc/llc_station.c
net/llc/sysctl_net_llc.c [new file with mode: 0644]

index 3a29a9f9b451d7f3b0e6135ff7d4fcc0fa886027..fc8e367f671e11bccc88faccb6247ce0017e5009 100644 (file)
@@ -202,7 +202,8 @@ enum
        NET_TR=14,
        NET_DECNET=15,
        NET_ECONET=16,
-       NET_SCTP=17, 
+       NET_SCTP=17,
+       NET_LLC=18,
 };
 
 /* /proc/sys/kernel/random */
@@ -522,6 +523,29 @@ enum {
        NET_IPX_FORWARDING=2
 };
 
+/* /proc/sys/net/llc */
+enum {
+       NET_LLC2=1,
+       NET_LLC_STATION=2,
+};
+
+/* /proc/sys/net/llc/llc2 */
+enum {
+       NET_LLC2_TIMEOUT=1,
+};
+
+/* /proc/sys/net/llc/station */
+enum {
+       NET_LLC_STATION_ACK_TIMEOUT=1,
+};
+
+/* /proc/sys/net/llc/llc2/timeout */
+enum {
+       NET_LLC2_ACK_TIMEOUT=1,
+       NET_LLC2_P_TIMEOUT=2,
+       NET_LLC2_REJ_TIMEOUT=3,
+       NET_LLC2_BUSY_TIMEOUT=4,
+};
 
 /* /proc/sys/net/appletalk */
 enum {
index 71769a5aeef3b929afd6b8dd0aa9fdab6f3c7f13..1adb2ef3f6f7b975cb1c59de626b70a17fa79f07 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+#include <asm/atomic.h>
+
 struct net_device;
 struct packet_type;
 struct sk_buff;
@@ -44,6 +46,7 @@ struct llc_sap {
        unsigned char    state;
        unsigned char    p_bit;
        unsigned char    f_bit;
+       atomic_t         refcnt;
        int              (*rcv_func)(struct sk_buff *skb,
                                     struct net_device *dev,
                                     struct packet_type *pt,
@@ -81,13 +84,27 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap,
                                               struct net_device *dev,
                                               struct packet_type *pt,
                                               struct net_device *orig_dev));
+static inline void llc_sap_hold(struct llc_sap *sap)
+{
+       atomic_inc(&sap->refcnt);
+}
+
 extern void llc_sap_close(struct llc_sap *sap);
 
+static inline void llc_sap_put(struct llc_sap *sap)
+{
+       if (atomic_dec_and_test(&sap->refcnt))
+               llc_sap_close(sap);
+}
+
 extern struct llc_sap *llc_sap_find(unsigned char sap_value);
 
 extern int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
                                     unsigned char *dmac, unsigned char dsap);
 
+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);
+
 extern int llc_station_init(void);
 extern void llc_station_exit(void);
 
@@ -98,4 +115,17 @@ extern void llc_proc_exit(void);
 #define llc_proc_init()        (0)
 #define llc_proc_exit()        do { } while(0)
 #endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_SYSCTL
+extern int llc_sysctl_init(void);
+extern void llc_sysctl_exit(void);
+
+extern int sysctl_llc2_ack_timeout;
+extern int sysctl_llc2_busy_timeout;
+extern int sysctl_llc2_p_timeout;
+extern int sysctl_llc2_rej_timeout;
+extern int sysctl_llc_station_ack_timeout;
+#else
+#define llc_sysctl_init() (0)
+#define llc_sysctl_exit() do { } while(0)
+#endif /* CONFIG_SYSCTL */
 #endif /* LLC_H */
index 8ad3bc2c23d78d16880623cb74cdc43f722f1263..54852ff6033bdf0c57cea25c0dc91ff3df468ed0 100644 (file)
 #define LLC_EVENT                1
 #define LLC_PACKET               2
 
-#define LLC_P_TIME               2
-#define LLC_ACK_TIME             1
-#define LLC_REJ_TIME             3
-#define LLC_BUSY_TIME            3
+#define LLC2_P_TIME               2
+#define LLC2_ACK_TIME             1
+#define LLC2_REJ_TIME             3
+#define LLC2_BUSY_TIME            3
 
 struct llc_timer {
        struct timer_list timer;
-       u16               expire;       /* timer expire time */
+       unsigned long     expire;       /* timer expire time */
 };
 
 struct llc_sock {
@@ -38,6 +38,7 @@ struct llc_sock {
        struct llc_addr     laddr;              /* lsap/mac pair */
        struct llc_addr     daddr;              /* dsap/mac pair */
        struct net_device   *dev;               /* device to send to remote */
+       u32                 copied_seq;         /* head of yet unread data */
        u8                  retry_count;        /* number of retries */
        u8                  ack_must_be_send;
        u8                  first_pdu_Ns;
@@ -92,7 +93,8 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb)
        return skb->cb[sizeof(skb->cb) - 1];
 }
 
-extern struct sock *llc_sk_alloc(int family, int priority, struct proto *prot);
+extern struct sock *llc_sk_alloc(int family, unsigned int __nocast priority,
+                                struct proto *prot);
 extern void llc_sk_free(struct sock *sk);
 
 extern void llc_sk_reset(struct sock *sk);
@@ -115,5 +117,4 @@ extern void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk);
 
 extern u8 llc_data_accept_state(u8 state);
 extern void llc_build_offset_table(void);
-extern int llc_release_sockets(struct llc_sap *sap);
 #endif /* LLC_CONN_H */
index 353baaa627f3b74f61c244c6a8d41102a7480b1c..2c56dbece7291ba1398dc5c5ce02ec3504e8f075 100644 (file)
  * See the GNU General Public License for more details.
  */
 struct llc_sap;
+struct net_device;
 struct sk_buff;
+struct sock;
 
 extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb);
-extern void llc_save_primitive(struct sk_buff* skb, unsigned char prim);
-extern struct sk_buff *llc_alloc_frame(void);
+extern void llc_save_primitive(struct sock *sk, struct sk_buff* skb,
+                              unsigned char prim);
+extern struct sk_buff *llc_alloc_frame(struct sock *sk,
+                                      struct net_device *dev);
 
 extern void llc_build_and_send_test_pkt(struct llc_sap *sap,
                                        struct sk_buff *skb,
index b24817c63ca8e31459a7b2c87b43bb2b05726ec8..2530f35241cde096a08a748790d74b75f8b22884 100644 (file)
@@ -56,7 +56,7 @@ struct datalink_proto *register_8022_client(unsigned char type,
 
 void unregister_8022_client(struct datalink_proto *proto)
 {
-       llc_sap_close(proto->sap);
+       llc_sap_put(proto->sap);
        kfree(proto);
 }
 
index ab80b1fab53c877eb312e35bea9b98f7bc3b233b..4d638944d933bf971c7750425474dfd3079360eb 100644 (file)
@@ -106,7 +106,7 @@ module_init(snap_init);
 
 static void __exit snap_exit(void)
 {
-       llc_sap_close(snap_sap);
+       llc_sap_put(snap_sap);
 }
 
 module_exit(snap_exit);
index 1bb7dc1b85cd448d4de0b47485dd54b9212b535d..1eaa3d19d8bf760b19b57d2a6b5556de677dd0cb 100644 (file)
@@ -238,7 +238,7 @@ unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev)
                return trllc->ethertype;
        }
 
-       return ntohs(ETH_P_802_2);
+       return ntohs(ETH_P_TR_802_2);
 }
 
 /*
index c01511e3d0c14a417f4ac025749405c061446e19..37c881070963aec33f184dac0341f7862877ca3b 100644 (file)
@@ -574,6 +574,8 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
        return dev;
 }
 
+EXPORT_SYMBOL(dev_getbyhwaddr);
+
 struct net_device *dev_getfirstbyhwtype(unsigned short type)
 {
        struct net_device *dev;
index 5ebd4ed2bd4295ef2e25d7425852887f4e972c4f..4e260cff3c5d89d3064120f4f3718e6feff1e44a 100644 (file)
@@ -22,3 +22,4 @@ 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
+llc2-$(CONFIG_SYSCTL)  += sysctl_net_llc.o
index 66f55e514b568d2682f0c859e0db1e90cd252cf2..59d02cbbeb9effd53158859aa522a7c73b581f5c 100644 (file)
@@ -21,6 +21,7 @@
  * See the GNU General Public License for more details.
  */
 #include <linux/config.h>
+#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/rtnetlink.h>
@@ -37,10 +38,9 @@ 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);
+static int llc_ui_wait_for_conn(struct sock *sk, long timeout);
+static int llc_ui_wait_for_disc(struct sock *sk, long timeout);
+static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
 
 #if 0
 #define dprintk(args...) printk(KERN_DEBUG args)
@@ -116,12 +116,12 @@ 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);
+       if (unlikely(llc_data_accept_state(llc->state) || llc->p_flag)) {
+               long timeout = sock_sndtimeo(sk, noblock);
 
                rc = llc_ui_wait_for_busy_core(sk, timeout);
        }
-       if (!rc)
+       if (unlikely(!rc))
                rc = llc_build_and_send_pkt(sk, skb);
        return rc;
 }
@@ -155,7 +155,7 @@ 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) {
+       if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) {
                rc = -ENOMEM;
                sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto);
                if (sk) {
@@ -177,7 +177,7 @@ static int llc_ui_release(struct socket *sock)
        struct sock *sk = sock->sk;
        struct llc_sock *llc;
 
-       if (!sk)
+       if (unlikely(sk == NULL))
                goto out;
        sock_hold(sk);
        lock_sock(sk);
@@ -189,10 +189,6 @@ static int llc_ui_release(struct socket *sock)
        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);
@@ -221,6 +217,7 @@ static int llc_ui_autoport(void)
                                llc_ui_sap_last_autoport = i + 2;
                                goto out;
                        }
+                       llc_sap_put(sap);
                }
                llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
                tries++;
@@ -231,20 +228,13 @@ out:
 }
 
 /**
- *     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.
+ *     llc_ui_autobind - automatically bind a socket to a sap
+ *     @sock: socket to bind
+ *     @addr: address to connect to
+ *
+ *     Used by llc_ui_connect and llc_ui_sendmsg when the user hasn't
+ *     specifically used llc_ui_bind to bind to an specific address/sap
  *
- *     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)
@@ -285,11 +275,7 @@ out:
  *     @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.
+ *     a specific sap only or mac + sap.
  *     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
@@ -305,10 +291,16 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
        int rc = -EINVAL;
 
        dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap);
-       if (!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr))
+       if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)))
                goto out;
        rc = -EAFNOSUPPORT;
-       if (addr->sllc_family != AF_LLC)
+       if (unlikely(addr->sllc_family != AF_LLC))
+               goto out;
+       rc = -ENODEV;
+       rtnl_lock();
+       llc->dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_mac);
+       rtnl_unlock();
+       if (!llc->dev)
                goto out;
        if (!addr->sllc_sap) {
                rc = -EUSERS;
@@ -322,6 +314,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
                rc = -EBUSY; /* some other network layer is using the sap */
                if (!sap)
                        goto out;
+               llc_sap_hold(sap);
        } else {
                struct llc_addr laddr, daddr;
                struct sock *ask;
@@ -338,7 +331,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
                ask = llc_lookup_established(sap, &daddr, &laddr);
                if (ask) {
                        sock_put(ask);
-                       goto out;
+                       goto out_put;
                }
        }
        llc->laddr.lsap = addr->sllc_sap;
@@ -348,6 +341,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
        llc_sap_add_socket(sap, sk);
        sock_reset_flag(sk, SOCK_ZAPPED);
        rc = 0;
+out_put:
+       llc_sap_put(sap);
 out:
        return rc;
 }
@@ -369,7 +364,7 @@ static int llc_ui_shutdown(struct socket *sock, int how)
        int rc = -ENOTCONN;
 
        lock_sock(sk);
-       if (sk->sk_state != TCP_ESTABLISHED)
+       if (unlikely(sk->sk_state != TCP_ESTABLISHED))
                goto out;
        rc = -EINVAL;
        if (how != 2)
@@ -404,14 +399,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
        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))
+       if (unlikely(addrlen != sizeof(*addr)))
                goto out;
        rc = -EAFNOSUPPORT;
-       if (addr->sllc_family != AF_LLC)
+       if (unlikely(addr->sllc_family != AF_LLC))
+               goto out;
+       if (unlikely(sk->sk_type != SOCK_STREAM))
+               goto out;
+       rc = -EALREADY;
+       if (unlikely(sock->state == SS_CONNECTING))
                goto out;
        /* bind connection to sap if user hasn't done it. */
        if (sock_flag(sk, SOCK_ZAPPED)) {
@@ -419,19 +418,13 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
                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;
+       llc->daddr.lsap = addr->sllc_sap;
+       memcpy(llc->daddr.mac, addr->sllc_mac, IFHWADDRLEN);
        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,
+       rc = llc_establish_connection(sk, llc->dev->dev_addr,
                                      addr->sllc_mac, addr->sllc_sap);
        if (rc) {
                dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
@@ -439,12 +432,30 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
                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);
+
+       if (sk->sk_state == TCP_SYN_SENT) {
+               const long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+
+               if (!timeo || !llc_ui_wait_for_conn(sk, timeo))
+                       goto out;
+
+               rc = sock_intr_errno(timeo);
+               if (signal_pending(current))
+                       goto out;
+       }
+
+       if (sk->sk_state == TCP_CLOSE)
+               goto sock_error;
+
+       sock->state = SS_CONNECTED;
+       rc = 0;
 out:
        release_sock(sk);
        return rc;
+sock_error:
+       rc = sock_error(sk) ? : -ECONNABORTED;
+       sock->state = SS_UNCONNECTED;
+       goto out;
 }
 
 /**
@@ -461,10 +472,10 @@ static int llc_ui_listen(struct socket *sock, int backlog)
        int rc = -EINVAL;
 
        lock_sock(sk);
-       if (sock->state != SS_UNCONNECTED)
+       if (unlikely(sock->state != SS_UNCONNECTED))
                goto out;
        rc = -EOPNOTSUPP;
-       if (sk->sk_type != SOCK_STREAM)
+       if (unlikely(sk->sk_type != SOCK_STREAM))
                goto out;
        rc = -EAGAIN;
        if (sock_flag(sk, SOCK_ZAPPED))
@@ -483,20 +494,14 @@ out:
        return rc;
 }
 
-static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
+static int llc_ui_wait_for_disc(struct sock *sk, long timeout)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int rc;
+       DEFINE_WAIT(wait);
+       int rc = 0;
 
-       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
+       while (1) {
+               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               if (sk_wait_event(sk, &timeout, sk->sk_state == TCP_CLOSE))
                        break;
                rc = -ERESTARTSYS;
                if (signal_pending(current))
@@ -504,65 +509,40 @@ static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
                rc = -EAGAIN;
                if (!timeout)
                        break;
+               rc = 0;
        }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       finish_wait(sk->sk_sleep, &wait);
        return rc;
 }
 
-static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
+static int llc_ui_wait_for_conn(struct sock *sk, long timeout)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int rc;
+       DEFINE_WAIT(wait);
 
-       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
+       while (1) {
+               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               if (sk_wait_event(sk, &timeout, sk->sk_state != TCP_SYN_SENT))
                        break;
-               rc = -ERESTARTSYS;
-               if (signal_pending(current))
-                       break;
-               rc = -EAGAIN;
-               if (!timeout)
+               if (signal_pending(current) || !timeout)
                        break;
        }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
-       return rc;
+       finish_wait(sk->sk_sleep, &wait);
+       return timeout;
 }
 
-static int llc_ui_wait_for_data(struct sock *sk, int timeout)
+static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int rc = 0;
+       DEFINE_WAIT(wait);
+       struct llc_sock *llc = llc_sk(sk);
+       int rc;
 
-       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);
-               }
+       while (1) {
+               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
                rc = 0;
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
-                       release_sock(sk);
-                       timeout = schedule_timeout(timeout);
-                       lock_sock(sk);
-               } else
+               if (sk_wait_event(sk, &timeout,
+                                 (sk->sk_shutdown & RCV_SHUTDOWN) ||
+                                 (!llc_data_accept_state(llc->state) &&
+                                  !llc->p_flag)))
                        break;
                rc = -ERESTARTSYS;
                if (signal_pending(current))
@@ -571,40 +551,35 @@ static int llc_ui_wait_for_data(struct sock *sk, int timeout)
                if (!timeout)
                        break;
        }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       finish_wait(sk->sk_sleep, &wait);
        return rc;
 }
 
-static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
+static int llc_wait_data(struct sock *sk, long timeo)
 {
-       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)
+       while (1) {
+               /*
+                * POSIX 1003.1g mandates this order.
+                */
+               if (sk->sk_err) {
+                       rc = sock_error(sk);
                        break;
+               }
                rc = 0;
-               if (llc_data_accept_state(llc->state) || llc->p_flag) {
-                       release_sock(sk);
-                       timeout = schedule_timeout(timeout);
-                       lock_sock(sk);
-               } else
+               if (sk->sk_shutdown & RCV_SHUTDOWN)
                        break;
-               rc = -ERESTARTSYS;
+               rc = -EAGAIN;
+               if (!timeo)
+                       break;
+               rc = sock_intr_errno(timeo);
                if (signal_pending(current))
                        break;
-               rc = -EAGAIN;
-               if (!timeout)
+               rc = 0;
+               if (sk_wait_data(sk, &timeo))
                        break;
        }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
        return rc;
 }
 
@@ -627,15 +602,18 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
        dprintk("%s: accepting on %02X\n", __FUNCTION__,
                llc_sk(sk)->laddr.lsap);
        lock_sock(sk);
-       if (sk->sk_type != SOCK_STREAM)
+       if (unlikely(sk->sk_type != SOCK_STREAM))
                goto out;
        rc = -EINVAL;
-       if (sock->state != SS_UNCONNECTED || sk->sk_state != TCP_LISTEN)
+       if (unlikely(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;
+       if (skb_queue_empty(&sk->sk_receive_queue)) {
+               rc = llc_wait_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);
@@ -657,7 +635,6 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
        /* 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:
@@ -671,56 +648,167 @@ out:
  *     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.
+ *     @len: 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 msghdr *msg, size_t len, int flags)
 {
-       struct sock *sk = sock->sk;
        struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
-       struct sk_buff *skb;
+       const int nonblock = flags & MSG_DONTWAIT;
+       struct sk_buff *skb = NULL;
+       struct sock *sk = sock->sk;
+       struct llc_sock *llc = llc_sk(sk);
        size_t copied = 0;
-       int rc = -ENOMEM, timeout;
-       int noblock = flags & MSG_DONTWAIT;
+       u32 peek_seq = 0;
+       u32 *seq;
+       unsigned long used;
+       int target;     /* Read at least this many bytes */
+       long timeo;
 
-       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);
+       copied = -ENOTCONN;
+       if (sk->sk_state == TCP_LISTEN)
                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->next) {
-dgram_free:
-               kfree_skb(skb);
-       }
+
+       timeo = sock_rcvtimeo(sk, nonblock);
+
+       seq = &llc->copied_seq;
+       if (flags & MSG_PEEK) {
+               peek_seq = llc->copied_seq;
+               seq = &peek_seq;
+       }
+
+       target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
+       copied = 0;
+
+       do {
+               u32 offset;
+
+               /*
+                * We need to check signals first, to get correct SIGURG
+                * handling. FIXME: Need to check this doesn't impact 1003.1g
+                * and move it down to the bottom of the loop
+                */
+               if (signal_pending(current)) {
+                       if (copied)
+                               break;
+                       copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
+                       break;
+               }
+
+               /* Next get a buffer. */
+
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb) {
+                       offset = *seq;
+                       goto found_ok_skb;
+               }
+               /* Well, if we have backlog, try to process it now yet. */
+
+               if (copied >= target && !sk->sk_backlog.tail)
+                       break;
+
+               if (copied) {
+                       if (sk->sk_err ||
+                           sk->sk_state == TCP_CLOSE ||
+                           (sk->sk_shutdown & RCV_SHUTDOWN) ||
+                           !timeo ||
+                           (flags & MSG_PEEK))
+                               break;
+               } else {
+                       if (sock_flag(sk, SOCK_DONE))
+                               break;
+
+                       if (sk->sk_err) {
+                               copied = sock_error(sk);
+                               break;
+                       }
+                       if (sk->sk_shutdown & RCV_SHUTDOWN)
+                               break;
+
+                       if (sk->sk_state == TCP_CLOSE) {
+                               if (!sock_flag(sk, SOCK_DONE)) {
+                                       /*
+                                        * This occurs when user tries to read
+                                        * from never connected socket.
+                                        */
+                                       copied = -ENOTCONN;
+                                       break;
+                               }
+                               break;
+                       }
+                       if (!timeo) {
+                               copied = -EAGAIN;
+                               break;
+                       }
+               }
+
+               if (copied >= target) { /* Do not sleep, just process backlog. */
+                       release_sock(sk);
+                       lock_sock(sk);
+               } else
+                       sk_wait_data(sk, &timeo);
+
+               if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) {
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "LLC(%s:%d): Application "
+                                                 "bug, race in MSG_PEEK.\n",
+                                      current->comm, current->pid);
+                       peek_seq = llc->copied_seq;
+               }
+               continue;
+       found_ok_skb:
+               /* Ok so how much can we use? */
+               used = skb->len - offset;
+               if (len < used)
+                       used = len;
+
+               if (!(flags & MSG_TRUNC)) {
+                       int rc = skb_copy_datagram_iovec(skb, offset,
+                                                        msg->msg_iov, used);
+                       if (rc) {
+                               /* Exception. Bailout! */
+                               if (!copied)
+                                       copied = -EFAULT;
+                               break;
+                       }
+               }
+
+               *seq += used;
+               copied += used;
+               len -= used;
+
+               if (used + offset < skb->len)
+                       continue;
+
+               if (!(flags & MSG_PEEK)) {
+                       sk_eat_skb(sk, skb);
+                       *seq = 0;
+               }
+       } while (len > 0);
+
+       /* 
+        * According to UNIX98, msg_name/msg_namelen are ignored
+        * on connected socket. -ANK
+        * But... af_llc still doesn't have separate sets of methods for
+        * SOCK_DGRAM and SOCK_STREAM :-( So we have to do this test, will
+        * eventually fix this tho :-) -acme
+        */
+       if (sk->sk_type == SOCK_DGRAM)
+               goto copy_uaddr;
 out:
        release_sock(sk);
-       return rc ? : copied;
+       return copied;
+copy_uaddr:
+       if (uaddr != NULL && skb != NULL) {
+               memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
+               msg->msg_namelen = sizeof(*uaddr);
+       }
+       goto out;
 }
 
 /**
@@ -740,7 +828,6 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock,
        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;
@@ -763,19 +850,17 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock,
                if (rc)
                        goto release;
        }
-       dev = llc->dev;
-       hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr);
+       hdrlen = llc->dev->hard_header_len + llc_ui_header_len(sk, addr);
        size = hdrlen + len;
-       if (size > dev->mtu)
-               size = dev->mtu;
+       if (size > llc->dev->mtu)
+               size = llc->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->dev      = llc->dev;
        skb->protocol = llc_proto_type(addr->sllc_arphrd);
        skb_reserve(skb, hdrlen); 
        rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied);
@@ -800,15 +885,13 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock,
        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)
+       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;
 }
@@ -895,7 +978,7 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
        int rc = -EINVAL, opt;
 
        lock_sock(sk);
-       if (level != SOL_LLC || optlen != sizeof(int))
+       if (unlikely(level != SOL_LLC || optlen != sizeof(int)))
                goto out;
        rc = get_user(opt, (int __user *)optval);
        if (rc)
@@ -915,22 +998,22 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
        case LLC_OPT_ACK_TMR_EXP:
                if (opt > LLC_OPT_MAX_ACK_TMR_EXP)
                        goto out;
-               llc->ack_timer.expire = opt;
+               llc->ack_timer.expire = opt * HZ;
                break;
        case LLC_OPT_P_TMR_EXP:
                if (opt > LLC_OPT_MAX_P_TMR_EXP)
                        goto out;
-               llc->pf_cycle_timer.expire = opt;
+               llc->pf_cycle_timer.expire = opt * HZ;
                break;
        case LLC_OPT_REJ_TMR_EXP:
                if (opt > LLC_OPT_MAX_REJ_TMR_EXP)
                        goto out;
-               llc->rej_sent_timer.expire = opt;
+               llc->rej_sent_timer.expire = opt * HZ;
                break;
        case LLC_OPT_BUSY_TMR_EXP:
                if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
                        goto out;
-               llc->busy_state_timer.expire = opt;
+               llc->busy_state_timer.expire = opt * HZ;
                break;
        case LLC_OPT_TX_WIN:
                if (opt > LLC_OPT_MAX_WIN)
@@ -970,7 +1053,7 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
        int val = 0, len = 0, rc = -EINVAL;
 
        lock_sock(sk);
-       if (level != SOL_LLC)
+       if (unlikely(level != SOL_LLC))
                goto out;
        rc = get_user(len, optlen);
        if (rc)
@@ -980,17 +1063,17 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
                goto out;
        switch (optname) {
        case LLC_OPT_RETRY:
-               val = llc->n2;                          break;
+               val = llc->n2;                                  break;
        case LLC_OPT_SIZE:
-               val = llc->n1;                          break;
+               val = llc->n1;                                  break;
        case LLC_OPT_ACK_TMR_EXP:
-               val = llc->ack_timer.expire;            break;
+               val = llc->ack_timer.expire / HZ;               break;
        case LLC_OPT_P_TMR_EXP:
-               val = llc->pf_cycle_timer.expire;       break;
+               val = llc->pf_cycle_timer.expire / HZ;          break;
        case LLC_OPT_REJ_TMR_EXP:
-               val = llc->rej_sent_timer.expire;       break;
+               val = llc->rej_sent_timer.expire / HZ;          break;
        case LLC_OPT_BUSY_TMR_EXP:
-               val = llc->busy_state_timer.expire;     break;
+               val = llc->busy_state_timer.expire / HZ;        break;
        case LLC_OPT_TX_WIN:
                val = llc->k;                           break;
        case LLC_OPT_RX_WIN:
@@ -1034,8 +1117,12 @@ static struct proto_ops llc_ui_ops = {
        .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 char llc_proc_err_msg[] __initdata =
+        KERN_CRIT "LLC: Unable to register the proc_fs entries\n";
+static char llc_sysctl_err_msg[] __initdata =
+        KERN_CRIT "LLC: Unable to register the sysctl entries\n";
+static char llc_sock_err_msg[] __initdata =
+        KERN_CRIT "LLC: Unable to register the network family\n";
 
 static int __init llc2_init(void)
 {
@@ -1048,13 +1135,28 @@ static int __init llc2_init(void)
        llc_station_init();
        llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
        rc = llc_proc_init();
-       if (rc != 0)
+       if (rc != 0) {
+               printk(llc_proc_err_msg);
                goto out_unregister_llc_proto;
-       sock_register(&llc_ui_family_ops);
+       }
+       rc = llc_sysctl_init();
+       if (rc) {
+               printk(llc_sysctl_err_msg);
+               goto out_proc;
+       }
+       rc = sock_register(&llc_ui_family_ops);
+       if (rc) {
+               printk(llc_sock_err_msg);
+               goto out_sysctl;
+       }
        llc_add_pack(LLC_DEST_SAP, llc_sap_handler);
        llc_add_pack(LLC_DEST_CONN, llc_conn_handler);
 out:
        return rc;
+out_sysctl:
+       llc_sysctl_exit();
+out_proc:
+       llc_proc_exit();
 out_unregister_llc_proto:
        proto_unregister(&llc_proto);
        goto out;
@@ -1067,6 +1169,7 @@ static void __exit llc2_exit(void)
        llc_remove_pack(LLC_DEST_CONN);
        sock_unregister(PF_LLC);
        llc_proc_exit();
+       llc_sysctl_exit();
        proto_unregister(&llc_proto);
 }
 
index b218be4c10ec44092e59deb2fdc149e027d7da79..b0bcfb1f12dd49b90a69ab7967c050f3652e3472 100644 (file)
@@ -60,23 +60,10 @@ int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb)
 
 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);
+       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
-               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;
+       ev->ind_prim = LLC_CONN_PRIM;
+       return 0;
 }
 
 int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
@@ -120,10 +107,8 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
                        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;
+       else
                rc = -EINVAL;
-       }
        if (!rc) {
                ev->reason   = reason;
                ev->ind_prim = LLC_DISC_PRIM;
@@ -160,9 +145,6 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
                           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:
@@ -172,8 +154,7 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
                if (llc->retry_count > llc->n2) {
                        reason = LLC_RESET_REASON_LOCAL;
                        rc = 0;
-               } else
-                       rc = 1;
+               }
                break;
        }
        if (!rc) {
@@ -217,18 +198,17 @@ int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
                llc_conn_ac_set_p_flag_1(sk, skb);
@@ -243,20 +223,19 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -270,19 +249,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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);
+               llc_pdu_init_as_dm_rsp(nskb, 1);
                rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
-               if (rc)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -306,17 +283,16 @@ int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb)
                llc_pdu_decode_pf_bit(skb, &f_bit);
        else
                f_bit = 0;
-       nskb = llc_alloc_frame();
+       nskb = llc_alloc_frame(sk, llc->dev);
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -330,21 +306,19 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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_pdu_init_as_frmr_rsp(nskb, pdu, 0, llc->vS,
                                         llc->vR, INCORRECT);
                rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
-               if (rc)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -360,21 +334,20 @@ 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;
+       struct llc_sock *llc = llc_sk(sk);
 
        llc_pdu_decode_pf_bit(skb, &f_bit);
-       nskb = llc_alloc_frame();
+       nskb = llc_alloc_frame(sk, llc->dev);
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -395,7 +368,7 @@ int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
                            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) {
+       if (likely(!rc)) {
                llc_conn_send_pdu(sk, skb);
                llc_conn_ac_inc_vs_by_1(sk, skb);
        }
@@ -412,7 +385,7 @@ static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
                            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) {
+       if (likely(!rc)) {
                llc_conn_send_pdu(sk, skb);
                llc_conn_ac_inc_vs_by_1(sk, skb);
        }
@@ -429,7 +402,7 @@ int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
                            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) {
+       if (likely(!rc)) {
                llc_conn_send_pdu(sk, skb);
                llc_conn_ac_inc_vs_by_1(sk, skb);
        }
@@ -451,18 +424,17 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
        u8 nr;
        struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
        int rc = -ENOBUFS;
-       struct sk_buff *nskb = llc_alloc_frame();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (likely(!rc))
                        llc_conn_send_pdu(sk, nskb);
                else
                        kfree_skb(skb);
@@ -487,18 +459,17 @@ int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -512,19 +483,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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);
+               llc_pdu_init_as_rej_rsp(nskb, 1, llc->vR);
                rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
-               if (rc)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -538,19 +507,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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);
+               llc_pdu_init_as_rej_rsp(nskb, 0, llc->vR);
                rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
-               if (rc)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -564,18 +531,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -589,19 +555,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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);
+               llc_pdu_init_as_rnr_rsp(nskb, 1, llc->vR);
                rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
-               if (rc)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -615,19 +579,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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);
+               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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -645,7 +607,7 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
        if (!llc->remote_busy_flag) {
                llc->remote_busy_flag = 1;
                mod_timer(&llc->busy_state_timer.timer,
-                        jiffies + llc->busy_state_timer.expire * HZ);
+                        jiffies + llc->busy_state_timer.expire);
        }
        return 0;
 }
@@ -653,18 +615,17 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -678,18 +639,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -703,19 +663,18 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -729,19 +688,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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);
+               llc_pdu_init_as_rr_rsp(nskb, 1, llc->vR);
                rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
-               if (rc)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -755,18 +712,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -780,18 +736,17 @@ free:
 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -815,8 +770,8 @@ void llc_conn_set_p_flag(struct sock *sk, u8 value)
 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);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        if (nskb) {
                struct llc_sap *sap = llc->sap;
@@ -824,12 +779,11 @@ int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
 
                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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
                llc_conn_set_p_flag(sk, 1);
@@ -845,11 +799,11 @@ 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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;
@@ -857,7 +811,7 @@ int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
                                    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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -886,7 +840,7 @@ int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
 
        llc_conn_set_p_flag(sk, 1);
        mod_timer(&llc->pf_cycle_timer.timer,
-                 jiffies + llc->pf_cycle_timer.expire * HZ);
+                 jiffies + llc->pf_cycle_timer.expire);
        return 0;
 }
 
@@ -957,7 +911,7 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
                            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) {
+       if (likely(!rc)) {
                llc_conn_send_pdu(sk, skb);
                llc_conn_ac_inc_vs_by_1(sk, skb);
        }
@@ -1001,18 +955,17 @@ 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();
+       struct llc_sock *llc = llc_sk(sk);
+       struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
 
        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)
+               if (unlikely(rc))
                        goto free;
                llc_conn_send_pdu(sk, nskb);
        }
@@ -1165,7 +1118,7 @@ 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);
+       mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire);
        return 0;
 }
 
@@ -1174,7 +1127,7 @@ 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);
+                 jiffies + llc->rej_sent_timer.expire);
        return 0;
 }
 
@@ -1185,7 +1138,7 @@ int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
 
        if (!timer_pending(&llc->ack_timer.timer))
                mod_timer(&llc->ack_timer.timer,
-                         jiffies + llc->ack_timer.expire * HZ);
+                         jiffies + llc->ack_timer.expire);
        return 0;
 }
 
@@ -1233,7 +1186,7 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
                }
                if (unacked)
                        mod_timer(&llc->ack_timer.timer,
-                                 jiffies + llc->ack_timer.expire * HZ);
+                                 jiffies + llc->ack_timer.expire);
        } else if (llc->failed_data_req) {
                u8 f_bit;
 
@@ -1354,13 +1307,13 @@ int llc_conn_ac_set_vs_nr(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
-int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb)
+static 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)
+static void llc_conn_tmr_common_cb(unsigned long timeout_data, u8 type)
 {
        struct sock *sk = (struct sock *)timeout_data;
        struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
@@ -1369,59 +1322,31 @@ void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
        if (skb) {
                struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
-               skb->sk  = sk;
-               ev->type = LLC_CONN_EV_TYPE_P_TMR;
+               skb_set_owner_r(skb, sk);
+               ev->type = type;
                llc_process_tmr_ev(sk, skb);
        }
        bh_unlock_sock(sk);
 }
 
-void llc_conn_busy_tmr_cb(unsigned long timeout_data)
+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);
+       llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_P_TMR);
+}
 
-               skb->sk  = sk;
-               ev->type = LLC_CONN_EV_TYPE_BUSY_TMR;
-               llc_process_tmr_ev(sk, skb);
-       }
-       bh_unlock_sock(sk);
+void llc_conn_busy_tmr_cb(unsigned long timeout_data)
+{
+       llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_BUSY_TMR);
 }
 
 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);
+       llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_ACK_TMR);
 }
 
 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);
+       llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_REJ_TMR);
 }
 
 int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
index d5bdb53a348f3002c184f3f0059ebbf183ba3309..c5deda24661486abeb62dc6a22b37e7ba366527e 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/llc_conn.h>
 #include <net/llc_sap.h>
 #include <net/sock.h>
+#include <net/llc_c_ac.h>
 #include <net/llc_c_ev.h>
 #include <net/llc_pdu.h>
 
@@ -46,8 +47,6 @@
 #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.
@@ -99,7 +98,7 @@ out:
 
 int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
@@ -107,7 +106,7 @@ int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
@@ -115,7 +114,7 @@ int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
@@ -123,7 +122,7 @@ int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
@@ -131,7 +130,7 @@ int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
@@ -139,7 +138,7 @@ int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
@@ -152,7 +151,7 @@ int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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;
@@ -160,7 +159,7 @@ int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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;
@@ -168,7 +167,7 @@ int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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;
@@ -176,7 +175,7 @@ int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -186,7 +185,7 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -197,9 +196,9 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const 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 &&
@@ -209,9 +208,9 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk,
 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const 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 &&
@@ -221,10 +220,11 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk,
 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 &&
+       const struct llc_pdu_sn * pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const u8 ns = LLC_I_GET_NS(pdu);
+       const 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",
@@ -234,7 +234,7 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
 
 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);
+       const 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) &&
@@ -244,7 +244,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -253,7 +253,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -263,9 +263,9 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const 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 &&
@@ -275,9 +275,9 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk,
 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const 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 &&
@@ -287,9 +287,9 @@ int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk,
 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const 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;
@@ -298,10 +298,11 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk,
 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 &&
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vr = llc_sk(sk)->vR;
+       const u8 ns = LLC_I_GET_NS(pdu);
+       const 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",
@@ -311,7 +312,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
 
 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);
+       const 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) &&
@@ -320,7 +321,7 @@ int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -329,7 +330,7 @@ int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -338,7 +339,7 @@ int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -347,7 +348,7 @@ int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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;
@@ -355,7 +356,7 @@ int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -364,7 +365,7 @@ int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -373,7 +374,7 @@ int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -382,7 +383,7 @@ int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -391,7 +392,7 @@ int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -400,7 +401,7 @@ int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -409,7 +410,7 @@ int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -419,7 +420,7 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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) &&
@@ -429,7 +430,7 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
 
 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);
+       const 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;
@@ -446,7 +447,7 @@ int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
 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);
+       const 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)) {
@@ -461,7 +462,7 @@ int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
 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);
+       const 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))
@@ -477,32 +478,10 @@ int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb)
        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);
+       const 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))
@@ -524,9 +503,9 @@ 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vs = llc_sk(sk)->vS;
+       const 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)) &&
@@ -542,9 +521,9 @@ 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);
+       const struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
+       const u8 vs = llc_sk(sk)->vS;
+       const 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)) &&
@@ -563,28 +542,28 @@ int llc_conn_ev_rx_any_frame(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_p_tmr_exp(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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);
+       const 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);
+       const 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);
+       const struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
        return ev->type != LLC_CONN_EV_TYPE_BUSY_TMR;
 }
@@ -596,7 +575,7 @@ int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct sk_buff *skb)
 
 int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb)
 {
-       struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+       const 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;
index 4c644bc70eaec7b4a9f3f11d55f603afd72922b0..042b24a8ca4c2119904c34c90ce6020951c9525a 100644 (file)
@@ -40,6 +40,11 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
 /* Offset table on connection states transition diagram */
 static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
 
+int sysctl_llc2_ack_timeout = LLC2_ACK_TIME * HZ;
+int sysctl_llc2_p_timeout = LLC2_P_TIME * HZ;
+int sysctl_llc2_rej_timeout = LLC2_REJ_TIME * HZ;
+int sysctl_llc2_busy_timeout = LLC2_BUSY_TIME * HZ;
+
 /**
  *     llc_conn_state_process - sends event to connection state machine
  *     @sk: connection
@@ -53,7 +58,7 @@ static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
 int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 {
        int rc;
-       struct llc_sock *llc = llc_sk(sk);
+       struct llc_sock *llc = llc_sk(skb->sk);
        struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
        /*
@@ -63,13 +68,16 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
         */
        skb_get(skb);
        ev->ind_prim = ev->cfm_prim = 0;
-       rc = llc_conn_service(sk, skb); /* sending event to state machine */
-       if (rc) {
+       /*
+        * Send event to state machine
+        */
+       rc = llc_conn_service(skb->sk, skb);
+       if (unlikely(rc != 0)) {
                printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__);
                goto out_kfree_skb;
        }
 
-       if (!ev->ind_prim && !ev->cfm_prim) {
+       if (unlikely(!ev->ind_prim && !ev->cfm_prim)) {
                /* indicate or confirm not required */
                /* XXX this is not very pretty, perhaps we should store
                 * XXX indicate/confirm-needed state in the llc_conn_state_ev
@@ -80,13 +88,13 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
                goto out_skb_put;
        }
 
-       if (ev->ind_prim && ev->cfm_prim) /* Paranoia */
+       if (unlikely(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)) {
+               llc_save_primitive(sk, skb, LLC_DATA_PRIM);
+               if (unlikely(sock_queue_rcv_skb(sk, skb))) {
                        /*
                         * shouldn't happen
                         */
@@ -95,13 +103,14 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
                        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);
-       }
+       case LLC_CONN_PRIM:
+               /*
+                * Can't be sock_queue_rcv_skb, because we have to leave the
+                * skb->sk pointing to the newly created struct sock in
+                * llc_conn_handler. -acme
+                */
+               skb_queue_tail(&sk->sk_receive_queue, skb);
+               sk->sk_state_change(sk);
                break;
        case LLC_DISC_PRIM:
                sock_hold(sk);
@@ -111,8 +120,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
                        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);
+                               sk->sk_state_change(sk);
                        }
                }
                kfree_skb(skb);
@@ -465,7 +474,7 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
 }
 
 /**
- *     llc_lookup_established - Finds connection for the remote/local sap/mac
+ *     __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)
@@ -473,14 +482,16 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
  *     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.
+ *     Caller has to make sure local_bh is disabled.
  */
-struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
-                                   struct llc_addr *laddr)
+static 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);
+       read_lock(&sap->sk_list.lock);
        sk_for_each(rc, node, &sap->sk_list.list) {
                struct llc_sock *llc = llc_sk(rc);
 
@@ -494,10 +505,22 @@ struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
        }
        rc = NULL;
 found:
-       read_unlock_bh(&sap->sk_list.lock);
+       read_unlock(&sap->sk_list.lock);
        return rc;
 }
 
+struct sock *llc_lookup_established(struct llc_sap *sap,
+                                   struct llc_addr *daddr,
+                                   struct llc_addr *laddr)
+{
+       struct sock *sk;
+
+       local_bh_disable();
+       sk = __llc_lookup_established(sap, daddr, laddr);
+       local_bh_enable();
+       return sk;
+}
+
 /**
  *     llc_lookup_listener - Finds listener for local MAC + SAP
  *     @sap: SAP
@@ -506,6 +529,7 @@ found:
  *     Search connection list of the SAP and finds connection listening on
  *     local mac, and local sap. Returns pointer for parent socket found,
  *     %NULL otherwise.
+ *     Caller has to make sure local_bh is disabled.
  */
 static struct sock *llc_lookup_listener(struct llc_sap *sap,
                                        struct llc_addr *laddr)
@@ -513,7 +537,7 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap,
        struct sock *rc;
        struct hlist_node *node;
 
-       read_lock_bh(&sap->sk_list.lock);
+       read_lock(&sap->sk_list.lock);
        sk_for_each(rc, node, &sap->sk_list.list) {
                struct llc_sock *llc = llc_sk(rc);
 
@@ -527,10 +551,19 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap,
        }
        rc = NULL;
 found:
-       read_unlock_bh(&sap->sk_list.lock);
+       read_unlock(&sap->sk_list.lock);
        return rc;
 }
 
+static struct sock *__llc_lookup(struct llc_sap *sap,
+                                struct llc_addr *daddr,
+                                struct llc_addr *laddr)
+{
+       struct sock *sk = __llc_lookup_established(sap, daddr, laddr);
+
+       return sk ? : llc_lookup_listener(sap, laddr);
+}
+
 /**
  *     llc_data_accept_state - designates if in this state data can be sent.
  *     @state: state of connection.
@@ -544,14 +577,14 @@ u8 llc_data_accept_state(u8 state)
 }
 
 /**
- *     find_next_offset - finds offset for next category of transitions
+ *     llc_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)
+static u16 __init llc_find_next_offset(struct llc_conn_state *state, u16 offset)
 {
        u16 cnt = 0;
        struct llc_conn_state_trans **next_trans;
@@ -578,8 +611,8 @@ void __init llc_build_offset_table(void)
                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;
+                       next_offset += llc_find_next_offset(curr_state,
+                                                           next_offset) + 1;
                }
        }
 }
@@ -623,6 +656,7 @@ static int llc_find_offset(int state, int ev_type)
  */
 void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
 {
+       llc_sap_hold(sap);
        write_lock_bh(&sap->sk_list.lock);
        llc_sk(sk)->sap = sap;
        sk_add_node(sk, &sap->sk_list.list);
@@ -642,6 +676,7 @@ 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_sap_put(sap);
 }
 
 /**
@@ -654,15 +689,34 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
 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);
 }
 
+static struct sock *llc_create_incoming_sock(struct sock *sk,
+                                            struct net_device *dev,
+                                            struct llc_addr *saddr,
+                                            struct llc_addr *daddr)
+{
+       struct sock *newsk = llc_sk_alloc(sk->sk_family, GFP_ATOMIC,
+                                         sk->sk_prot);
+       struct llc_sock *newllc, *llc = llc_sk(sk);
+
+       if (!newsk)
+               goto out;
+       newllc = llc_sk(newsk);
+       memcpy(&newllc->laddr, daddr, sizeof(newllc->laddr));
+       memcpy(&newllc->daddr, saddr, sizeof(newllc->daddr));
+       newllc->dev = dev;
+       dev_hold(dev);
+       llc_sap_add_socket(llc->sap, newsk);
+       llc_sap_hold(llc->sap);
+out:
+       return newsk;
+}
+
 void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
 {
        struct llc_addr saddr, daddr;
@@ -673,35 +727,35 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
        llc_pdu_decode_da(skb, daddr.mac);
        llc_pdu_decode_dsap(skb, &daddr.lsap);
 
-       sk = llc_lookup_established(sap, &saddr, &daddr);
-       if (!sk) {
+       sk = __llc_lookup(sap, &saddr, &daddr);
+       if (!sk)
+               goto drop;
+
+       bh_lock_sock(sk);
+       /*
+        * This has to be done here and not at the upper layer ->accept
+        * method because of the way the PROCOM state machine works:
+        * it needs to set several state variables (see, for instance,
+        * llc_adm_actions_2 in net/llc/llc_c_st.c) and send a packet to
+        * the originator of the new connection, and this state has to be
+        * in the newly created struct sock private area. -acme
+        */
+       if (unlikely(sk->sk_state == TCP_LISTEN)) {
+               struct sock *newsk = llc_create_incoming_sock(sk, skb->dev,
+                                                             &saddr, &daddr);
+               if (!newsk)
+                       goto drop_unlock;
+               skb_set_owner_r(skb, newsk);
+       } else {
                /*
-                * Didn't find an active connection; verify if there
-                * is a listening socket for this llc addr
+                * Can't be skb_set_owner_r, this will be done at the
+                * llc_conn_state_process function, later on, when we will use
+                * skb_queue_rcv_skb to send it to upper layers, this is
+                * another trick required to cope with how the PROCOM state
+                * machine works. -acme
                 */
-               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 {
@@ -709,11 +763,16 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
                llc_set_backlog_type(skb, LLC_PACKET);
                sk_add_backlog(sk, skb);
        }
+out:
        bh_unlock_sock(sk);
        sock_put(sk);
        return;
 drop:
        kfree_skb(skb);
+       return;
+drop_unlock:
+       kfree_skb(skb);
+       goto out;
 }
 
 #undef LLC_REFCNT_DEBUG
@@ -721,32 +780,6 @@ drop:
 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)
@@ -762,14 +795,14 @@ 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 */
+       if (likely(llc_backlog_type(skb) == LLC_PACKET)) {
+               if (likely(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 */
+               if (likely(llc->state > 1))  /* not closed */
                        rc = llc_conn_state_process(sk, skb);
                else
                        goto out_kfree_skb;
@@ -799,22 +832,22 @@ static void llc_sk_init(struct sock* sk)
        llc->dec_step = llc->connect_step = 1;
 
        init_timer(&llc->ack_timer.timer);
-       llc->ack_timer.expire         = LLC_ACK_TIME;
+       llc->ack_timer.expire         = sysctl_llc2_ack_timeout;
        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.expire         = sysctl_llc2_p_timeout;
        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.expire         = sysctl_llc2_rej_timeout;
        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.expire         = sysctl_llc2_busy_timeout;
        llc->busy_state_timer.timer.data     = (unsigned long)sk;
        llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
 
@@ -834,7 +867,8 @@ static void llc_sk_init(struct sock* sk)
  *     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 *llc_sk_alloc(int family, unsigned int __nocast priority,
+                        struct proto *prot)
 {
        struct sock *sk = sk_alloc(family, priority, prot, 1);
 
index 9727455bf0e7907d4285c42e2744bb1e4d52aed9..ab0fcd32fd8447bf69b5ee10848dc0afa88c53df 100644 (file)
@@ -40,6 +40,7 @@ static struct llc_sap *llc_sap_alloc(void)
                sap->state = LLC_SAP_STATE_ACTIVE;
                memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
                rwlock_init(&sap->sk_list.lock);
+               atomic_set(&sap->refcnt, 1);
        }
        return sap;
 }
@@ -52,9 +53,7 @@ static struct llc_sap *llc_sap_alloc(void)
  */
 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);
 }
 
 /**
@@ -70,11 +69,25 @@ static void llc_del_sap(struct llc_sap *sap)
        write_unlock_bh(&llc_sap_list_lock);
 }
 
+static struct llc_sap *__llc_sap_find(unsigned char sap_value)
+{
+       struct llc_sap* sap;
+
+       list_for_each_entry(sap, &llc_sap_list, node)
+               if (sap->laddr.lsap == sap_value)
+                       goto out;
+       sap = NULL;
+out:
+       return sap;
+}
+
 /**
  *     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.
+ *     If the sap is found it will be refcounted and the user will have to do
+ *     a llc_sap_put after use.
  *     Returns the sap or %NULL if not found.
  */
 struct llc_sap *llc_sap_find(unsigned char sap_value)
@@ -82,11 +95,9 @@ 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:
+       sap = __llc_sap_find(sap_value);
+       if (sap)
+               llc_sap_hold(sap);
        read_unlock_bh(&llc_sap_list_lock);
        return sap;
 }
@@ -106,19 +117,20 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
                                         struct packet_type *pt,
                                         struct net_device *orig_dev))
 {
-       struct llc_sap *sap = llc_sap_find(lsap);
+       struct llc_sap *sap = NULL;
 
-       if (sap) { /* SAP already exists */
-               sap = NULL;
+       write_lock_bh(&llc_sap_list_lock);
+       if (__llc_sap_find(lsap)) /* SAP already exists */
                goto out;
-       }
        sap = llc_sap_alloc();
        if (!sap)
                goto out;
        sap->laddr.lsap = lsap;
        sap->rcv_func   = func;
+       llc_sap_hold(sap);
        llc_add_sap(sap);
 out:
+       write_unlock_bh(&llc_sap_list_lock);
        return sap;
 }
 
index 0f84f66018e4ca2f63c09ee7b0a8ecdbfb429c19..ba90f7f0801ad5fbe9006a3da96234a71b6b7042 100644 (file)
@@ -47,14 +47,11 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
        int rc = -ECONNABORTED;
        struct llc_sock *llc = llc_sk(sk);
 
-       if (llc->state == LLC_CONN_STATE_ADM)
+       if (unlikely(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) {
+       if (unlikely(llc_data_accept_state(llc->state) || /* data_conn_refuse */
+                    llc->p_flag)) {
                llc->failed_data_req = 1;
                goto out;
        }
@@ -110,6 +107,7 @@ int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
                ev->type      = LLC_CONN_EV_TYPE_PRIM;
                ev->prim      = LLC_CONN_PRIM;
                ev->prim_type = LLC_PRIM_TYPE_REQ;
+               skb_set_owner_w(skb, sk);
                rc = llc_conn_state_process(sk, skb);
        }
 out_put:
@@ -144,6 +142,7 @@ int llc_send_disc(struct sock *sk)
        skb = alloc_skb(0, GFP_ATOMIC);
        if (!skb)
                goto out;
+       skb_set_owner_w(skb, sk);
        sk->sk_state  = TCP_CLOSING;
        ev            = llc_conn_ev(skb);
        ev->type      = LLC_CONN_EV_TYPE_PRIM;
index 13b46240b7a108148657aa736a03a52b7e540b41..8f3addf0724c01658c8c46b96677f701c52197f8 100644 (file)
@@ -99,15 +99,19 @@ out:
 static inline int llc_fixup_skb(struct sk_buff *skb)
 {
        u8 llc_len = 2;
-       struct llc_pdu_sn *pdu;
+       struct llc_pdu_un *pdu;
 
-       if (!pskb_may_pull(skb, sizeof(*pdu)))
+       if (unlikely(!pskb_may_pull(skb, sizeof(*pdu))))
                return 0;
 
-       pdu = (struct llc_pdu_sn *)skb->data;
+       pdu = (struct llc_pdu_un *)skb->data;
        if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U)
                llc_len = 1;
        llc_len += 2;
+
+       if (unlikely(!pskb_may_pull(skb, llc_len)))
+               return 0;
+
        skb->h.raw += llc_len;
        skb_pull(skb, llc_len);
        if (skb->protocol == htons(ETH_P_802_2)) {
@@ -166,17 +170,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
         */
        if (sap->rcv_func) {
                sap->rcv_func(skb, dev, pt, orig_dev);
-               goto out;
+               goto out_put;
        }
        dest = llc_pdu_type(skb);
        if (unlikely(!dest || !llc_type_handlers[dest - 1]))
-               goto drop;
+               goto drop_put;
        llc_type_handlers[dest - 1](sap, skb);
+out_put:
+       llc_sap_put(sap);
 out:
        return 0;
 drop:
        kfree_skb(skb);
        goto out;
+drop_put:
+       kfree_skb(skb);
+       goto out_put;
 handle_station:
        if (!llc_station_handler)
                goto drop;
index ab5784cf163e738754e161f54ac8c5fb85a3477a..b4d55b6abb679f33c39fa54c0d3f370a3909c448 100644 (file)
@@ -98,7 +98,7 @@ int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
                            dsap, LLC_PDU_CMD);
        llc_pdu_init_as_ui_cmd(skb);
        rc = llc_mac_hdr_init(skb, skb->dev->dev_addr, dmac);
-       if (!rc)
+       if (likely(!rc))
                rc = dev_queue_xmit(skb);
        return rc;
 }
index 36e8db3fa1a2af6bc95cae50b2e2948fea178aed..bd531cb235a70c6ea22de33b935307ca04aeea24 100644 (file)
@@ -134,7 +134,7 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v)
        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),
+                  atomic_read(&sk->sk_rmem_alloc) - llc->copied_seq,
                   sk->sk_state,
                   sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1,
                   llc->link);
index ed8ba7de6122301e78800c6c4524815c16a5b782..bb3580fb8cfe9410e21cd432996cc06fbcc413de 100644 (file)
@@ -58,7 +58,7 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
                            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)
+       if (likely(!rc))
                rc = dev_queue_xmit(skb);
        return rc;
 }
@@ -81,7 +81,7 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
                            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)
+       if (likely(!rc))
                rc = dev_queue_xmit(skb);
        return rc;
 }
@@ -103,15 +103,14 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
        llc_pdu_decode_sa(skb, mac_da);
        llc_pdu_decode_da(skb, mac_sa);
        llc_pdu_decode_ssap(skb, &dsap);
-       nskb = llc_alloc_frame();
+       nskb = llc_alloc_frame(NULL, skb->dev);
        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)
+       if (likely(!rc))
                rc = dev_queue_xmit(nskb);
 out:
        return rc;
@@ -135,7 +134,7 @@ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb)
                            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)
+       if (likely(!rc))
                rc = dev_queue_xmit(skb);
        return rc;
 }
@@ -149,15 +148,14 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
        llc_pdu_decode_sa(skb, mac_da);
        llc_pdu_decode_da(skb, mac_sa);
        llc_pdu_decode_ssap(skb, &dsap);
-       nskb = llc_alloc_frame();
+       nskb = llc_alloc_frame(NULL, skb->dev);
        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)
+       if (likely(!rc))
                rc = dev_queue_xmit(nskb);
 out:
        return rc;
index 34228ef149854175c7ecc65a6bc7d008c05421b5..4029ceee9b9168d2f7b09e1eb1d64316f8544234 100644 (file)
 
 /**
  *     llc_alloc_frame - allocates sk_buff for frame
+ *     @dev: network device this skb will be sent over
  *
  *     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 *llc_alloc_frame(struct sock *sk, struct net_device *dev)
 {
        struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
 
@@ -38,18 +39,23 @@ struct sk_buff *llc_alloc_frame(void)
                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->dev      = dev;
                skb->mac.raw  = skb->head;
+               if (sk != NULL)
+                       skb_set_owner_w(skb, sk);
        }
        return skb;
 }
 
-void llc_save_primitive(struct sk_buff* skb, u8 prim)
+void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim)
 {
-       struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
+       struct sockaddr_llc *addr;
 
+       if (skb->sk->sk_type == SOCK_STREAM) /* See UNIX98 */
+               return;
        /* save primitive for use by the user. */
-       addr->sllc_family = skb->sk->sk_family;
+       addr              = llc_ui_skb_cb(skb);
+       addr->sllc_family = sk->sk_family;
        addr->sllc_arphrd = skb->dev->type;
        addr->sllc_test   = prim == LLC_TEST_PRIM;
        addr->sllc_xid    = prim == LLC_XID_PRIM;
@@ -189,7 +195,7 @@ static void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
                if (skb->sk->sk_state == TCP_LISTEN)
                        kfree_skb(skb);
                else {
-                       llc_save_primitive(skb, ev->prim);
+                       llc_save_primitive(skb->sk, skb, ev->prim);
 
                        /* queue skb to the user. */
                        if (sock_queue_rcv_skb(skb->sk, skb))
@@ -308,7 +314,7 @@ void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
 
        sk = llc_lookup_dgram(sap, &laddr);
        if (sk) {
-               skb->sk = sk;
+               skb_set_owner_r(skb, sk);
                llc_sap_rcv(sap, skb);
                sock_put(sk);
        } else
index 8fe48a24bad5f1606826f57e5e018432fa00881a..f37dbf8ef126a1cdc8464d98f1320660f664a9f6 100644 (file)
@@ -50,6 +50,10 @@ struct llc_station {
        struct sk_buff_head         mac_pdu_q;
 };
 
+#define LLC_STATION_ACK_TIME (3 * HZ)
+
+int sysctl_llc_station_ack_timeout = LLC_STATION_ACK_TIME;
+
 /* Types of events (possible values in 'ev->type') */
 #define LLC_STATION_EV_TYPE_SIMPLE     1
 #define LLC_STATION_EV_TYPE_CONDITION  2
@@ -218,7 +222,8 @@ static void llc_station_send_pdu(struct sk_buff *skb)
 
 static int llc_station_ac_start_ack_timer(struct sk_buff *skb)
 {
-       mod_timer(&llc_main_station.ack_timer, jiffies + LLC_ACK_TIME * HZ);
+       mod_timer(&llc_main_station.ack_timer,
+                 jiffies + sysctl_llc_station_ack_timeout);
        return 0;
 }
 
@@ -249,14 +254,14 @@ static int llc_station_ac_inc_xid_r_cnt_by_1(struct sk_buff *skb)
 static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb)
 {
        int rc = 1;
-       struct sk_buff *nskb = llc_alloc_frame();
+       struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev);
 
        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)
+       if (unlikely(rc))
                goto free;
        llc_station_send_pdu(nskb);
 out:
@@ -270,18 +275,17 @@ 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();
+       struct sk_buff* nskb = llc_alloc_frame(NULL, skb->dev);
 
        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)
+       if (unlikely(rc))
                goto free;
        llc_station_send_pdu(nskb);
 out:
@@ -295,18 +299,17 @@ 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();
+       struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev);
 
        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)
+       if (unlikely(rc))
                goto free;
        llc_station_send_pdu(nskb);
 out:
@@ -689,7 +692,8 @@ int __init llc_station_init(void)
        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;
-
+       llc_main_station.ack_timer.expires  = jiffies +
+                                               sysctl_llc_station_ack_timeout;
        skb = alloc_skb(0, GFP_ATOMIC);
        if (!skb)
                goto out;
@@ -697,7 +701,6 @@ int __init llc_station_init(void)
        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;
diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c
new file mode 100644 (file)
index 0000000..d1eaddb
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * sysctl_net_llc.c: sysctl interface to LLC net subsystem.
+ * 
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <net/llc.h>
+
+#ifndef CONFIG_SYSCTL
+#error This file should not be compiled without CONFIG_SYSCTL defined
+#endif
+
+static struct ctl_table llc2_timeout_table[] = {
+       {
+               .ctl_name       = NET_LLC2_ACK_TIMEOUT,
+               .procname       = "ack",
+               .data           = &sysctl_llc2_ack_timeout,
+               .maxlen         = sizeof(long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = &sysctl_jiffies,
+       },
+       {
+               .ctl_name       = NET_LLC2_BUSY_TIMEOUT,
+               .procname       = "busy",
+               .data           = &sysctl_llc2_busy_timeout,
+               .maxlen         = sizeof(long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = &sysctl_jiffies,
+       },
+       {
+               .ctl_name       = NET_LLC2_P_TIMEOUT,
+               .procname       = "p",
+               .data           = &sysctl_llc2_p_timeout,
+               .maxlen         = sizeof(long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = &sysctl_jiffies,
+       },
+       {
+               .ctl_name       = NET_LLC2_REJ_TIMEOUT,
+               .procname       = "rej",
+               .data           = &sysctl_llc2_rej_timeout,
+               .maxlen         = sizeof(long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = &sysctl_jiffies,
+       },
+       { 0 },
+};
+
+static struct ctl_table llc_station_table[] = {
+       {
+               .ctl_name       = NET_LLC_STATION_ACK_TIMEOUT,
+               .procname       = "ack_timeout",
+               .data           = &sysctl_llc_station_ack_timeout,
+               .maxlen         = sizeof(long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = &sysctl_jiffies,
+       },
+       { 0 },
+};
+
+static struct ctl_table llc2_dir_timeout_table[] = {
+       {
+               .ctl_name       = NET_LLC2,
+               .procname       = "timeout",
+               .mode           = 0555,
+               .child          = llc2_timeout_table,
+               },
+       { 0 },
+};
+
+static struct ctl_table llc_table[] = {
+       {
+               .ctl_name       = NET_LLC2,
+               .procname       = "llc2",
+               .mode           = 0555,
+               .child          = llc2_dir_timeout_table,
+               },
+       {
+               .ctl_name       = NET_LLC_STATION,
+               .procname       = "station",
+               .mode           = 0555,
+               .child          = llc_station_table,
+       },
+       { 0 },
+};
+
+static struct ctl_table llc_dir_table[] = {
+       {
+               .ctl_name       = NET_LLC,
+               .procname       = "llc",
+               .mode           = 0555,
+               .child          = llc_table,
+               },
+       { 0 },
+};
+
+static struct ctl_table llc_root_table[] = {
+       {
+               .ctl_name       = CTL_NET,
+               .procname       = "net",
+               .mode           = 0555,
+               .child          = llc_dir_table,
+       },
+       { 0 },
+};
+
+static struct ctl_table_header *llc_table_header;
+
+int __init llc_sysctl_init(void)
+{
+       llc_table_header = register_sysctl_table(llc_root_table, 1);
+
+       return llc_table_header ? 0 : -ENOMEM;
+}
+
+void llc_sysctl_exit(void)
+{
+       if (llc_table_header) {
+               unregister_sysctl_table(llc_table_header);
+               llc_table_header = NULL;
+       }
+}