summaryrefslogtreecommitdiffstats
path: root/net/llc
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2018-03-26 18:08:33 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-27 11:56:00 -0400
commitb85ab56c3f81c5a24b5a5213374f549df06430da (patch)
tree4580d5ab329020259c744ca5b5accae6997258c9 /net/llc
parent2a7fdec98f74cc305c1247cbe67307d504a3223d (diff)
llc: properly handle dev_queue_xmit() return value
llc_conn_send_pdu() pushes the skb into write queue and calls llc_conn_send_pdus() to flush them out. However, the status of dev_queue_xmit() is not returned to caller, in this case, llc_conn_state_process(). llc_conn_state_process() needs hold the skb no matter success or failure, because it still uses it after that, therefore we should hold skb before dev_queue_xmit() when that skb is the one being processed by llc_conn_state_process(). For other callers, they can just pass NULL and ignore the return value as they are. Reported-by: Noam Rathaus <noamr@beyondsecurity.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/llc')
-rw-r--r--net/llc/llc_c_ac.c15
-rw-r--r--net/llc/llc_conn.c32
2 files changed, 32 insertions, 15 deletions
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
index f59648018060..163121192aca 100644
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -389,7 +389,7 @@ static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
389 llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR); 389 llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
390 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); 390 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
391 if (likely(!rc)) { 391 if (likely(!rc)) {
392 llc_conn_send_pdu(sk, skb); 392 rc = llc_conn_send_pdu(sk, skb);
393 llc_conn_ac_inc_vs_by_1(sk, skb); 393 llc_conn_ac_inc_vs_by_1(sk, skb);
394 } 394 }
395 return rc; 395 return rc;
@@ -916,7 +916,7 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
916 llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR); 916 llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR);
917 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); 917 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
918 if (likely(!rc)) { 918 if (likely(!rc)) {
919 llc_conn_send_pdu(sk, skb); 919 rc = llc_conn_send_pdu(sk, skb);
920 llc_conn_ac_inc_vs_by_1(sk, skb); 920 llc_conn_ac_inc_vs_by_1(sk, skb);
921 } 921 }
922 return rc; 922 return rc;
@@ -935,14 +935,17 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
935int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb) 935int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
936{ 936{
937 struct llc_sock *llc = llc_sk(sk); 937 struct llc_sock *llc = llc_sk(sk);
938 int ret;
938 939
939 if (llc->ack_must_be_send) { 940 if (llc->ack_must_be_send) {
940 llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb); 941 ret = llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
941 llc->ack_must_be_send = 0 ; 942 llc->ack_must_be_send = 0 ;
942 llc->ack_pf = 0; 943 llc->ack_pf = 0;
943 } else 944 } else {
944 llc_conn_ac_send_i_cmd_p_set_0(sk, skb); 945 ret = llc_conn_ac_send_i_cmd_p_set_0(sk, skb);
945 return 0; 946 }
947
948 return ret;
946} 949}
947 950
948/** 951/**
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 9177dbb16dce..110e32bcb399 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -30,7 +30,7 @@
30#endif 30#endif
31 31
32static int llc_find_offset(int state, int ev_type); 32static int llc_find_offset(int state, int ev_type);
33static void llc_conn_send_pdus(struct sock *sk); 33static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *skb);
34static int llc_conn_service(struct sock *sk, struct sk_buff *skb); 34static int llc_conn_service(struct sock *sk, struct sk_buff *skb);
35static int llc_exec_conn_trans_actions(struct sock *sk, 35static int llc_exec_conn_trans_actions(struct sock *sk,
36 struct llc_conn_state_trans *trans, 36 struct llc_conn_state_trans *trans,
@@ -193,11 +193,11 @@ out_skb_put:
193 return rc; 193 return rc;
194} 194}
195 195
196void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) 196int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
197{ 197{
198 /* queue PDU to send to MAC layer */ 198 /* queue PDU to send to MAC layer */
199 skb_queue_tail(&sk->sk_write_queue, skb); 199 skb_queue_tail(&sk->sk_write_queue, skb);
200 llc_conn_send_pdus(sk); 200 return llc_conn_send_pdus(sk, skb);
201} 201}
202 202
203/** 203/**
@@ -255,7 +255,7 @@ void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit)
255 if (howmany_resend > 0) 255 if (howmany_resend > 0)
256 llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; 256 llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
257 /* any PDUs to re-send are queued up; start sending to MAC */ 257 /* any PDUs to re-send are queued up; start sending to MAC */
258 llc_conn_send_pdus(sk); 258 llc_conn_send_pdus(sk, NULL);
259out:; 259out:;
260} 260}
261 261
@@ -296,7 +296,7 @@ void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit)
296 if (howmany_resend > 0) 296 if (howmany_resend > 0)
297 llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; 297 llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
298 /* any PDUs to re-send are queued up; start sending to MAC */ 298 /* any PDUs to re-send are queued up; start sending to MAC */
299 llc_conn_send_pdus(sk); 299 llc_conn_send_pdus(sk, NULL);
300out:; 300out:;
301} 301}
302 302
@@ -340,12 +340,16 @@ out:
340/** 340/**
341 * llc_conn_send_pdus - Sends queued PDUs 341 * llc_conn_send_pdus - Sends queued PDUs
342 * @sk: active connection 342 * @sk: active connection
343 * @hold_skb: the skb held by caller, or NULL if does not care
343 * 344 *
344 * Sends queued pdus to MAC layer for transmission. 345 * Sends queued pdus to MAC layer for transmission. When @hold_skb is
346 * NULL, always return 0. Otherwise, return 0 if @hold_skb is sent
347 * successfully, or 1 for failure.
345 */ 348 */
346static void llc_conn_send_pdus(struct sock *sk) 349static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *hold_skb)
347{ 350{
348 struct sk_buff *skb; 351 struct sk_buff *skb;
352 int ret = 0;
349 353
350 while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { 354 while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) {
351 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); 355 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
@@ -357,10 +361,20 @@ static void llc_conn_send_pdus(struct sock *sk)
357 skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb); 361 skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb);
358 if (!skb2) 362 if (!skb2)
359 break; 363 break;
360 skb = skb2; 364 dev_queue_xmit(skb2);
365 } else {
366 bool is_target = skb == hold_skb;
367 int rc;
368
369 if (is_target)
370 skb_get(skb);
371 rc = dev_queue_xmit(skb);
372 if (is_target)
373 ret = rc;
361 } 374 }
362 dev_queue_xmit(skb);
363 } 375 }
376
377 return ret;
364} 378}
365 379
366/** 380/**