aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc/llc_conn.c')
-rw-r--r--net/llc/llc_conn.c35
1 files changed, 8 insertions, 27 deletions
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index ed2aca12460c..a79b739eb223 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -55,6 +55,8 @@ int sysctl_llc2_busy_timeout = LLC2_BUSY_TIME * HZ;
55 * (executing it's actions and changing state), upper layer will be 55 * (executing it's actions and changing state), upper layer will be
56 * indicated or confirmed, if needed. Returns 0 for success, 1 for 56 * indicated or confirmed, if needed. Returns 0 for success, 1 for
57 * failure. The socket lock has to be held before calling this function. 57 * failure. The socket lock has to be held before calling this function.
58 *
59 * This function always consumes a reference to the skb.
58 */ 60 */
59int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) 61int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
60{ 62{
@@ -62,12 +64,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
62 struct llc_sock *llc = llc_sk(skb->sk); 64 struct llc_sock *llc = llc_sk(skb->sk);
63 struct llc_conn_state_ev *ev = llc_conn_ev(skb); 65 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
64 66
65 /*
66 * We have to hold the skb, because llc_conn_service will kfree it in
67 * the sending path and we need to look at the skb->cb, where we encode
68 * llc_conn_state_ev.
69 */
70 skb_get(skb);
71 ev->ind_prim = ev->cfm_prim = 0; 67 ev->ind_prim = ev->cfm_prim = 0;
72 /* 68 /*
73 * Send event to state machine 69 * Send event to state machine
@@ -75,21 +71,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
75 rc = llc_conn_service(skb->sk, skb); 71 rc = llc_conn_service(skb->sk, skb);
76 if (unlikely(rc != 0)) { 72 if (unlikely(rc != 0)) {
77 printk(KERN_ERR "%s: llc_conn_service failed\n", __func__); 73 printk(KERN_ERR "%s: llc_conn_service failed\n", __func__);
78 goto out_kfree_skb;
79 }
80
81 if (unlikely(!ev->ind_prim && !ev->cfm_prim)) {
82 /* indicate or confirm not required */
83 if (!skb->next)
84 goto out_kfree_skb;
85 goto out_skb_put; 74 goto out_skb_put;
86 } 75 }
87 76
88 if (unlikely(ev->ind_prim && ev->cfm_prim)) /* Paranoia */
89 skb_get(skb);
90
91 switch (ev->ind_prim) { 77 switch (ev->ind_prim) {
92 case LLC_DATA_PRIM: 78 case LLC_DATA_PRIM:
79 skb_get(skb);
93 llc_save_primitive(sk, skb, LLC_DATA_PRIM); 80 llc_save_primitive(sk, skb, LLC_DATA_PRIM);
94 if (unlikely(sock_queue_rcv_skb(sk, skb))) { 81 if (unlikely(sock_queue_rcv_skb(sk, skb))) {
95 /* 82 /*
@@ -106,6 +93,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
106 * skb->sk pointing to the newly created struct sock in 93 * skb->sk pointing to the newly created struct sock in
107 * llc_conn_handler. -acme 94 * llc_conn_handler. -acme
108 */ 95 */
96 skb_get(skb);
109 skb_queue_tail(&sk->sk_receive_queue, skb); 97 skb_queue_tail(&sk->sk_receive_queue, skb);
110 sk->sk_state_change(sk); 98 sk->sk_state_change(sk);
111 break; 99 break;
@@ -121,7 +109,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
121 sk->sk_state_change(sk); 109 sk->sk_state_change(sk);
122 } 110 }
123 } 111 }
124 kfree_skb(skb);
125 sock_put(sk); 112 sock_put(sk);
126 break; 113 break;
127 case LLC_RESET_PRIM: 114 case LLC_RESET_PRIM:
@@ -130,14 +117,11 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
130 * RESET is not being notified to upper layers for now 117 * RESET is not being notified to upper layers for now
131 */ 118 */
132 printk(KERN_INFO "%s: received a reset ind!\n", __func__); 119 printk(KERN_INFO "%s: received a reset ind!\n", __func__);
133 kfree_skb(skb);
134 break; 120 break;
135 default: 121 default:
136 if (ev->ind_prim) { 122 if (ev->ind_prim)
137 printk(KERN_INFO "%s: received unknown %d prim!\n", 123 printk(KERN_INFO "%s: received unknown %d prim!\n",
138 __func__, ev->ind_prim); 124 __func__, ev->ind_prim);
139 kfree_skb(skb);
140 }
141 /* No indication */ 125 /* No indication */
142 break; 126 break;
143 } 127 }
@@ -179,15 +163,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
179 printk(KERN_INFO "%s: received a reset conf!\n", __func__); 163 printk(KERN_INFO "%s: received a reset conf!\n", __func__);
180 break; 164 break;
181 default: 165 default:
182 if (ev->cfm_prim) { 166 if (ev->cfm_prim)
183 printk(KERN_INFO "%s: received unknown %d prim!\n", 167 printk(KERN_INFO "%s: received unknown %d prim!\n",
184 __func__, ev->cfm_prim); 168 __func__, ev->cfm_prim);
185 break; 169 /* No confirmation */
186 } 170 break;
187 goto out_skb_put; /* No confirmation */
188 } 171 }
189out_kfree_skb:
190 kfree_skb(skb);
191out_skb_put: 172out_skb_put:
192 kfree_skb(skb); 173 kfree_skb(skb);
193 return rc; 174 return rc;