From 590232a7150674b2036291eaefce085f3f9659c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 22 Sep 2005 04:30:44 -0300 Subject: [LLC]: Add sysctl support for the LLC timeouts Signed-off-by: Jochen Friedrich Signed-off-by: Arnaldo Carvalho de Melo --- include/net/llc_conn.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include/net/llc_conn.h') diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 8ad3bc2c23d..8a8ff481013 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -19,14 +19,14 @@ #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 { -- cgit v1.2.3-70-g09d2 From 6e2144b76840be09924de1626e2dcd7b315f75b3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 22 Sep 2005 04:43:05 -0300 Subject: [LLC]: Use refcounting with struct llc_sap Signed-off-by: Jochen Friedrich Signed-off-by: Arnaldo Carvalho de Melo --- include/net/llc.h | 16 +++++++++++++++- include/net/llc_conn.h | 1 - net/802/p8022.c | 2 +- net/802/psnap.c | 2 +- net/llc/af_llc.c | 11 ++++++----- net/llc/llc_c_ac.c | 1 + net/llc/llc_conn.c | 28 ++-------------------------- net/llc/llc_core.c | 34 +++++++++++++++++++++++----------- net/llc/llc_input.c | 9 +++++++-- 9 files changed, 56 insertions(+), 48 deletions(-) (limited to 'include/net/llc_conn.h') diff --git a/include/net/llc.h b/include/net/llc.h index 8b8e2be289b..93e5b443a9a 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -17,6 +17,8 @@ #include #include +#include + 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,7 +84,18 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)); -extern void llc_sap_close(struct llc_sap *sap); +static inline void llc_sap_hold(struct llc_sap *sap) +{ + atomic_inc(&sap->refcnt); +} + +static inline void llc_sap_put(struct llc_sap *sap) +{ + extern void llc_sap_close(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); diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 8a8ff481013..b2889218c76 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -115,5 +115,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 */ diff --git a/net/802/p8022.c b/net/802/p8022.c index b24817c63ca..2530f35241c 100644 --- a/net/802/p8022.c +++ b/net/802/p8022.c @@ -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); } diff --git a/net/802/psnap.c b/net/802/psnap.c index ab80b1fab53..4d638944d93 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c @@ -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); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index ad9aad807aa..a75b8f2aab1 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -21,6 +21,7 @@ * See the GNU General Public License for more details. */ #include +#include #include #include #include @@ -188,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); @@ -220,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++; @@ -310,6 +308,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; @@ -326,7 +325,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; @@ -336,6 +335,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; } diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index c1e75103189..05236c2cbb9 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -75,6 +75,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) llc->dev = skb->dev; ev->ind_prim = LLC_CONN_PRIM; rc = 0; + llc_sap_put(sap); } return rc; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 9f0e10e0978..ab9e6d7e287 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -633,6 +633,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); @@ -652,6 +653,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); } /** @@ -730,32 +732,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) diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 9727455bf0e..9ccff1266b2 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -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); } +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; } diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 60c1acac7c9..789eec42645 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -166,17 +166,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; -- cgit v1.2.3-70-g09d2 From 2928c19e1086e2f1e90d05931437ab6f1e4cfdc8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 22 Sep 2005 05:14:33 -0300 Subject: [LLC]: Fix sparse warnings Signed-off-by: Arnaldo Carvalho de Melo --- include/net/llc.h | 13 +++++++++++-- include/net/llc_conn.h | 3 ++- net/llc/af_llc.c | 5 +---- net/llc/llc_c_ac.c | 2 +- net/llc/llc_conn.c | 3 ++- net/llc/llc_core.c | 2 +- net/llc/sysctl_net_llc.c | 7 +------ 7 files changed, 19 insertions(+), 16 deletions(-) (limited to 'include/net/llc_conn.h') diff --git a/include/net/llc.h b/include/net/llc.h index 93e5b443a9a..1adb2ef3f6f 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -89,10 +89,10 @@ 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) { - extern void llc_sap_close(struct llc_sap *sap); - if (atomic_dec_and_test(&sap->refcnt)) llc_sap_close(sap); } @@ -102,6 +102,9 @@ 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); @@ -115,6 +118,12 @@ extern void llc_proc_exit(void); #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) diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index b2889218c76..e44f494bbef 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -92,7 +92,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); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 3361ae900e2..7aa51eb79b1 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -555,7 +555,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout) return rc; } -int llc_wait_data(struct sock *sk, long timeo) +static int llc_wait_data(struct sock *sk, long timeo) { int rc; @@ -1003,9 +1003,6 @@ 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 = diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index 05236c2cbb9..8f7b46d2063 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -1321,7 +1321,7 @@ 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; diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index ab9e6d7e287..76f94e0d840 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -819,7 +819,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); diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 9ccff1266b2..ab0fcd32fd8 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -69,7 +69,7 @@ static void llc_del_sap(struct llc_sap *sap) write_unlock_bh(&llc_sap_list_lock); } -struct llc_sap *__llc_sap_find(unsigned char sap_value) +static struct llc_sap *__llc_sap_find(unsigned char sap_value) { struct llc_sap* sap; diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c index 4d99d2f27a2..d1eaddb1363 100644 --- a/net/llc/sysctl_net_llc.c +++ b/net/llc/sysctl_net_llc.c @@ -8,17 +8,12 @@ #include #include #include +#include #ifndef CONFIG_SYSCTL #error This file should not be compiled without CONFIG_SYSCTL defined #endif -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; - static struct ctl_table llc2_timeout_table[] = { { .ctl_name = NET_LLC2_ACK_TIMEOUT, -- cgit v1.2.3-70-g09d2 From 8420e1b541fe92aee1d8d4d25d9e33eaca756a7b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 22 Sep 2005 08:29:08 -0300 Subject: [LLC]: fix llc_ui_recvmsg, making it behave like tcp_recvmsg In fact it is an exact copy of the parts that makes sense to LLC :-) Signed-off-by: Arnaldo Carvalho de Melo --- include/net/llc_conn.h | 1 + net/llc/af_llc.c | 180 ++++++++++++++++++++++++++++++++++++++++--------- net/llc/llc_conn.c | 2 +- net/llc/llc_proc.c | 2 +- net/llc/llc_sap.c | 5 +- 5 files changed, 154 insertions(+), 36 deletions(-) (limited to 'include/net/llc_conn.h') diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index e44f494bbef..54852ff6033 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -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; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 7aa51eb79b1..59d02cbbeb9 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -648,53 +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; - 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); - if (skb_queue_empty(&sk->sk_receive_queue)) { - rc = llc_wait_data(sk, sock_rcvtimeo(sk, noblock)); - if (rc) - goto out; - } - skb = skb_dequeue(&sk->sk_receive_queue); - if (!skb) /* shutdown */ + copied = -ENOTCONN; + if (sk->sk_state == TCP_LISTEN) 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; } /** diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index e10ce5adb10..042b24a8ca4 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -120,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); diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 36e8db3fa1a..bd531cb235a 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -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); diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index e6d538937f9..4029ceee9b9 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -49,9 +49,12 @@ struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev) 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 = llc_ui_skb_cb(skb); addr->sllc_family = sk->sk_family; addr->sllc_arphrd = skb->dev->type; addr->sllc_test = prim == LLC_TEST_PRIM; -- cgit v1.2.3-70-g09d2