diff options
Diffstat (limited to 'net/llc/llc_conn.c')
-rw-r--r-- | net/llc/llc_conn.c | 35 |
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 | */ |
59 | int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) | 61 | int 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 | } |
189 | out_kfree_skb: | ||
190 | kfree_skb(skb); | ||
191 | out_skb_put: | 172 | out_skb_put: |
192 | kfree_skb(skb); | 173 | kfree_skb(skb); |
193 | return rc; | 174 | return rc; |