summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@conectiva.com.br>2002-09-11 07:48:48 -0300
committerArnaldo Carvalho de Melo <acme@conectiva.com.br>2002-09-11 07:48:48 -0300
commit269f04b762fa11f693d3c3167afcdd4ca505fca6 (patch)
treed46f99f4f39506ab6e2c21871a051c651ef93967
parentebf9bc772851196b2a5e8daf4eadd609c734501f (diff)
[LLC] use just one struct sock per connection
With this PF_LLC is tightly integrated with the core and that is a good thing 8) . kill llc_ui_opt, the only non-duplicated bit is struct sockaddr_llc and this now lives in llc_opt . remove debug code from llc_sk_alloc/free (previously llc_sock_alloc/free) . the skbs allocated for event processing don't need to have any payload at all, just the skb->cb is enough, so remove the bogus 1 from alloc_skb calls . llc_conn_disc put on death row . llc_process_tmr_ev callers have to hold the socket lock . the request functions in llc_if.c doesn't hold the socket lock anymore its up to its callers on the socket layer (llc_sock.c) . llc_sk_alloc now receives a priority for sk_alloc call and is the only way to alloc a new sock (from llc_mac and llc_sock, bottom and top) . added the traditional struct sock REFCNT_DEBUG support for llc . llc_sock was simplified and is on the zen route to cleanliness, wait for the next patches, it'll shrink a lot when I zap all the crap (as in not needed) list handling, using the existing list maintained in struct llc_sap for that, probably splitting it in two, one for listening sockets and other for (being) established ones. Ah, and the sap->ind and sap->req and friends will die.
-rw-r--r--include/linux/llc.h11
-rw-r--r--include/net/llc_conn.h64
-rw-r--r--include/net/llc_if.h2
-rw-r--r--net/llc/llc_actn.c2
-rw-r--r--net/llc/llc_c_ac.c42
-rw-r--r--net/llc/llc_conn.c34
-rw-r--r--net/llc/llc_if.c56
-rw-r--r--net/llc/llc_mac.c19
-rw-r--r--net/llc/llc_main.c59
-rw-r--r--net/llc/llc_sock.c619
10 files changed, 409 insertions, 499 deletions
diff --git a/include/linux/llc.h b/include/linux/llc.h
index 824a149e9e6b..77ac5d9df544 100644
--- a/include/linux/llc.h
+++ b/include/linux/llc.h
@@ -78,17 +78,6 @@ enum llc_sockopts {
#define LLC_SAP_DYN_STOP 0xDE
#define LLC_SAP_DYN_TRIES 4
-struct sock;
-
-struct llc_ui_opt {
- u16 link; /* network layer link number */
- struct llc_sap *sap; /* pointer to parent SAP */
- struct sock *core_sk;
- struct net_device *dev; /* device to send to remote */
- struct sockaddr_llc addr; /* address sock is bound to */
-};
-
-#define llc_ui_sk(__sk) ((struct llc_ui_opt *)(__sk)->protinfo)
#define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0]))
#ifdef CONFIG_LLC_UI
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
index ea7725fa705f..3b2d68e45075 100644
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -2,7 +2,7 @@
#define LLC_CONN_H
/*
* Copyright (c) 1997 by Procom Technology, Inc.
- * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * 2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
@@ -13,8 +13,7 @@
*/
#include <linux/timer.h>
#include <net/llc_if.h>
-
-#define DEBUG_LLC_CONN_ALLOC
+#include <linux/llc.h>
struct llc_timer {
struct timer_list timer;
@@ -25,7 +24,7 @@ struct llc_timer {
struct llc_opt {
struct list_head node; /* entry in sap->sk_list.list */
struct sock *sk; /* sock that has this llc_opt */
- void *handler; /* for upper layers usage */
+ struct sockaddr_llc addr; /* address sock is bound to */
u8 state; /* state of connection */
struct llc_sap *sap; /* pointer to parent SAP */
struct llc_addr laddr; /* lsap/mac pair */
@@ -80,60 +79,11 @@ struct llc_opt {
struct llc_conn_state_ev;
-extern struct sock *__llc_sock_alloc(int family);
-extern void __llc_sock_free(struct sock *sk, u8 free);
-
-#ifdef DEBUG_LLC_CONN_ALLOC
-#define dump_stack() printk(KERN_INFO "call trace: %p, %p, %p\n", \
- __builtin_return_address(0), \
- __builtin_return_address(1), \
- __builtin_return_address(2));
-#define llc_sock_alloc(family) ({ \
- struct sock *__sk = __llc_sock_alloc(family); \
- if (__sk) { \
- llc_sk(__sk)->f_alloc = __FUNCTION__; \
- llc_sk(__sk)->l_alloc = __LINE__; \
- } \
- __sk;})
-#define __llc_sock_assert(__sk) \
- if (llc_sk(__sk)->f_free) { \
- printk(KERN_ERR \
- "%p conn (alloc'd @ %s(%d)) " \
- "already freed @ %s(%d) " \
- "being used again @ %s(%d)\n", \
- llc_sk(__sk), \
- llc_sk(__sk)->f_alloc, llc_sk(__sk)->l_alloc, \
- llc_sk(__sk)->f_free, llc_sk(__sk)->l_free, \
- __FUNCTION__, __LINE__); \
- dump_stack();
-#define llc_sock_free(__sk) \
-{ \
- __llc_sock_assert(__sk) \
- } else { \
- __llc_sock_free(__sk, 0); \
- llc_sk(__sk)->f_free = __FUNCTION__; \
- llc_sk(__sk)->l_free = __LINE__; \
- } \
-}
-#define llc_sock_assert(__sk) \
-{ \
- __llc_sock_assert(__sk); \
- return; } \
-}
-#define llc_sock_assert_ret(__sk, __ret) \
-{ \
- __llc_sock_assert(__sk); \
- return __ret; } \
-}
-#else /* DEBUG_LLC_CONN_ALLOC */
-#define llc_sock_alloc(family) __llc_sock_alloc(family)
-#define llc_sock_free(__sk) __llc_sock_free(__sk, 1)
-#define llc_sock_assert(__sk)
-#define llc_sock_assert_ret(__sk)
-#endif /* DEBUG_LLC_CONN_ALLOC */
+extern struct sock *llc_sk_alloc(int family, int priority);
+extern void llc_sk_free(struct sock *sk);
-extern void llc_sock_reset(struct sock *sk);
-extern int llc_sock_init(struct sock *sk);
+extern void llc_sk_reset(struct sock *sk);
+extern int llc_sk_init(struct sock *sk);
/* Access to a connection */
extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb);
diff --git a/include/net/llc_if.h b/include/net/llc_if.h
index 975485fc42c0..e294c1d976b1 100644
--- a/include/net/llc_if.h
+++ b/include/net/llc_if.h
@@ -73,8 +73,6 @@ struct llc_prim_conn {
u8 pri; /* service_class */
struct net_device *dev;
struct sock *sk; /* returned from REQUEST */
- void *handler; /* upper layer use,
- stored in llc_opt->handler */
u16 link;
struct sk_buff *skb; /* received SABME */
};
diff --git a/net/llc/llc_actn.c b/net/llc/llc_actn.c
index cb8704409d8e..dadb22054749 100644
--- a/net/llc/llc_actn.c
+++ b/net/llc/llc_actn.c
@@ -134,7 +134,7 @@ int llc_station_ac_report_status(struct llc_station *station,
static void llc_station_ack_tmr_callback(unsigned long timeout_data)
{
struct llc_station *station = (struct llc_station *)timeout_data;
- struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
station->ack_tmr_running = 0;
if (skb) {
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
index bc296905424d..ecb6d6f1658d 100644
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -1454,8 +1454,9 @@ int llc_conn_ac_set_f_flag_p(struct sock *sk, struct sk_buff *skb)
void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
{
struct sock *sk = (struct sock *)timeout_data;
- struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
+ bh_lock_sock(sk);
llc_sk(sk)->pf_cycle_timer.running = 0;
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -1464,13 +1465,15 @@ void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb);
}
+ bh_unlock_sock(sk);
}
static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
{
struct sock *sk = (struct sock *)timeout_data;
- struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
+ bh_lock_sock(sk);
llc_sk(sk)->busy_state_timer.running = 0;
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -1479,13 +1482,15 @@ static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb);
}
+ bh_unlock_sock(sk);
}
void llc_conn_ack_tmr_cb(unsigned long timeout_data)
{
struct sock* sk = (struct sock *)timeout_data;
- struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
+ bh_lock_sock(sk);
llc_sk(sk)->ack_timer.running = 0;
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -1494,13 +1499,15 @@ void llc_conn_ack_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb);
}
+ bh_unlock_sock(sk);
}
static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
{
struct sock *sk = (struct sock *)timeout_data;
- struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
+ bh_lock_sock(sk);
llc_sk(sk)->rej_sent_timer.running = 0;
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -1509,6 +1516,7 @@ static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb);
}
+ bh_unlock_sock(sk);
}
int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
@@ -1536,14 +1544,11 @@ int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb)
* llc_conn_disc - removes connection from SAP list and frees it
* @sk: closed connection
* @skb: occurred event
- *
- * Returns 2, to indicate the state machine that the connection was freed.
*/
int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
{
- llc_sap_unassign_sock(llc_sk(sk)->sap, sk);
- llc_sock_free(sk);
- return 2;
+ /* FIXME: this thing seems to want to die */
+ return 0;
}
/**
@@ -1555,7 +1560,7 @@ int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
*/
int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
{
- llc_sock_reset(sk);
+ llc_sk_reset(sk);
return 0;
}
@@ -1589,19 +1594,16 @@ u8 llc_circular_between(u8 a, u8 b, u8 c)
*/
static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
{
- bh_lock_sock(sk);
if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
printk(KERN_WARNING "%s: timer called on closed connection\n",
__FUNCTION__);
llc_conn_free_ev(skb);
- goto out;
- }
- if (!sk->lock.users)
- llc_conn_state_process(sk, skb);
- else {
- llc_set_backlog_type(skb, LLC_EVENT);
- sk_add_backlog(sk, skb);
+ } else {
+ if (!sk->lock.users)
+ llc_conn_state_process(sk, skb);
+ else {
+ llc_set_backlog_type(skb, LLC_EVENT);
+ sk_add_backlog(sk, skb);
+ }
}
-out:
- bh_unlock_sock(sk);
}
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index ef6093acb1c3..46e54e9621ba 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -43,7 +43,7 @@ static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
* @sk: connection
* @skb: occurred event
*
- * Sends an event to connection state machine. after processing event
+ * Sends an event to connection state machine. After processing event
* (executing it's actions and changing state), upper layer will be
* indicated or confirmed, if needed. Returns 0 for success, 1 for
* failure. The socket lock has to be held before calling this function.
@@ -65,15 +65,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
llc_conn_free_ev(skb);
else if (ind_prim && cfm_prim)
skb_get(skb);
-#ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY
- /* check if the connection was freed by the state machine by
- * means of llc_conn_disc */
- if (rc == 2) {
- printk(KERN_INFO "%s: rc == 2\n", __FUNCTION__);
- rc = -ECONNABORTED;
- goto out;
- }
-#endif /* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */
if (!flag) /* indicate or confirm not required */
goto out;
rc = 0;
@@ -83,10 +74,13 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
* sock crap
*/
if (flag == LLC_DATA_PRIM + 1) {
- struct sock *upper = llc_sk(skb->sk)->handler;
-
- skb->sk = upper;
- if (sock_queue_rcv_skb(upper, skb)) {
+ if (sock_queue_rcv_skb(skb->sk, skb)) {
+ /*
+ * FIXME: have to sync the LLC state
+ * machine wrt mem usage with
+ * sk->{r,w}mem_alloc, will do
+ * this soon 8)
+ */
printk(KERN_ERR
"%s: sock_queue_rcv_skb failed!\n",
__FUNCTION__);
@@ -105,10 +99,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
}
if (!llc_data_accept_state(llc->state)) {
/* In this state, we can send I pdu */
- struct sock* upper = llc_sk(skb->sk)->handler;
-
- if (upper)
- wake_up(upper->sleep);
+ if (skb->sk)
+ skb->sk->write_space(skb->sk);
} else
rc = llc->failed_data_req = 1;
kfree_skb(skb);
@@ -118,7 +110,6 @@ out:
void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
{
- llc_sock_assert(sk);
/* queue PDU to send to MAC layer */
skb_queue_tail(&sk->write_queue, skb);
llc_conn_send_pdus(sk);
@@ -380,11 +371,10 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
* llc_exec_conn_trans_actions - executes related actions
* @sk: connection
* @trans: transition that it's actions must be performed
- * @skb: happened event
+ * @skb: event
*
* Executes actions that is related to happened event. Returns 0 for
- * success, 1 to indicate failure of at least one action or 2 if the
- * connection was freed (llc_conn_disc was called)
+ * success, 1 to indicate failure of at least one action.
*/
static int llc_exec_conn_trans_actions(struct sock *sk,
struct llc_conn_state_trans *trans,
diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c
index cab3de5fb797..8af1ec3a1417 100644
--- a/net/llc/llc_if.c
+++ b/net/llc/llc_if.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/tcp.h>
#include <asm/errno.h>
#include <net/llc_if.h>
#include <net/llc_sap.h>
@@ -249,7 +250,6 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
int rc = -ECONNABORTED;
struct llc_opt *llc = llc_sk(sk);
- lock_sock(sk);
if (llc->state == LLC_CONN_STATE_ADM)
goto out;
rc = -EBUSY;
@@ -269,7 +269,6 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
skb->dev = llc->dev;
rc = llc_conn_state_process(sk, skb);
out:
- release_sock(sk);
return rc;
}
@@ -299,7 +298,6 @@ static void llc_confirm_impossible(struct llc_prim_if_block *prim)
static int llc_conn_req_handler(struct llc_prim_if_block *prim)
{
int rc = -EBUSY;
- struct llc_opt *llc;
struct llc_sap *sap = prim->sap;
struct sk_buff *skb;
struct net_device *ddev = mac_dev_peer(prim->data->conn.dev,
@@ -319,37 +317,16 @@ static int llc_conn_req_handler(struct llc_prim_if_block *prim)
daddr.lsap = prim->data->conn.daddr.lsap;
sk = llc_lookup_established(sap, &daddr, &laddr);
if (sk) {
- llc_confirm_impossible(prim);
- goto out_put;
- }
- rc = -ENOMEM;
- if (prim->data->conn.sk) {
- sk = prim->data->conn.sk;
- if (llc_sock_init(sk))
- goto out;
- } else {
- /*
- * FIXME: this one will die as soon as core and
- * llc_sock starts sharing a struct sock.
- */
- sk = llc_sock_alloc(PF_LLC);
- if (!sk) {
+ if (sk->state == TCP_ESTABLISHED) {
llc_confirm_impossible(prim);
- goto out;
- }
- prim->data->conn.sk = sk;
+ goto out_put;
+ } else
+ sock_put(sk);
}
+ rc = -ENOMEM;
+ sk = prim->data->conn.sk;
sock_hold(sk);
- lock_sock(sk);
- /* assign new connection to it's SAP */
- llc_sap_assign_sock(sap, sk);
- llc = llc_sk(sk);
- memcpy(&llc->daddr, &daddr, sizeof(llc->daddr));
- memcpy(&llc->laddr, &laddr, sizeof(llc->laddr));
- llc->dev = ddev;
- llc->link = prim->data->conn.link;
- llc->handler = prim->data->conn.handler;
- skb = alloc_skb(1, GFP_ATOMIC);
+ skb = alloc_skb(0, GFP_ATOMIC);
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -359,15 +336,10 @@ static int llc_conn_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb);
}
- if (rc) {
- llc_sap_unassign_sock(sap, sk);
- llc_sock_free(sk);
+ if (rc)
llc_confirm_impossible(prim);
- }
- release_sock(sk);
out_put:
sock_put(sk);
-out:
return rc;
}
@@ -388,7 +360,6 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim)
struct sock* sk = prim->data->disc.sk;
sock_hold(sk);
- lock_sock(sk);
if (llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
goto out;
@@ -396,7 +367,7 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim)
* Postpone unassigning the connection from its SAP and returning the
* connection until all ACTIONs have been completely executed
*/
- skb = alloc_skb(1, GFP_ATOMIC);
+ skb = alloc_skb(0, GFP_ATOMIC);
if (!skb)
goto out;
ev = llc_conn_ev(skb);
@@ -406,7 +377,6 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb);
out:
- release_sock(sk);
sock_put(sk);
return rc;
}
@@ -426,8 +396,7 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim)
int rc = 1;
struct sock *sk = prim->data->res.sk;
- lock_sock(sk);
- skb = alloc_skb(1, GFP_ATOMIC);
+ skb = alloc_skb(0, GFP_ATOMIC);
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -437,7 +406,6 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb);
}
- release_sock(sk);
return rc;
}
@@ -498,7 +466,7 @@ static int llc_rst_rsp_handler(struct llc_prim_if_block *prim)
* package as event and send it to connection event handler
*/
struct sock *sk = prim->data->res.sk;
- struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
diff --git a/net/llc/llc_mac.c b/net/llc/llc_mac.c
index 0020b3801d6a..b8b031510043 100644
--- a/net/llc/llc_mac.c
+++ b/net/llc/llc_mac.c
@@ -27,7 +27,7 @@
#include <net/llc_s_ev.h>
#include <linux/trdevice.h>
-#if 1
+#if 0
#define dprintk(args...) printk(KERN_DEBUG args)
#else
#define dprintk(args...)
@@ -123,23 +123,30 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
sk = llc_lookup_established(sap, &saddr, &daddr);
if (!sk) {
+ struct llc_opt *llc;
+
+ dprintk("%s: llc_lookup_established failed\n", __FUNCTION__);
/*
* FIXME: here we'll pass the sk->family of the
* listening socket, if found, when
* llc_lookup_listener is added in the next patches.
*/
- sk = llc_sock_alloc(PF_LLC);
+ sk = llc_sk_alloc(PF_LLC, GFP_ATOMIC);
if (!sk)
goto drop;
- memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr));
+ llc = llc_sk(sk);
+ memcpy(&llc->laddr, &daddr, sizeof(llc->laddr));
+ memcpy(&llc->daddr, &saddr, sizeof(llc->daddr));
llc_sap_assign_sock(sap, sk);
sock_hold(sk);
}
skb->sk = sk;
bh_lock_sock(sk);
- if (!sk->lock.users)
- rc = llc_conn_rcv(sk, skb);
- else {
+ if (!sk->lock.users) {
+ /* rc = */ llc_conn_rcv(sk, skb);
+ rc = 0;
+ } else {
+ dprintk("%s: adding to backlog...\n", __FUNCTION__);
llc_set_backlog_type(skb, LLC_PACKET);
sk_add_backlog(sk, skb);
rc = 0;
diff --git a/net/llc/llc_main.c b/net/llc/llc_main.c
index fe24722bd45a..a1768084605b 100644
--- a/net/llc/llc_main.c
+++ b/net/llc/llc_main.c
@@ -52,6 +52,11 @@ static int llc_rtn_all_conns(struct llc_sap *sap);
static struct llc_station llc_main_station; /* only one of its kind */
+#undef LLC_REFCNT_DEBUG
+#ifdef LLC_REFCNT_DEBUG
+static atomic_t llc_sock_nr;
+#endif
+
/**
* llc_sap_alloc - allocates and initializes sap.
*
@@ -165,10 +170,12 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
}
/**
- * llc_sock_init - Initialize a socket with default llc values.
+ * llc_sk_init - Initializes a socket with default llc values.
* @sk: socket to intiailize.
+ *
+ * Initializes a socket with default llc values.
*/
-int llc_sock_init(struct sock* sk)
+int llc_sk_init(struct sock* sk)
{
struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
int rc = -ENOMEM;
@@ -198,61 +205,83 @@ out:
}
/**
- * __llc_sock_alloc - Allocates LLC sock
+ * llc_sk_alloc - Allocates LLC sock
* @family: upper layer protocol family
+ * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
*
* Allocates a LLC sock and initializes it. Returns the new LLC sock
* or %NULL if there's no memory available for one
*/
-struct sock *__llc_sock_alloc(int family)
+struct sock *llc_sk_alloc(int family, int priority)
{
- struct sock *sk = sk_alloc(family, GFP_ATOMIC, 1, NULL);
+ struct sock *sk = sk_alloc(family, priority, 1, NULL);
+ MOD_INC_USE_COUNT;
if (!sk)
- goto out;
- if (llc_sock_init(sk))
+ goto decmod;
+ if (llc_sk_init(sk))
goto outsk;
sock_init_data(NULL, sk);
+#ifdef LLC_REFCNT_DEBUG
+ atomic_inc(&llc_sock_nr);
+ printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
+ __FUNCTION__, atomic_read(&llc_sock_nr));
+#endif
out:
return sk;
outsk:
sk_free(sk);
sk = NULL;
+decmod:
+ MOD_DEC_USE_COUNT;
goto out;
}
/**
- * __llc_sock_free - Frees a LLC socket
+ * llc_sk_free - Frees a LLC socket
* @sk - socket to free
*
* Frees a LLC socket
*/
-void __llc_sock_free(struct sock *sk, u8 free)
+void llc_sk_free(struct sock *sk)
{
struct llc_opt *llc = llc_sk(sk);
llc->state = LLC_CONN_OUT_OF_SVC;
- /* stop all (possibly) running timers */
+ /* Stop all (possibly) running timers */
llc_conn_ac_stop_all_timers(sk, NULL);
#ifdef DEBUG_LLC_CONN_ALLOC
printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
skb_queue_len(&llc->pdu_unack_q),
skb_queue_len(&sk->write_queue));
#endif
+ skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&sk->write_queue);
skb_queue_purge(&llc->pdu_unack_q);
- if (free)
- sock_put(sk);
+#ifdef LLC_REFCNT_DEBUG
+ if (atomic_read(&sk->refcnt) != 1) {
+ printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
+ sk, __FUNCTION__, atomic_read(&sk->refcnt));
+ printk(KERN_DEBUG "%d LLC sockets are still alive\n",
+ atomic_read(&llc_sock_nr));
+ } else {
+ atomic_dec(&llc_sock_nr);
+ printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,
+ __FUNCTION__, atomic_read(&llc_sock_nr));
+ }
+#endif
+ sock_put(sk);
+ MOD_DEC_USE_COUNT;
}
/**
- * llc_sock_reset - resets a connection
+ * llc_sk_reset - resets a connection
* @sk: LLC socket to reset
*
* Resets a connection to the out of service state. Stops its timers
* and frees any frames in the queues of the connection.
*/
-void llc_sock_reset(struct sock *sk)
+void llc_sk_reset(struct sock *sk)
{
struct llc_opt *llc = llc_sk(sk);
@@ -585,7 +614,7 @@ static int __init llc_init(void)
skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock);
- skb = alloc_skb(1, GFP_ATOMIC);
+ skb = alloc_skb(0, GFP_ATOMIC);
if (!skb)
goto err;
llc_build_offset_table();
diff --git a/net/llc/llc_sock.c b/net/llc/llc_sock.c
index 0b2c3a9966d4..5753d316feaf 100644
--- a/net/llc/llc_sock.c
+++ b/net/llc/llc_sock.c
@@ -11,6 +11,7 @@
* connections.
*
* Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
+ * 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
@@ -57,6 +58,13 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim);
static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
static int llc_ui_wait_for_data(struct sock *sk, int timeout);
+static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout);
+
+#if 0
+#define dprintk(args...) printk(KERN_DEBUG args)
+#else
+#define dprintk(args...)
+#endif
/**
* llc_ui_next_link_no - return the next unused link number for a sap
@@ -130,7 +138,7 @@ static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap,
struct sockaddr_llc *addr,
struct net_device *dev, int link)
{
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
@@ -139,10 +147,9 @@ static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap,
prim.prim = LLC_CONN_PRIM;
prim_data.conn.dev = dev;
prim_data.conn.link = link;
- prim_data.conn.sk = NULL;
- prim_data.conn.handler = sk;
+ prim_data.conn.sk = sk;
prim_data.conn.pri = 0;
- prim_data.conn.saddr.lsap = llc_ui->addr.sllc_ssap;
+ prim_data.conn.saddr.lsap = llc->addr.sllc_ssap;
prim_data.conn.daddr.lsap = addr->sllc_dsap;
memcpy(prim_data.conn.saddr.mac, dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.conn.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
@@ -159,55 +166,50 @@ static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap,
*/
static int llc_ui_send_disc(struct sock *sk)
{
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
int rc = 0;
- if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
+ if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) {
+ rc = 1;
goto out;
+ }
sk->state = TCP_CLOSING;
prim.data = &prim_data;
- prim.sap = llc_ui->sap;
+ prim.sap = llc->sap;
prim.prim = LLC_DISC_PRIM;
- prim_data.disc.sk = llc_ui->core_sk;
- prim_data.disc.link = llc_ui->link;
- rc = llc_ui->sap->req(&prim);
+ prim_data.disc.sk = sk;
+ prim_data.disc.link = llc->link;
+ rc = llc->sap->req(&prim);
out:
return rc;
}
/**
* llc_ui_send_data - send data via reliable llc2 connection
- * @sap: Sap the socket is bound to.
* @sk: Connection the socket is using.
* @skb: Data the user wishes to send.
* @addr: Source and destination fields provided by the user.
+ * @noblock: can we block waiting for data?
*
* Send data via reliable llc2 connection.
- * Returns 0 upon success, non-zero if action did not succeed.
+ * Returns 0 upon success, non-zero if action did not succeed.
*/
-static int llc_ui_send_data(struct llc_sap *sap, struct sock* sk,
- struct sk_buff *skb, struct sockaddr_llc *addr)
+static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb,
+ struct sockaddr_llc *addr, int noblock)
{
- struct llc_ui_opt* llc_ui = llc_ui_sk(sk);
- struct llc_opt* llc_core = llc_sk(llc_ui->core_sk);
- int rc;
+ struct llc_opt* llc = llc_sk(sk);
+ int rc = 0;
skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd);
- sock_hold(sk);
-try:
- rc = llc_build_and_send_pkt(llc_ui->core_sk, skb);
- if (rc != -EBUSY)
- goto out;
- rc = wait_event_interruptible(sk->socket->wait, !llc_ui->core_sk ||
- !llc_core->failed_data_req);
+ if (llc_data_accept_state(llc->state) || llc->p_flag) {
+ int timeout = sock_sndtimeo(sk, noblock);
+
+ rc = llc_ui_wait_for_busy_core(sk, timeout);
+ }
if (!rc)
- goto try;
- if (!llc_ui->core_sk)
- rc = -ENOTCONN;
-out:
- sock_put(sk);
+ rc = llc_build_and_send_pkt(sk, skb);
return rc;
}
@@ -255,12 +257,12 @@ static __inline__ struct llc_sap *llc_ui_find_sap(u8 sap)
read_lock_bh(&llc_ui_sockets_lock);
for (sk = llc_ui_sockets; sk; sk = sk->next) {
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
- if (!llc_ui->sap)
+ if (!llc->sap)
continue;
- if (llc_ui->sap->laddr.lsap == sap) {
- s = llc_ui->sap;
+ if (llc->sap->laddr.lsap == sap) {
+ s = llc->sap;
break;
}
}
@@ -274,13 +276,13 @@ static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr,
struct sock *sk;
for (sk = llc_ui_sockets; sk; sk = sk->next) {
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
- if (llc_ui->addr.sllc_ssap == laddr->lsap &&
- llc_ui->addr.sllc_dsap == daddr->lsap &&
- llc_mac_null(llc_ui->addr.sllc_mmac) &&
- llc_mac_match(llc_ui->addr.sllc_smac, laddr->mac) &&
- llc_mac_match(llc_ui->addr.sllc_dmac, daddr->mac))
+ if (llc->addr.sllc_ssap == laddr->lsap &&
+ llc->addr.sllc_dsap == daddr->lsap &&
+ llc_mac_null(llc->addr.sllc_mmac) &&
+ llc_mac_match(llc->addr.sllc_smac, laddr->mac) &&
+ llc_mac_match(llc->addr.sllc_dmac, daddr->mac))
break;
}
return sk;
@@ -303,31 +305,31 @@ static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr,
struct sock *sk, *tmp_sk;
for (sk = llc_ui_sockets; sk; sk = sk->next) {
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
- if (llc_ui->addr.sllc_ssap != laddr->lsap)
+ if (llc->addr.sllc_ssap != laddr->lsap)
continue;
- if (llc_mac_null(llc_ui->addr.sllc_smac)) {
- if (!llc_mac_null(llc_ui->addr.sllc_mmac) &&
- !llc_mac_match(llc_ui->addr.sllc_mmac,
- laddr->mac))
+ if (llc_mac_null(llc->addr.sllc_smac)) {
+ if (!llc_mac_null(llc->addr.sllc_mmac) &&
+ !llc_mac_match(llc->addr.sllc_mmac,
+ laddr->mac))
continue;
break;
}
- if (dev && !llc_mac_null(llc_ui->addr.sllc_mmac) &&
- llc_mac_match(llc_ui->addr.sllc_mmac, laddr->mac) &&
- llc_mac_match(llc_ui->addr.sllc_smac, dev->dev_addr))
+ if (dev && !llc_mac_null(llc->addr.sllc_mmac) &&
+ llc_mac_match(llc->addr.sllc_mmac, laddr->mac) &&
+ llc_mac_match(llc->addr.sllc_smac, dev->dev_addr))
break;
if (dev->flags & IFF_LOOPBACK)
break;
- if (!llc_mac_match(llc_ui->addr.sllc_smac, laddr->mac))
+ if (!llc_mac_match(llc->addr.sllc_smac, laddr->mac))
continue;
tmp_sk = __llc_ui_find_sk_by_exact(laddr, daddr);
if (tmp_sk) {
sk = tmp_sk;
break;
}
- if (llc_mac_null(llc_ui->addr.sllc_dmac))
+ if (llc_mac_null(llc->addr.sllc_dmac))
break;
}
return sk;
@@ -393,7 +395,8 @@ static __inline__ void llc_ui_remove_socket(struct sock *sk)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
- /* this only makes sense if the socket was inserted on the
+ /*
+ * This only makes sense if the socket was inserted on the
* list, if sk->pprev is NULL it wasn't
*/
sock_put(sk);
@@ -401,38 +404,13 @@ static __inline__ void llc_ui_remove_socket(struct sock *sk)
write_unlock_bh(&llc_ui_sockets_lock);
}
-/**
- * llc_ui_destroy_sk - destroy socket
- * @data: Socket which is to be destroyed.
- *
- * Really destroy the socket.
- */
-static void llc_ui_destroy_sk(struct sock *sk)
-{
- skb_queue_purge(&sk->receive_queue);
- skb_queue_purge(&sk->write_queue);
- sock_put(sk);
- MOD_DEC_USE_COUNT;
-}
-
-/**
- * llc_ui_destroy_timer - try to destroy socket again
- * @data: Socket which is to be destroyed.
- *
- * Attempt to destroy a socket which was previously destroyed but
- * was still in use at the time.
- */
-static void llc_ui_destroy_timer(unsigned long data)
+static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
{
- struct sock *sk = (struct sock *)data;
-
- if (!atomic_read(&sk->wmem_alloc) &&
- !atomic_read(&sk->rmem_alloc) && sk->dead)
- llc_ui_destroy_sk(sk);
- else {
- sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
- add_timer(&sk->timer);
- }
+ sk->type = sock->type;
+ sk->sleep = &sock->wait;
+ sk->socket = sock;
+ sock->sk = sk;
+ sock->ops = &llc_ui_ops;
}
/**
@@ -447,31 +425,17 @@ static void llc_ui_destroy_timer(unsigned long data)
static int llc_ui_create(struct socket *sock, int protocol)
{
struct sock *sk;
- struct llc_ui_opt *llc_ui;
int rc = -ESOCKTNOSUPPORT;
- MOD_INC_USE_COUNT;
- if (sock->type != SOCK_DGRAM && sock->type != SOCK_STREAM)
- goto decmod;
- rc = -ENOMEM;
- sk = sk_alloc(PF_LLC, GFP_KERNEL, 1, NULL);
- if (!sk)
- goto decmod;
- llc_ui = kmalloc(sizeof(*llc_ui), GFP_KERNEL);
- if (!llc_ui)
- goto outsk;
- memset(llc_ui, 0, sizeof(*llc_ui));
- rc = 0;
- sock_init_data(sock, sk);
- llc_ui_sk(sk) = llc_ui;
- sock->ops = &llc_ui_ops;
-out:
+ if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) {
+ rc = -ENOMEM;
+ sk = llc_sk_alloc(PF_LLC, GFP_KERNEL);
+ if (sk) {
+ rc = 0;
+ llc_ui_sk_init(sock, sk);
+ }
+ }
return rc;
-outsk:
- sk_free(sk);
-decmod:
- MOD_DEC_USE_COUNT;
- goto out;
}
/**
@@ -483,33 +447,25 @@ decmod:
static int llc_ui_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui;
+ struct llc_opt *llc;
if (!sk)
goto out;
sock_hold(sk);
lock_sock(sk);
- llc_ui = llc_ui_sk(sk);
- if (llc_ui->core_sk && !llc_ui_send_disc(sk))
+ llc = llc_sk(sk);
+ dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
+ llc->laddr.lsap, llc->daddr.lsap);
+ if (!llc_ui_send_disc(sk))
llc_ui_wait_for_disc(sk, sk->rcvtimeo);
- llc_ui_remove_socket(sk);
+ llc_sap_unassign_sock(llc->sap, sk);
release_sock(sk);
+ llc_ui_remove_socket(sk);
- if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap))
- llc_sap_close(llc_ui->sap);
- sock_orphan(sk);
- sock->sk = NULL;
- if (!atomic_read(&sk->wmem_alloc) &&
- !atomic_read(&sk->rmem_alloc) && sk->dead)
- llc_ui_destroy_sk(sk);
- else {
- init_timer(&sk->timer);
- sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
- sk->timer.function = llc_ui_destroy_timer;
- sk->timer.data = (unsigned long)sk;
- add_timer(&sk->timer);
- }
+ if (llc->sap && list_empty(&llc->sap->sk_list.list))
+ llc_sap_close(llc->sap);
sock_put(sk);
+ llc_sk_free(sk);
out:
return 0;
}
@@ -563,7 +519,7 @@ out:
static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
{
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap;
struct net_device *dev = NULL;
int rc = -EINVAL;
@@ -578,7 +534,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
rc = -ENETUNREACH;
if (!dev)
goto out;
- llc_ui->dev = dev;
+ llc->dev = dev;
}
/* bind to a specific sap, optional. */
if (!addr->sllc_ssap) {
@@ -619,10 +575,15 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
goto out;
}
}
- memcpy(&llc_ui->addr, addr, sizeof(*addr));
- llc_ui->sap = sap;
+ llc->laddr.lsap = addr->sllc_ssap;
+ memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
+ llc->daddr.lsap = addr->sllc_dsap;
+ memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
+ memcpy(&llc->addr, addr, sizeof(llc->addr));
rc = sk->zapped = 0;
llc_ui_insert_socket(sk);
+ /* assign new connection to it's SAP */
+ llc_sap_assign_sock(sap, sk);
out:
return rc;
}
@@ -651,6 +612,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
struct sock *sk = sock->sk;
int rc = -EINVAL;
+ dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap);
if (!sk->zapped || addrlen != sizeof(*addr))
goto out;
rc = -EAFNOSUPPORT;
@@ -686,7 +648,7 @@ static int llc_ui_shutdown(struct socket *sock, int how)
goto out;
rc = llc_ui_send_disc(sk);
if (!rc)
- llc_ui_wait_for_disc(sk, sk->rcvtimeo);
+ rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo);
/* Wake up anyone sleeping in poll */
sk->state_change(sk);
out:
@@ -712,7 +674,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
int addrlen, int flags)
{
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
struct net_device *dev;
int rc = -EINVAL;
@@ -730,14 +692,15 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
if (rc)
goto out;
}
- if (!llc_ui->dev) {
+ if (!llc->dev) {
rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock();
if (!dev)
goto out;
+ llc->dev = dev;
} else
- dev = llc_ui->dev;
+ dev = llc->dev;
if (sk->type != SOCK_STREAM)
goto out;
rc = -EALREADY;
@@ -745,14 +708,17 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
goto out;
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
- llc_ui->link = llc_ui_next_link_no(llc_ui->sap->laddr.lsap);
- rc = llc_ui_send_conn(sk, llc_ui->sap, addr, dev, llc_ui->link);
+ llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap);
+ rc = llc_ui_send_conn(sk, llc->sap, addr, dev, llc->link);
if (rc) {
+ dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
sock->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
goto out;
}
rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
+ if (rc)
+ dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc);
out:
release_sock(sk);
return rc;
@@ -802,6 +768,12 @@ static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
+ rc = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+ rc = -EAGAIN;
+ if (!timeout)
+ break;
rc = 0;
if (sk->state != TCP_CLOSE) {
release_sock(sk);
@@ -809,12 +781,6 @@ static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
lock_sock(sk);
} else
break;
- rc = -ERESTARTSYS;
- if (signal_pending(current))
- break;
- rc = -EAGAIN;
- if (!timeout)
- break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
@@ -823,23 +789,12 @@ static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
{
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
DECLARE_WAITQUEUE(wait, current);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
- rc = 0;
- if (sk->state != TCP_ESTABLISHED) {
- release_sock(sk);
- timeout = schedule_timeout(timeout);
- lock_sock(sk);
- } else {
- if (!llc_ui->core_sk)
- rc = -EAGAIN;
- break;
- }
rc = -EAGAIN;
if (sk->state == TCP_CLOSE)
break;
@@ -849,6 +804,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
rc = -EAGAIN;
if (!timeout)
break;
+ rc = 0;
+ if (sk->state != TCP_ESTABLISHED) {
+ release_sock(sk);
+ timeout = schedule_timeout(timeout);
+ lock_sock(sk);
+ } else
+ break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
@@ -858,11 +820,19 @@ static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
static int llc_ui_wait_for_data(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
- int rc;
+ int rc = 0;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
+ if (sk->shutdown & RCV_SHUTDOWN)
+ break;
+ rc = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+ rc = -EAGAIN;
+ if (!timeout)
+ break;
rc = 0;
if (skb_queue_empty(&sk->receive_queue)) {
release_sock(sk);
@@ -870,12 +840,38 @@ static int llc_ui_wait_for_data(struct sock *sk, int timeout)
lock_sock(sk);
} else
break;
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk->sleep, &wait);
+ return rc;
+}
+
+static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct llc_opt *llc = llc_sk(sk);
+ int rc;
+
+ add_wait_queue_exclusive(sk->sleep, &wait);
+ for (;;) {
+ dprintk("%s: looping...\n", __FUNCTION__);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ rc = -ENOTCONN;
+ if (sk->shutdown & RCV_SHUTDOWN)
+ break;
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
+ rc = 0;
+ if (llc_data_accept_state(llc->state) || llc->p_flag) {
+ release_sock(sk);
+ timeout = schedule_timeout(timeout);
+ lock_sock(sk);
+ } else
+ break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
@@ -894,11 +890,11 @@ static int llc_ui_wait_for_data(struct sock *sk, int timeout)
static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk = sock->sk, *newsk;
- struct llc_ui_opt *llc_ui, *newllc_ui;
- struct llc_opt *newllc_core;
+ struct llc_opt *llc, *newllc;
struct sk_buff *skb;
int rc = -EOPNOTSUPP;
+ dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
lock_sock(sk);
if (sk->type != SOCK_STREAM)
goto out;
@@ -909,40 +905,32 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
rc = llc_ui_wait_for_data(sk, sk->rcvtimeo);
if (rc)
goto out;
+ dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
skb = skb_dequeue(&sk->receive_queue);
-
rc = -EINVAL;
if (!skb->sk)
goto frees;
- /* attach connection to a new socket. */
- rc = llc_ui_create(newsock, sk->protocol);
- if (rc)
- goto frees;
rc = 0;
- newsk = newsock->sk;
+ newsk = skb->sk;
+ /* attach connection to a new socket. */
+ llc_ui_sk_init(newsock, newsk);
newsk->pair = NULL;
- newsk->socket = newsock;
- newsk->sleep = &newsock->wait;
newsk->zapped = 0;
newsk->state = TCP_ESTABLISHED;
newsock->state = SS_CONNECTED;
- llc_ui = llc_ui_sk(sk);
- newllc_ui = llc_ui_sk(newsk);
- newllc_ui->sap = llc_ui->sap;
- newllc_ui->dev = llc_ui->dev;
- newllc_ui->core_sk = skb->sk;
- newllc_core = llc_sk(newllc_ui->core_sk);
- newllc_ui->link = newllc_core->link;
- newllc_core->handler = newsk;
- memcpy(&newllc_ui->addr, &llc_ui->addr, sizeof(newllc_ui->addr));
- memcpy(newllc_ui->addr.sllc_dmac, newllc_core->daddr.mac, IFHWADDRLEN);
- newllc_ui->addr.sllc_dsap = newllc_core->daddr.lsap;
+ llc = llc_sk(sk);
+ newllc = llc_sk(newsk);
+ memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));
+ memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
+ newllc->addr.sllc_dsap = newllc->daddr.lsap;
/* put original socket back into a clean listen state. */
sk->state = TCP_LISTEN;
sk->ack_backlog--;
llc_ui_insert_socket(newsk);
skb->sk = NULL;
+ dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
+ llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap);
frees:
kfree_skb(skb);
out:
@@ -967,12 +955,21 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
struct sock *sk = sock->sk;
struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
struct sk_buff *skb;
- int rc = -ENOMEM, copied = 0;
+ int rc = -ENOMEM, copied = 0, timeout;
int noblock = flags & MSG_DONTWAIT;
+ dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,
+ llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
lock_sock(sk);
- skb = skb_recv_datagram(sk, flags, noblock, &rc);
- if (!skb)
+ timeout = sock_rcvtimeo(sk, noblock);
+ rc = llc_ui_wait_for_data(sk, timeout);
+ if (rc) {
+ dprintk("%s: llc_ui_wait_for_data failed recv in %02X from %02X\n",
+ __FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
+ goto out;
+ }
+ skb = skb_dequeue(&sk->receive_queue);
+ if (!skb) /* shutdown */
goto out;
copied = skb->len;
if (copied > size) {
@@ -986,7 +983,7 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
msg->msg_namelen = sizeof(*uaddr);
dgram_free:
- skb_free_datagram(sk, skb); /* Free the datagram. */
+ kfree_skb(skb);
out:
release_sock(sk);
return rc ? : copied;
@@ -1006,24 +1003,23 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
int flags = msg->msg_flags;
+ int noblock = flags & MSG_DONTWAIT;
struct net_device *dev;
struct sk_buff *skb;
- int rc = -EOPNOTSUPP, size = 0;
+ int rc = -EINVAL, size = 0;
+ dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
lock_sock(sk);
- if (flags & ~MSG_DONTWAIT)
- goto release;
- rc = -EINVAL;
if (addr) {
if (msg->msg_namelen < sizeof(*addr))
goto release;
} else {
- if (llc_ui_addr_null(&llc_ui->addr))
+ if (llc_ui_addr_null(&llc->addr))
goto release;
- addr = &llc_ui->addr;
+ addr = &llc->addr;
}
/* must bind connection to sap if user hasn't done it. */
if (sk->zapped) {
@@ -1032,7 +1028,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (rc)
goto release;
}
- if (!llc_ui->dev) {
+ if (!llc->dev) {
rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock();
@@ -1040,12 +1036,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (!dev)
goto release;
} else
- dev = llc_ui->dev;
+ dev = llc->dev;
size = dev->hard_header_len + len + llc_ui_header_len(sk, addr);
rc = -EMSGSIZE;
if (size > dev->mtu)
goto release;
- skb = sock_alloc_send_skb(sk, size, flags & MSG_DONTWAIT, &rc);
+ skb = sock_alloc_send_skb(sk, size, noblock, &rc);
if (!skb)
goto release;
skb->sk = sk;
@@ -1053,30 +1049,32 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr));
rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (rc)
- goto release;
+ goto out;
if (addr->sllc_test) {
- rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_TEST_PRIM);
+ rc = llc_ui_send_llc1(llc->sap, skb, addr, LLC_TEST_PRIM);
goto out;
}
if (addr->sllc_xid) {
- rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_XID_PRIM);
+ rc = llc_ui_send_llc1(llc->sap, skb, addr, LLC_XID_PRIM);
goto out;
}
if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
- rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_DATAUNIT_PRIM);
+ rc = llc_ui_send_llc1(llc->sap, skb, addr, LLC_DATAUNIT_PRIM);
goto out;
}
rc = -ENOPROTOOPT;
if (!(sk->type == SOCK_STREAM && !addr->sllc_ua))
goto out;
- rc = -ENOTCONN;
- if (!llc_ui->core_sk)
- goto out;
- rc = llc_ui_send_data(llc_ui->sap, sk, skb, addr);
+ rc = llc_ui_send_data(sk, skb, addr, noblock);
+ if (rc)
+ dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc);
out:
if (rc)
- skb_free_datagram(sk, skb);
+ 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 ? : len;
}
@@ -1095,7 +1093,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
{
struct sockaddr_llc sllc;
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct llc_opt *llc = llc_sk(sk);
int rc = 0;
lock_sock(sk);
@@ -1107,20 +1105,19 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED)
goto out;
- if(llc_ui->dev)
- sllc.sllc_arphrd = llc_ui->dev->type;
- sllc.sllc_dsap = llc_sk(llc_ui->core_sk)->daddr.lsap;
- memcpy(&sllc.sllc_dmac, &llc_sk(llc_ui->core_sk)->daddr.mac,
- IFHWADDRLEN);
+ if(llc->dev)
+ sllc.sllc_arphrd = llc->dev->type;
+ sllc.sllc_dsap = llc->daddr.lsap;
+ memcpy(&sllc.sllc_dmac, &llc->daddr.mac, IFHWADDRLEN);
} else {
rc = -EINVAL;
- if (!llc_ui->sap)
+ if (!llc->sap)
goto out;
- sllc.sllc_ssap = llc_ui->sap->laddr.lsap;
+ sllc.sllc_ssap = llc->sap->laddr.lsap;
- if (llc_ui->dev) {
- sllc.sllc_arphrd = llc_ui->dev->type;
- memcpy(&sllc.sllc_smac, &llc_ui->dev->dev_addr,
+ if (llc->dev) {
+ sllc.sllc_arphrd = llc->dev->type;
+ memcpy(&sllc.sllc_smac, &llc->dev->dev_addr,
IFHWADDRLEN);
}
}
@@ -1160,61 +1157,56 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
- struct llc_opt *llc_core;
+ struct llc_opt *llc = llc_sk(sk);
int rc = -EINVAL, opt;
lock_sock(sk);
if (level != SOL_LLC || optlen != sizeof(int))
goto out;
- rc = -ENOTCONN;
- if (!llc_ui->core_sk)
- goto out;
rc = get_user(opt, (int *)optval);
if (rc)
goto out;
rc = -EINVAL;
- llc_core = llc_sk(llc_ui->core_sk);
switch (optname) {
case LLC_OPT_RETRY:
if (opt > LLC_OPT_MAX_RETRY)
goto out;
- llc_core->n2 = opt;
+ llc->n2 = opt;
break;
case LLC_OPT_SIZE:
if (opt > LLC_OPT_MAX_SIZE)
goto out;
- llc_core->n1 = opt;
+ llc->n1 = opt;
break;
case LLC_OPT_ACK_TMR_EXP:
if (opt > LLC_OPT_MAX_ACK_TMR_EXP)
goto out;
- llc_core->ack_timer.expire = opt;
+ llc->ack_timer.expire = opt;
break;
case LLC_OPT_P_TMR_EXP:
if (opt > LLC_OPT_MAX_P_TMR_EXP)
goto out;
- llc_core->pf_cycle_timer.expire = opt;
+ llc->pf_cycle_timer.expire = opt;
break;
case LLC_OPT_REJ_TMR_EXP:
if (opt > LLC_OPT_MAX_REJ_TMR_EXP)
goto out;
- llc_core->rej_sent_timer.expire = opt;
+ llc->rej_sent_timer.expire = opt;
break;
case LLC_OPT_BUSY_TMR_EXP:
if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
goto out;
- llc_core->busy_state_timer.expire = opt;
+ llc->busy_state_timer.expire = opt;
break;
case LLC_OPT_TX_WIN:
if (opt > LLC_OPT_MAX_WIN)
goto out;
- llc_core->k = opt;
+ llc->k = opt;
break;
case LLC_OPT_RX_WIN:
if (opt > LLC_OPT_MAX_WIN)
goto out;
- llc_core->rw = opt;
+ llc->rw = opt;
break;
default:
rc = -ENOPROTOOPT;
@@ -1240,40 +1232,35 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
struct sock *sk = sock->sk;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
- struct llc_opt *llc_core;
+ struct llc_opt *llc = llc_sk(sk);
int val = 0, len = 0, rc = -EINVAL;
lock_sock(sk);
if (level != SOL_LLC)
goto out;
- rc = -ENOTCONN;
- if (!llc_ui->core_sk)
- goto out;
rc = get_user(len, optlen);
if (rc)
goto out;
rc = -EINVAL;
if (len != sizeof(int))
goto out;
- llc_core = llc_sk(llc_ui->core_sk);
switch (optname) {
case LLC_OPT_RETRY:
- val = llc_core->n2; break;
+ val = llc->n2; break;
case LLC_OPT_SIZE:
- val = llc_core->n1; break;
+ val = llc->n1; break;
case LLC_OPT_ACK_TMR_EXP:
- val = llc_core->ack_timer.expire; break;
+ val = llc->ack_timer.expire; break;
case LLC_OPT_P_TMR_EXP:
- val = llc_core->pf_cycle_timer.expire; break;
+ val = llc->pf_cycle_timer.expire; break;
case LLC_OPT_REJ_TMR_EXP:
- val = llc_core->rej_sent_timer.expire; break;
+ val = llc->rej_sent_timer.expire; break;
case LLC_OPT_BUSY_TMR_EXP:
- val = llc_core->busy_state_timer.expire; break;
+ val = llc->busy_state_timer.expire; break;
case LLC_OPT_TX_WIN:
- val = llc_core->k; break;
+ val = llc->k; break;
case LLC_OPT_RX_WIN:
- val = llc_core->rw; break;
+ val = llc->rw; break;
default:
rc = -ENOPROTOOPT;
goto out;
@@ -1296,7 +1283,7 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim)
{
struct llc_prim_test *prim_data = &prim->data->test;
struct sk_buff *skb = prim_data->skb;
- struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
+ struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev);
if (!sk)
@@ -1304,15 +1291,15 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim)
if (sk->state == TCP_LISTEN)
goto out_put;
/* save primitive for use by the user. */
- llc_ui->sllc_family = AF_LLC;
- llc_ui->sllc_arphrd = skb->dev->type;
- llc_ui->sllc_test = 1;
- llc_ui->sllc_xid = 0;
- llc_ui->sllc_ua = 0;
- llc_ui->sllc_dsap = prim_data->daddr.lsap;
- memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
- llc_ui->sllc_ssap = prim_data->saddr.lsap;
- memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
+ addr->sllc_family = AF_LLC;
+ addr->sllc_arphrd = skb->dev->type;
+ addr->sllc_test = 1;
+ addr->sllc_xid = 0;
+ addr->sllc_ua = 0;
+ addr->sllc_dsap = prim_data->daddr.lsap;
+ memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
+ addr->sllc_ssap = prim_data->saddr.lsap;
+ memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
@@ -1331,7 +1318,7 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
{
struct llc_prim_xid *prim_data = &prim->data->xid;
struct sk_buff *skb = prim_data->skb;
- struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
+ struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev);
if (!sk)
@@ -1339,15 +1326,15 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
if (sk->state == TCP_LISTEN)
goto out_put;
/* save primitive for use by the user. */
- llc_ui->sllc_family = AF_LLC;
- llc_ui->sllc_arphrd = 0;
- llc_ui->sllc_test = 0;
- llc_ui->sllc_xid = 1;
- llc_ui->sllc_ua = 0;
- llc_ui->sllc_dsap = prim_data->daddr.lsap;
- memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
- llc_ui->sllc_ssap = prim_data->saddr.lsap;
- memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
+ addr->sllc_family = AF_LLC;
+ addr->sllc_arphrd = 0;
+ addr->sllc_test = 0;
+ addr->sllc_xid = 1;
+ addr->sllc_ua = 0;
+ addr->sllc_dsap = prim_data->daddr.lsap;
+ memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
+ addr->sllc_ssap = prim_data->saddr.lsap;
+ memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
@@ -1366,7 +1353,7 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
{
struct llc_prim_unit_data *prim_data = &prim->data->udata;
struct sk_buff *skb = prim_data->skb;
- struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
+ struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev);
if (!sk)
@@ -1374,15 +1361,15 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
if (sk->state == TCP_LISTEN)
goto out_put;
/* save primitive for use by the user. */
- llc_ui->sllc_family = AF_LLC;
- llc_ui->sllc_arphrd = skb->dev->type;
- llc_ui->sllc_test = 0;
- llc_ui->sllc_xid = 0;
- llc_ui->sllc_ua = 1;
- llc_ui->sllc_dsap = prim_data->daddr.lsap;
- memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
- llc_ui->sllc_ssap = prim_data->saddr.lsap;
- memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
+ addr->sllc_family = AF_LLC;
+ addr->sllc_arphrd = skb->dev->type;
+ addr->sllc_test = 0;
+ addr->sllc_xid = 0;
+ addr->sllc_ua = 1;
+ addr->sllc_dsap = prim_data->daddr.lsap;
+ memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
+ addr->sllc_ssap = prim_data->saddr.lsap;
+ memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
@@ -1400,29 +1387,36 @@ out:;
static void llc_ui_ind_conn(struct llc_prim_if_block *prim)
{
struct llc_prim_conn *prim_data = &prim->data->conn;
- struct sock* sk;
+ struct sock* newsk = prim_data->sk, *parent;
+ struct llc_opt *newllc = llc_sk(newsk);
struct sk_buff *skb2;
- llc_sk(prim_data->sk)->laddr.lsap = prim->sap->laddr.lsap;
- sk = llc_ui_find_sk_by_addr(&llc_sk(prim_data->sk)->laddr,
- &prim_data->saddr, prim_data->dev);
- if (!sk)
+ parent = llc_ui_find_sk_by_addr(&newllc->laddr, &prim_data->saddr,
+ prim_data->dev);
+ if (!parent) {
+ dprintk("%s: can't find a parent :-(\n", __FUNCTION__);
goto out;
- if (sk->type != SOCK_STREAM || sk->state != TCP_LISTEN)
+ }
+ dprintk("%s: found parent of remote %02X, its local %02X\n", __FUNCTION__,
+ newllc->daddr.lsap, llc_sk(parent)->laddr.lsap);
+ if (parent->type != SOCK_STREAM || parent->state != TCP_LISTEN) {
+ dprintk("%s: bad parent :-(\n", __FUNCTION__);
goto out_put;
- if (prim->data->conn.status)
+ }
+ if (prim->data->conn.status) {
+ dprintk("%s: bad status :-(\n", __FUNCTION__);
goto out_put; /* bad status. */
+ }
/* give this connection a link number. */
- llc_sk(prim_data->sk)->link =
- llc_ui_next_link_no(llc_sk(prim_data->sk)->laddr.lsap);
+ newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
skb2 = alloc_skb(0, GFP_ATOMIC);
if (!skb2)
goto out_put;
- skb2->sk = prim_data->sk;
- skb_queue_tail(&sk->receive_queue, skb2);
- sk->state_change(sk);
+ skb2->sk = newsk;
+ skb_queue_tail(&parent->receive_queue, skb2);
+ parent->state_change(parent);
out_put:
- sock_put(sk);
+ sock_put(parent);
out:;
}
@@ -1435,14 +1429,13 @@ out:;
static void llc_ui_ind_disc(struct llc_prim_if_block *prim)
{
struct llc_prim_disc *prim_data = &prim->data->disc;
- struct sock* sk = llc_sk(prim_data->sk)->handler;
+ struct sock* sk = prim_data->sk;
- if (!sk)
- goto out;
sock_hold(sk);
- if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
+ if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) {
+ dprintk("%s: bad socket...\n", __FUNCTION__);
goto out_put;
- llc_ui_sk(sk)->core_sk = NULL;
+ }
sk->shutdown = SHUTDOWN_MASK;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
@@ -1452,7 +1445,6 @@ static void llc_ui_ind_disc(struct llc_prim_if_block *prim)
}
out_put:
sock_put(sk);
-out:;
}
/**
@@ -1475,8 +1467,8 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
case LLC_CONN_PRIM:
llc_ui_ind_conn(prim); break;
case LLC_DATA_PRIM:
- printk(KERN_ERR "%s: shouldn't happen, LLC_DATA_PRIM "
- "is gone for ->ind()...\n", __FUNCTION__);
+ dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
+ "is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM:
llc_ui_ind_disc(prim); break;
@@ -1496,28 +1488,21 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
static void llc_ui_conf_conn(struct llc_prim_if_block *prim)
{
struct llc_prim_conn *prim_data = &prim->data->conn;
- struct llc_opt *llc_core = llc_sk(prim_data->sk);
- struct sock* sk = llc_core->handler;
- struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+ struct sock* sk = prim_data->sk;
- if (!sk)
- goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
goto out_put;
if (!prim->data->conn.status) {
sk->socket->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
- llc_ui->core_sk = prim_data->sk;
} else {
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
- llc_ui->core_sk = NULL;
}
sk->state_change(sk);
out_put:
sock_put(sk);
-out:;
}
/**
@@ -1529,20 +1514,16 @@ out:;
static void llc_ui_conf_disc(struct llc_prim_if_block *prim)
{
struct llc_prim_disc *prim_data = &prim->data->disc;
- struct sock* sk = llc_sk(prim_data->sk)->handler;
+ struct sock* sk = prim_data->sk;
- if (!sk)
- goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING)
goto out_put;
- llc_ui_sk(sk)->core_sk = NULL;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
sk->state_change(sk);
out_put:
sock_put(sk);
-out:;
}
/**
@@ -1559,8 +1540,8 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim)
case LLC_CONN_PRIM:
llc_ui_conf_conn(prim); break;
case LLC_DATA_PRIM:
- printk(KERN_ERR "%s: shouldn't happen, LLC_DATA_PRIM "
- "is gone for ->conf()...\n", __FUNCTION__);
+ dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
+ "is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM:
llc_ui_conf_disc(prim); break;
@@ -1596,46 +1577,42 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
struct sock *s;
- int len = sprintf(buffer, "SocketID SKt Mc local_mac_sap\t "
- "remote_mac_sap\t tx_queue rx_queue st uid "
- "link_no\n");
+ int len = sprintf(buffer, "SKt Mc local_mac_sap "
+ "remote_mac_sap tx_queue rx_queue st uid "
+ "link\n");
/* Output the LLC socket data for the /proc filesystem */
read_lock_bh(&llc_ui_sockets_lock);
for (s = llc_ui_sockets; s; s = s->next) {
- struct llc_ui_opt *llc_ui = llc_ui_sk(s);
- len += sprintf(buffer + len, "%p %02X %02X ", s, s->type,
- !llc_mac_null(llc_ui->addr.sllc_mmac));
- if (llc_ui->sap) {
- if (llc_ui->dev &&
- llc_mac_null(llc_ui->addr.sllc_mmac))
+ struct llc_opt *llc = llc_sk(s);
+
+ len += sprintf(buffer + len, "%2X %2X ", s->type,
+ !llc_mac_null(llc->addr.sllc_mmac));
+ if (llc->sap) {
+ if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
llc_ui_format_mac(buffer + len,
- llc_ui->dev->dev_addr);
+ llc->dev->dev_addr);
else {
- if (!llc_mac_null(llc_ui->addr.sllc_mmac))
+ if (!llc_mac_null(llc->addr.sllc_mmac))
llc_ui_format_mac(buffer + len,
- llc_ui->addr.sllc_mmac);
+ llc->addr.sllc_mmac);
else
sprintf(buffer + len,
"00:00:00:00:00:00");
}
len += MAC_FORMATTED_SIZE;
len += sprintf(buffer + len, "@%02X ",
- llc_ui->sap->laddr.lsap);
+ llc->sap->laddr.lsap);
} else
len += sprintf(buffer + len, "00:00:00:00:00:00@00 ");
- llc_ui_format_mac(buffer + len, llc_ui->addr.sllc_dmac);
+ llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac);
len += MAC_FORMATTED_SIZE;
len += sprintf(buffer + len,
- "@%02X %08d:%08d %02d %-3d ",
- llc_ui->addr.sllc_dsap,
+ "@%02X %8d %8d %2d %-3d ",
+ llc->addr.sllc_dsap,
atomic_read(&s->wmem_alloc),
atomic_read(&s->rmem_alloc), s->state,
SOCK_INODE(s->socket)->i_uid);
- if (llc_ui->core_sk)
- len += sprintf(buffer + len, "%-7d\n",
- llc_sk(llc_ui->core_sk)->link);
- else
- len += sprintf(buffer + len, "no_link\n");
+ len += sprintf(buffer + len, "%-4d\n", llc->link);
/* Are we still dumping unwanted data then discard the record */
pos = begin + len;
@@ -1686,7 +1663,7 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = {
SOCKOPS_WRAP(llc_ui, PF_LLC);
static char llc_ui_banner[] __initdata =
- KERN_INFO "NET4.0 IEEE 802.2 User Interface SAPs, Jay Schulist, 2001\n";
+ KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n";
int __init llc_ui_init(void)
{