[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.
parent ebf9bc77
...@@ -78,17 +78,6 @@ enum llc_sockopts { ...@@ -78,17 +78,6 @@ enum llc_sockopts {
#define LLC_SAP_DYN_STOP 0xDE #define LLC_SAP_DYN_STOP 0xDE
#define LLC_SAP_DYN_TRIES 4 #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])) #define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0]))
#ifdef CONFIG_LLC_UI #ifdef CONFIG_LLC_UI
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define LLC_CONN_H #define LLC_CONN_H
/* /*
* Copyright (c) 1997 by Procom Technology, Inc. * 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 * This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation. * GNU General Public License as published by the Free Software Foundation.
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
*/ */
#include <linux/timer.h> #include <linux/timer.h>
#include <net/llc_if.h> #include <net/llc_if.h>
#include <linux/llc.h>
#define DEBUG_LLC_CONN_ALLOC
struct llc_timer { struct llc_timer {
struct timer_list timer; struct timer_list timer;
...@@ -25,7 +24,7 @@ struct llc_timer { ...@@ -25,7 +24,7 @@ struct llc_timer {
struct llc_opt { struct llc_opt {
struct list_head node; /* entry in sap->sk_list.list */ struct list_head node; /* entry in sap->sk_list.list */
struct sock *sk; /* sock that has this llc_opt */ 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 */ u8 state; /* state of connection */
struct llc_sap *sap; /* pointer to parent SAP */ struct llc_sap *sap; /* pointer to parent SAP */
struct llc_addr laddr; /* lsap/mac pair */ struct llc_addr laddr; /* lsap/mac pair */
...@@ -80,60 +79,11 @@ struct llc_opt { ...@@ -80,60 +79,11 @@ struct llc_opt {
struct llc_conn_state_ev; struct llc_conn_state_ev;
extern struct sock *__llc_sock_alloc(int family); extern struct sock *llc_sk_alloc(int family, int priority);
extern void __llc_sock_free(struct sock *sk, u8 free); extern void llc_sk_free(struct sock *sk);
#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 void llc_sock_reset(struct sock *sk); extern void llc_sk_reset(struct sock *sk);
extern int llc_sock_init(struct sock *sk); extern int llc_sk_init(struct sock *sk);
/* Access to a connection */ /* Access to a connection */
extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb); extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb);
......
...@@ -73,8 +73,6 @@ struct llc_prim_conn { ...@@ -73,8 +73,6 @@ struct llc_prim_conn {
u8 pri; /* service_class */ u8 pri; /* service_class */
struct net_device *dev; struct net_device *dev;
struct sock *sk; /* returned from REQUEST */ struct sock *sk; /* returned from REQUEST */
void *handler; /* upper layer use,
stored in llc_opt->handler */
u16 link; u16 link;
struct sk_buff *skb; /* received SABME */ struct sk_buff *skb; /* received SABME */
}; };
......
...@@ -134,7 +134,7 @@ int llc_station_ac_report_status(struct llc_station *station, ...@@ -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) static void llc_station_ack_tmr_callback(unsigned long timeout_data)
{ {
struct llc_station *station = (struct llc_station *)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; station->ack_tmr_running = 0;
if (skb) { if (skb) {
......
...@@ -1454,8 +1454,9 @@ int llc_conn_ac_set_f_flag_p(struct sock *sk, struct sk_buff *skb) ...@@ -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) void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)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; llc_sk(sk)->pf_cycle_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(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) ...@@ -1464,13 +1465,15 @@ void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
static void llc_conn_busy_tmr_cb(unsigned long timeout_data) static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)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; llc_sk(sk)->busy_state_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(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) ...@@ -1479,13 +1482,15 @@ static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
void llc_conn_ack_tmr_cb(unsigned long timeout_data) void llc_conn_ack_tmr_cb(unsigned long timeout_data)
{ {
struct sock* sk = (struct sock *)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; llc_sk(sk)->ack_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(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) ...@@ -1494,13 +1499,15 @@ void llc_conn_ack_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
static void llc_conn_rej_tmr_cb(unsigned long timeout_data) static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)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; llc_sk(sk)->rej_sent_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(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) ...@@ -1509,6 +1516,7 @@ static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb) 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) ...@@ -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 * llc_conn_disc - removes connection from SAP list and frees it
* @sk: closed connection * @sk: closed connection
* @skb: occurred event * @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) int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
{ {
llc_sap_unassign_sock(llc_sk(sk)->sap, sk); /* FIXME: this thing seems to want to die */
llc_sock_free(sk); return 0;
return 2;
} }
/** /**
...@@ -1555,7 +1560,7 @@ int llc_conn_disc(struct sock *sk, struct sk_buff *skb) ...@@ -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) int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
{ {
llc_sock_reset(sk); llc_sk_reset(sk);
return 0; return 0;
} }
...@@ -1589,19 +1594,16 @@ u8 llc_circular_between(u8 a, u8 b, u8 c) ...@@ -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) 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) { if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
printk(KERN_WARNING "%s: timer called on closed connection\n", printk(KERN_WARNING "%s: timer called on closed connection\n",
__FUNCTION__); __FUNCTION__);
llc_conn_free_ev(skb); llc_conn_free_ev(skb);
goto out; } else {
} if (!sk->lock.users)
if (!sk->lock.users) llc_conn_state_process(sk, skb);
llc_conn_state_process(sk, skb); else {
else { llc_set_backlog_type(skb, LLC_EVENT);
llc_set_backlog_type(skb, LLC_EVENT); sk_add_backlog(sk, skb);
sk_add_backlog(sk, skb); }
} }
out:
bh_unlock_sock(sk);
} }
...@@ -43,7 +43,7 @@ static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; ...@@ -43,7 +43,7 @@ static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
* @sk: connection * @sk: connection
* @skb: occurred event * @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 * (executing it's actions and changing state), upper layer will be
* indicated or confirmed, if needed. Returns 0 for success, 1 for * indicated or confirmed, if needed. Returns 0 for success, 1 for
* failure. The socket lock has to be held before calling this function. * 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) ...@@ -65,15 +65,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
llc_conn_free_ev(skb); llc_conn_free_ev(skb);
else if (ind_prim && cfm_prim) else if (ind_prim && cfm_prim)
skb_get(skb); 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 */ if (!flag) /* indicate or confirm not required */
goto out; goto out;
rc = 0; rc = 0;
...@@ -83,10 +74,13 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -83,10 +74,13 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
* sock crap * sock crap
*/ */
if (flag == LLC_DATA_PRIM + 1) { if (flag == LLC_DATA_PRIM + 1) {
struct sock *upper = llc_sk(skb->sk)->handler; if (sock_queue_rcv_skb(skb->sk, skb)) {
/*
skb->sk = upper; * FIXME: have to sync the LLC state
if (sock_queue_rcv_skb(upper, skb)) { * machine wrt mem usage with
* sk->{r,w}mem_alloc, will do
* this soon 8)
*/
printk(KERN_ERR printk(KERN_ERR
"%s: sock_queue_rcv_skb failed!\n", "%s: sock_queue_rcv_skb failed!\n",
__FUNCTION__); __FUNCTION__);
...@@ -105,10 +99,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -105,10 +99,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
} }
if (!llc_data_accept_state(llc->state)) { if (!llc_data_accept_state(llc->state)) {
/* In this state, we can send I pdu */ /* In this state, we can send I pdu */
struct sock* upper = llc_sk(skb->sk)->handler; if (skb->sk)
skb->sk->write_space(skb->sk);
if (upper)
wake_up(upper->sleep);
} else } else
rc = llc->failed_data_req = 1; rc = llc->failed_data_req = 1;
kfree_skb(skb); kfree_skb(skb);
...@@ -118,7 +110,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -118,7 +110,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
{ {
llc_sock_assert(sk);
/* queue PDU to send to MAC layer */ /* queue PDU to send to MAC layer */
skb_queue_tail(&sk->write_queue, skb); skb_queue_tail(&sk->write_queue, skb);
llc_conn_send_pdus(sk); llc_conn_send_pdus(sk);
...@@ -380,11 +371,10 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *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 * llc_exec_conn_trans_actions - executes related actions
* @sk: connection * @sk: connection
* @trans: transition that it's actions must be performed * @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 * 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 * success, 1 to indicate failure of at least one action.
* connection was freed (llc_conn_disc was called)
*/ */
static int llc_exec_conn_trans_actions(struct sock *sk, static int llc_exec_conn_trans_actions(struct sock *sk,
struct llc_conn_state_trans *trans, struct llc_conn_state_trans *trans,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/tcp.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <net/llc_if.h> #include <net/llc_if.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
...@@ -249,7 +250,6 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) ...@@ -249,7 +250,6 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
int rc = -ECONNABORTED; int rc = -ECONNABORTED;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
lock_sock(sk);
if (llc->state == LLC_CONN_STATE_ADM) if (llc->state == LLC_CONN_STATE_ADM)
goto out; goto out;
rc = -EBUSY; rc = -EBUSY;
...@@ -269,7 +269,6 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) ...@@ -269,7 +269,6 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
skb->dev = llc->dev; skb->dev = llc->dev;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
out: out:
release_sock(sk);
return rc; return rc;
} }
...@@ -299,7 +298,6 @@ static void llc_confirm_impossible(struct llc_prim_if_block *prim) ...@@ -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) static int llc_conn_req_handler(struct llc_prim_if_block *prim)
{ {
int rc = -EBUSY; int rc = -EBUSY;
struct llc_opt *llc;
struct llc_sap *sap = prim->sap; struct llc_sap *sap = prim->sap;
struct sk_buff *skb; struct sk_buff *skb;
struct net_device *ddev = mac_dev_peer(prim->data->conn.dev, 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) ...@@ -319,37 +317,16 @@ static int llc_conn_req_handler(struct llc_prim_if_block *prim)
daddr.lsap = prim->data->conn.daddr.lsap; daddr.lsap = prim->data->conn.daddr.lsap;
sk = llc_lookup_established(sap, &daddr, &laddr); sk = llc_lookup_established(sap, &daddr, &laddr);
if (sk) { if (sk) {
llc_confirm_impossible(prim); if (sk->state == TCP_ESTABLISHED) {
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) {
llc_confirm_impossible(prim); llc_confirm_impossible(prim);
goto out; goto out_put;
} } else
prim->data->conn.sk = sk; sock_put(sk);
} }
rc = -ENOMEM;
sk = prim->data->conn.sk;
sock_hold(sk); sock_hold(sk);
lock_sock(sk); skb = alloc_skb(0, GFP_ATOMIC);
/* 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);
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(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) ...@@ -359,15 +336,10 @@ static int llc_conn_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.data = prim; ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
} }
if (rc) { if (rc)
llc_sap_unassign_sock(sap, sk);
llc_sock_free(sk);
llc_confirm_impossible(prim); llc_confirm_impossible(prim);
}
release_sock(sk);
out_put: out_put:
sock_put(sk); sock_put(sk);
out:
return rc; return rc;
} }
...@@ -388,7 +360,6 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim) ...@@ -388,7 +360,6 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim)
struct sock* sk = prim->data->disc.sk; struct sock* sk = prim->data->disc.sk;
sock_hold(sk); sock_hold(sk);
lock_sock(sk);
if (llc_sk(sk)->state == LLC_CONN_STATE_ADM || if (llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
goto out; goto out;
...@@ -396,7 +367,7 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim) ...@@ -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 * Postpone unassigning the connection from its SAP and returning the
* connection until all ACTIONs have been completely executed * connection until all ACTIONs have been completely executed
*/ */
skb = alloc_skb(1, GFP_ATOMIC); skb = alloc_skb(0, GFP_ATOMIC);
if (!skb) if (!skb)
goto out; goto out;
ev = llc_conn_ev(skb); ev = llc_conn_ev(skb);
...@@ -406,7 +377,6 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim) ...@@ -406,7 +377,6 @@ static int llc_disc_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.data = prim; ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
out: out:
release_sock(sk);
sock_put(sk); sock_put(sk);
return rc; return rc;
} }
...@@ -426,8 +396,7 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim) ...@@ -426,8 +396,7 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim)
int rc = 1; int rc = 1;
struct sock *sk = prim->data->res.sk; struct sock *sk = prim->data->res.sk;
lock_sock(sk); skb = alloc_skb(0, GFP_ATOMIC);
skb = alloc_skb(1, GFP_ATOMIC);
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(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) ...@@ -437,7 +406,6 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.data = prim; ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
} }
release_sock(sk);
return rc; return rc;
} }
...@@ -498,7 +466,7 @@ static int llc_rst_rsp_handler(struct llc_prim_if_block *prim) ...@@ -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 * package as event and send it to connection event handler
*/ */
struct sock *sk = prim->data->res.sk; 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) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <net/llc_s_ev.h> #include <net/llc_s_ev.h>
#include <linux/trdevice.h> #include <linux/trdevice.h>
#if 1 #if 0
#define dprintk(args...) printk(KERN_DEBUG args) #define dprintk(args...) printk(KERN_DEBUG args)
#else #else
#define dprintk(args...) #define dprintk(args...)
...@@ -123,23 +123,30 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -123,23 +123,30 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
sk = llc_lookup_established(sap, &saddr, &daddr); sk = llc_lookup_established(sap, &saddr, &daddr);
if (!sk) { if (!sk) {
struct llc_opt *llc;
dprintk("%s: llc_lookup_established failed\n", __FUNCTION__);
/* /*
* FIXME: here we'll pass the sk->family of the * FIXME: here we'll pass the sk->family of the
* listening socket, if found, when * listening socket, if found, when
* llc_lookup_listener is added in the next patches. * 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) if (!sk)
goto drop; 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); llc_sap_assign_sock(sap, sk);
sock_hold(sk); sock_hold(sk);
} }
skb->sk = sk; skb->sk = sk;
bh_lock_sock(sk); bh_lock_sock(sk);
if (!sk->lock.users) if (!sk->lock.users) {
rc = llc_conn_rcv(sk, skb); /* rc = */ llc_conn_rcv(sk, skb);
else { rc = 0;
} else {
dprintk("%s: adding to backlog...\n", __FUNCTION__);
llc_set_backlog_type(skb, LLC_PACKET); llc_set_backlog_type(skb, LLC_PACKET);
sk_add_backlog(sk, skb); sk_add_backlog(sk, skb);
rc = 0; rc = 0;
......
...@@ -52,6 +52,11 @@ static int llc_rtn_all_conns(struct llc_sap *sap); ...@@ -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 */ 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. * llc_sap_alloc - allocates and initializes sap.
* *
...@@ -165,10 +170,12 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -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. * @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); struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
int rc = -ENOMEM; int rc = -ENOMEM;
...@@ -198,61 +205,83 @@ int llc_sock_init(struct sock* sk) ...@@ -198,61 +205,83 @@ int llc_sock_init(struct sock* sk)
} }
/** /**
* __llc_sock_alloc - Allocates LLC sock * llc_sk_alloc - Allocates LLC sock
* @family: upper layer protocol family * @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 * Allocates a LLC sock and initializes it. Returns the new LLC sock
* or %NULL if there's no memory available for one * 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) if (!sk)
goto out; goto decmod;
if (llc_sock_init(sk)) if (llc_sk_init(sk))
goto outsk; goto outsk;
sock_init_data(NULL, sk); sock_init_data(NULL, sk);
#ifdef LLC_REFCNT_DEBUG
atomic_inc(&llc_sock_nr);
printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
__FUNCTION__, atomic_read(&llc_sock_nr));
#endif
out: out:
return sk; return sk;
outsk: outsk:
sk_free(sk); sk_free(sk);
sk = NULL; sk = NULL;
decmod:
MOD_DEC_USE_COUNT;
goto out; goto out;
} }
/** /**
* __llc_sock_free - Frees a LLC socket * llc_sk_free - Frees a LLC socket
* @sk - socket to free * @sk - socket to free
* *
* Frees a LLC socket * 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); struct llc_opt *llc = llc_sk(sk);
llc->state = LLC_CONN_OUT_OF_SVC; 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); llc_conn_ac_stop_all_timers(sk, NULL);
#ifdef DEBUG_LLC_CONN_ALLOC #ifdef DEBUG_LLC_CONN_ALLOC
printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__, printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
skb_queue_len(&llc->pdu_unack_q), skb_queue_len(&llc->pdu_unack_q),
skb_queue_len(&sk->write_queue)); skb_queue_len(&sk->write_queue));
#endif #endif
skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&sk->write_queue); skb_queue_purge(&sk->write_queue);
skb_queue_purge(&llc->pdu_unack_q); skb_queue_purge(&llc->pdu_unack_q);
if (free) #ifdef LLC_REFCNT_DEBUG
sock_put(sk); 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 * @sk: LLC socket to reset
* *
* Resets a connection to the out of service state. Stops its timers * Resets a connection to the out of service state. Stops its timers
* and frees any frames in the queues of the connection. * 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); struct llc_opt *llc = llc_sk(sk);
...@@ -585,7 +614,7 @@ static int __init llc_init(void) ...@@ -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.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list); skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock); spin_lock_init(&llc_main_station.ev_q.lock);
skb = alloc_skb(1, GFP_ATOMIC); skb = alloc_skb(0, GFP_ATOMIC);
if (!skb) if (!skb)
goto err; goto err;
llc_build_offset_table(); llc_build_offset_table();
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment