Commit 4e87a098 authored by David S. Miller's avatar David S. Miller

Merge master.kernel.org:/home/acme/BK/llc-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents f32a9e2a c96542ed
...@@ -79,7 +79,6 @@ extern int llc_sk_init(struct sock *sk); ...@@ -79,7 +79,6 @@ extern int llc_sk_init(struct sock *sk);
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);
extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb); extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_free_ev(struct sk_buff *skb);
extern void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, extern void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr,
u8 first_p_bit); u8 first_p_bit);
extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr,
......
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
*/ */
extern int llc_rcv(struct sk_buff *skb, struct net_device *dev, extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt); struct packet_type *pt);
extern struct net_device *mac_dev_peer(struct net_device *current_dev,
int type, u8 *mac);
extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da); extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da);
extern int llc_conn_rcv(struct sock *sk, struct sk_buff *skb); extern int llc_conn_rcv(struct sock *sk, struct sk_buff *skb);
......
...@@ -569,6 +569,13 @@ static int llc_ui_wait_for_data(struct sock *sk, int timeout) ...@@ -569,6 +569,13 @@ static int llc_ui_wait_for_data(struct sock *sk, int timeout)
rc = -EAGAIN; rc = -EAGAIN;
if (!timeout) if (!timeout)
break; break;
/*
* Well, if we have backlog, try to process it now.
*/
if (sk->backlog.tail) {
release_sock(sk);
lock_sock(sk);
}
rc = 0; rc = 0;
if (skb_queue_empty(&sk->receive_queue)) { if (skb_queue_empty(&sk->receive_queue)) {
release_sock(sk); release_sock(sk);
......
...@@ -1487,7 +1487,7 @@ static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb) ...@@ -1487,7 +1487,7 @@ static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
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); kfree_skb(skb);
} else { } else {
if (!sk->lock.users) if (!sk->lock.users)
llc_conn_state_process(sk, skb); llc_conn_state_process(sk, skb);
......
...@@ -71,6 +71,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -71,6 +71,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
/*
* We have to hold the skb, because llc_conn_service will kfree it in
* the sending path and we need to look at the skb->cb, where we encode
* llc_conn_state_ev.
*/
skb_get(skb);
ev->ind_prim = ev->cfm_prim = 0; ev->ind_prim = ev->cfm_prim = 0;
rc = llc_conn_service(sk, skb); /* sending event to state machine */ rc = llc_conn_service(sk, skb); /* sending event to state machine */
if (rc) { if (rc) {
...@@ -81,10 +87,10 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -81,10 +87,10 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
if (!ev->ind_prim && !ev->cfm_prim) { /* indicate or confirm not required */ if (!ev->ind_prim && !ev->cfm_prim) { /* indicate or confirm not required */
if (!skb->list) if (!skb->list)
goto out_kfree_skb; goto out_kfree_skb;
goto out; goto out_skb_put;
} }
if (ev->ind_prim && ev->cfm_prim) if (ev->ind_prim && ev->cfm_prim) /* Paranoia */
skb_get(skb); skb_get(skb);
switch (ev->ind_prim) { switch (ev->ind_prim) {
...@@ -180,11 +186,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -180,11 +186,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
__FUNCTION__, ev->cfm_prim); __FUNCTION__, ev->cfm_prim);
break; break;
} }
goto out; /* No confirmation */ goto out_skb_put; /* No confirmation */
} }
out_kfree_skb: out_kfree_skb:
kfree_skb(skb); kfree_skb(skb);
out: out_skb_put:
kfree_skb(skb);
return rc; return rc;
} }
...@@ -226,25 +233,29 @@ void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit) ...@@ -226,25 +233,29 @@ void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit)
struct sk_buff *skb; struct sk_buff *skb;
struct llc_pdu_sn *pdu; struct llc_pdu_sn *pdu;
u16 nbr_unack_pdus; u16 nbr_unack_pdus;
struct llc_opt *llc;
u8 howmany_resend = 0; u8 howmany_resend = 0;
llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus); llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
if (!nbr_unack_pdus) if (!nbr_unack_pdus)
goto out; goto out;
/* process unack PDUs only if unack queue is not empty; remove /*
* Process unack PDUs only if unack queue is not empty; remove
* appropriate PDUs, fix them up, and put them on mac_pdu_q. * appropriate PDUs, fix them up, and put them on mac_pdu_q.
*/ */
while ((skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q)) != NULL) { llc = llc_sk(sk);
pdu = (struct llc_pdu_sn *)skb->nh.raw;
while ((skb = skb_dequeue(&llc->pdu_unack_q)) != NULL) {
pdu = llc_pdu_sn_hdr(skb);
llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD); llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD);
llc_pdu_set_pf_bit(skb, first_p_bit); llc_pdu_set_pf_bit(skb, first_p_bit);
skb_queue_tail(&sk->write_queue, skb); skb_queue_tail(&sk->write_queue, skb);
first_p_bit = 0; first_p_bit = 0;
llc_sk(sk)->vS = LLC_I_GET_NS(pdu); llc->vS = LLC_I_GET_NS(pdu);
howmany_resend++; howmany_resend++;
} }
if (howmany_resend > 0) if (howmany_resend > 0)
llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO; llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
/* any PDUs to re-send are queued up; start sending to MAC */ /* any PDUs to re-send are queued up; start sending to MAC */
llc_conn_send_pdus(sk); llc_conn_send_pdus(sk);
out:; out:;
...@@ -263,27 +274,29 @@ out:; ...@@ -263,27 +274,29 @@ out:;
void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit) void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct llc_pdu_sn *pdu;
u16 nbr_unack_pdus; u16 nbr_unack_pdus;
struct llc_opt *llc = llc_sk(sk);
u8 howmany_resend = 0; u8 howmany_resend = 0;
llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus); llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
if (!nbr_unack_pdus) if (!nbr_unack_pdus)
goto out; goto out;
/* process unack PDUs only if unack queue is not empty; remove /*
* Process unack PDUs only if unack queue is not empty; remove
* appropriate PDUs, fix them up, and put them on mac_pdu_q * appropriate PDUs, fix them up, and put them on mac_pdu_q
*/ */
while ((skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q)) != NULL) { while ((skb = skb_dequeue(&llc->pdu_unack_q)) != NULL) {
pdu = (struct llc_pdu_sn *)skb->nh.raw; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP); llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP);
llc_pdu_set_pf_bit(skb, first_f_bit); llc_pdu_set_pf_bit(skb, first_f_bit);
skb_queue_tail(&sk->write_queue, skb); skb_queue_tail(&sk->write_queue, skb);
first_f_bit = 0; first_f_bit = 0;
llc_sk(sk)->vS = LLC_I_GET_NS(pdu); llc->vS = LLC_I_GET_NS(pdu);
howmany_resend++; howmany_resend++;
} }
if (howmany_resend > 0) if (howmany_resend > 0)
llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO; llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
/* any PDUs to re-send are queued up; start sending to MAC */ /* any PDUs to re-send are queued up; start sending to MAC */
llc_conn_send_pdus(sk); llc_conn_send_pdus(sk);
out:; out:;
...@@ -304,25 +317,26 @@ int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked) ...@@ -304,25 +317,26 @@ int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked)
struct sk_buff *skb; struct sk_buff *skb;
struct llc_pdu_sn *pdu; struct llc_pdu_sn *pdu;
int nbr_acked = 0; int nbr_acked = 0;
int q_len = skb_queue_len(&llc_sk(sk)->pdu_unack_q); struct llc_opt *llc = llc_sk(sk);
int q_len = skb_queue_len(&llc->pdu_unack_q);
if (!q_len) if (!q_len)
goto out; goto out;
skb = skb_peek(&llc_sk(sk)->pdu_unack_q); skb = skb_peek(&llc->pdu_unack_q);
pdu = (struct llc_pdu_sn *)skb->nh.raw; pdu = llc_pdu_sn_hdr(skb);
/* finding position of last acked pdu in queue */ /* finding position of last acked pdu in queue */
pdu_pos = ((int)LLC_2_SEQ_NBR_MODULO + (int)nr - pdu_pos = ((int)LLC_2_SEQ_NBR_MODULO + (int)nr -
(int)LLC_I_GET_NS(pdu)) % LLC_2_SEQ_NBR_MODULO; (int)LLC_I_GET_NS(pdu)) % LLC_2_SEQ_NBR_MODULO;
for (i = 0; i < pdu_pos && i < q_len; i++) { for (i = 0; i < pdu_pos && i < q_len; i++) {
skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q); skb = skb_dequeue(&llc->pdu_unack_q);
if (skb) if (skb)
kfree_skb(skb); kfree_skb(skb);
nbr_acked++; nbr_acked++;
} }
out: out:
*how_many_unacked = skb_queue_len(&llc_sk(sk)->pdu_unack_q); *how_many_unacked = skb_queue_len(&llc->pdu_unack_q);
return nbr_acked; return nbr_acked;
} }
...@@ -337,7 +351,7 @@ static void llc_conn_send_pdus(struct sock *sk) ...@@ -337,7 +351,7 @@ static void llc_conn_send_pdus(struct sock *sk)
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = skb_dequeue(&sk->write_queue)) != NULL) { while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
if (!LLC_PDU_TYPE_IS_I(pdu) && if (!LLC_PDU_TYPE_IS_I(pdu) &&
!(skb->dev->flags & IFF_LOOPBACK)) { !(skb->dev->flags & IFF_LOOPBACK)) {
...@@ -352,31 +366,6 @@ static void llc_conn_send_pdus(struct sock *sk) ...@@ -352,31 +366,6 @@ static void llc_conn_send_pdus(struct sock *sk)
} }
} }
/**
* llc_conn_free_ev - free event
* @skb: event to free
*
* Free allocated event.
*/
void llc_conn_free_ev(struct sk_buff *skb)
{
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
if (ev->type == LLC_CONN_EV_TYPE_PDU) {
/* free the frame that is bound to this event */
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
if (LLC_PDU_TYPE_IS_I(pdu) || !ev->ind_prim)
kfree_skb(skb);
} else if (ev->type == LLC_CONN_EV_TYPE_PRIM &&
ev->prim != LLC_DATA_PRIM)
kfree_skb(skb);
else if (ev->type == LLC_CONN_EV_TYPE_P_TMR ||
ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ||
ev->type == LLC_CONN_EV_TYPE_REJ_TMR)
kfree_skb(skb);
}
/** /**
* llc_conn_service - finds transition and changes state of connection * llc_conn_service - finds transition and changes state of connection
* @sk: connection * @sk: connection
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <net/llc_c_ac.h> #include <net/llc_c_ac.h>
#include <net/llc_c_st.h> #include <net/llc_c_st.h>
#include <net/llc_main.h> #include <net/llc_main.h>
#include <net/llc_mac.h>
/** /**
* llc_sap_open - open interface to the upper layers. * llc_sap_open - open interface to the upper layers.
......
...@@ -294,27 +294,3 @@ u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da) ...@@ -294,27 +294,3 @@ u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da)
} }
return rc; return rc;
} }
/**
* mac_dev_peer - search the appropriate dev to send packets to peer
* @current_dev - Current device suggested by upper layer
* @type - hardware type
* @mac - mac address
*
* Check if the we should use loopback to send packets, i.e., if the
* dmac belongs to one of the local interfaces, returning the pointer
* to the loopback &net_device struct or the current_dev if it is not
* local.
*/
struct net_device *mac_dev_peer(struct net_device *current_dev, int type,
u8 *mac)
{
struct net_device *dev;
rtnl_lock();
dev = dev_getbyhwaddr(type, mac);
if (dev)
dev = __dev_get_by_name("lo");
rtnl_unlock();
return dev ? : current_dev;
}
...@@ -147,20 +147,22 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -147,20 +147,22 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
if (llc->state > 1) /* not closed */ if (llc->state > 1) /* not closed */
rc = llc_conn_rcv(sk, skb); rc = llc_conn_rcv(sk, skb);
else else
kfree_skb(skb); goto out_kfree_skb;
} else if (llc_backlog_type(skb) == LLC_EVENT) { } else if (llc_backlog_type(skb) == LLC_EVENT) {
/* timer expiration event */ /* timer expiration event */
if (llc->state > 1) /* not closed */ if (llc->state > 1) /* not closed */
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
else else
llc_conn_free_ev(skb); goto out_kfree_skb;
kfree_skb(skb);
} else { } else {
printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__); printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__);
kfree_skb(skb); goto out_kfree_skb;
} }
out:
return rc; return rc;
out_kfree_skb:
kfree_skb(skb);
goto out;
} }
/** /**
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/if_tr.h> #include <linux/if_tr.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_if.h> #include <net/llc_if.h>
#include <net/llc_mac.h>
#include <net/llc_main.h> #include <net/llc_main.h>
static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
......
...@@ -20,17 +20,9 @@ ...@@ -20,17 +20,9 @@
#include <net/sock.h> #include <net/sock.h>
#include <linux/tcp.h> #include <linux/tcp.h>
#include <net/llc_main.h> #include <net/llc_main.h>
#include <net/llc_mac.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <linux/if_tr.h> #include <linux/if_tr.h>
static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb);
static int llc_exec_sap_trans_actions(struct llc_sap *sap,
struct llc_sap_state_trans *trans,
struct sk_buff *skb);
static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
struct sk_buff *skb);
/** /**
* llc_sap_assign_sock - adds a connection to a SAP * llc_sap_assign_sock - adds a connection to a SAP
* @sap: pointer to SAP. * @sap: pointer to SAP.
...@@ -75,41 +67,6 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) ...@@ -75,41 +67,6 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
write_unlock_bh(&sap->sk_list.lock); write_unlock_bh(&sap->sk_list.lock);
} }
/**
* llc_sap_state_process - sends event to SAP state machine
* @sap: sap to use
* @skb: pointer to occurred event
*
* After executing actions of the event, upper layer will be indicated
* if needed(on receiving an UI frame). sk can be null for the
* datalink_proto case.
*/
void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
/*
* We have to hold the skb, because llc_sap_next_state
* will kfree it in the sending path and we need to
* look at the skb->cb, where we encode llc_sap_state_ev.
*/
skb_get(skb);
ev->ind_cfm_flag = 0;
llc_sap_next_state(sap, skb);
if (ev->ind_cfm_flag == LLC_IND) {
if (skb->sk->state == TCP_LISTEN)
kfree_skb(skb);
else {
llc_save_primitive(skb, ev->prim);
/* queue skb to the user. */
if (sock_queue_rcv_skb(skb->sk, skb))
kfree_skb(skb);
}
}
kfree_skb(skb);
}
/** /**
* llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu. * llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu.
* @sap: pointer to SAP * @sap: pointer to SAP
...@@ -117,10 +74,9 @@ void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) ...@@ -117,10 +74,9 @@ void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
*/ */
void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_pdu_un *pdu;
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu = llc_pdu_un_hdr(skb);
switch (LLC_U_PDU_RSP(pdu)) { switch (LLC_U_PDU_RSP(pdu)) {
case LLC_1_PDU_CMD_TEST: case LLC_1_PDU_CMD_TEST:
ev->prim = LLC_TEST_PRIM; break; ev->prim = LLC_TEST_PRIM; break;
...@@ -132,38 +88,6 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) ...@@ -132,38 +88,6 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
ev->ind_cfm_flag = LLC_IND; ev->ind_cfm_flag = LLC_IND;
} }
/**
* llc_sap_next_state - finds transition, execs actions & change SAP state
* @sap: pointer to SAP
* @skb: happened event
*
* This function finds transition that matches with happened event, then
* executes related actions and finally changes state of SAP. It returns
* 0 on success and 1 for failure.
*/
static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb)
{
int rc = 1;
struct llc_sap_state_trans *trans;
if (sap->state <= LLC_NR_SAP_STATES) {
trans = llc_find_sap_trans(sap, skb);
if (trans) {
/* got the state to which we next transition; perform
* the actions associated with this transition before
* actually transitioning to the next state
*/
rc = llc_exec_sap_trans_actions(sap, trans, skb);
if (!rc)
/* transition SAP to next state if all actions
* execute successfully
*/
sap->state = trans->next_state;
}
}
return rc;
}
/** /**
* llc_find_sap_trans - finds transition for event * llc_find_sap_trans - finds transition for event
* @sap: pointer to SAP * @sap: pointer to SAP
...@@ -180,13 +104,13 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, ...@@ -180,13 +104,13 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
struct llc_sap_state_trans *rc = NULL; struct llc_sap_state_trans *rc = NULL;
struct llc_sap_state_trans **next_trans; struct llc_sap_state_trans **next_trans;
struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1]; struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1];
/* search thru events for this state until list exhausted or until /*
* Search thru events for this state until list exhausted or until
* its obvious the event is not valid for the current state * its obvious the event is not valid for the current state
*/ */
for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
if (!next_trans[i]->ev(sap, skb)) { if (!next_trans[i]->ev(sap, skb)) {
/* got event match; return it */ rc = next_trans[i]; /* got event match; return it */
rc = next_trans[i];
break; break;
} }
return rc; return rc;
...@@ -213,3 +137,73 @@ static int llc_exec_sap_trans_actions(struct llc_sap *sap, ...@@ -213,3 +137,73 @@ static int llc_exec_sap_trans_actions(struct llc_sap *sap,
rc = 1; rc = 1;
return rc; return rc;
} }
/**
* llc_sap_next_state - finds transition, execs actions & change SAP state
* @sap: pointer to SAP
* @skb: happened event
*
* This function finds transition that matches with happened event, then
* executes related actions and finally changes state of SAP. It returns
* 0 on success and 1 for failure.
*/
static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb)
{
int rc = 1;
struct llc_sap_state_trans *trans;
if (sap->state > LLC_NR_SAP_STATES)
goto out;
trans = llc_find_sap_trans(sap, skb);
if (!trans)
goto out;
/*
* Got the state to which we next transition; perform the actions
* associated with this transition before actually transitioning to the
* next state
*/
rc = llc_exec_sap_trans_actions(sap, trans, skb);
if (rc)
goto out;
/*
* Transition SAP to next state if all actions execute successfully
*/
sap->state = trans->next_state;
out:
return rc;
}
/**
* llc_sap_state_process - sends event to SAP state machine
* @sap: sap to use
* @skb: pointer to occurred event
*
* After executing actions of the event, upper layer will be indicated
* if needed(on receiving an UI frame). sk can be null for the
* datalink_proto case.
*/
void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
/*
* We have to hold the skb, because llc_sap_next_state
* will kfree it in the sending path and we need to
* look at the skb->cb, where we encode llc_sap_state_ev.
*/
skb_get(skb);
ev->ind_cfm_flag = 0;
llc_sap_next_state(sap, skb);
if (ev->ind_cfm_flag == LLC_IND) {
if (skb->sk->state == TCP_LISTEN)
kfree_skb(skb);
else {
llc_save_primitive(skb, ev->prim);
/* queue skb to the user. */
if (sock_queue_rcv_skb(skb->sk, skb))
kfree_skb(skb);
}
}
kfree_skb(skb);
}
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