1*4a61cd66SEric Lapuyade /* 2*4a61cd66SEric Lapuyade * shdlc Link Layer Control 3*4a61cd66SEric Lapuyade * 4*4a61cd66SEric Lapuyade * Copyright (C) 2012 Intel Corporation. All rights reserved. 5*4a61cd66SEric Lapuyade * 6*4a61cd66SEric Lapuyade * This program is free software; you can redistribute it and/or modify it 7*4a61cd66SEric Lapuyade * under the terms and conditions of the GNU General Public License, 8*4a61cd66SEric Lapuyade * version 2, as published by the Free Software Foundation. 9*4a61cd66SEric Lapuyade * 10*4a61cd66SEric Lapuyade * This program is distributed in the hope that it will be useful, 11*4a61cd66SEric Lapuyade * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*4a61cd66SEric Lapuyade * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*4a61cd66SEric Lapuyade * GNU General Public License for more details. 14*4a61cd66SEric Lapuyade * 15*4a61cd66SEric Lapuyade * You should have received a copy of the GNU General Public License 16*4a61cd66SEric Lapuyade * along with this program; if not, write to the 17*4a61cd66SEric Lapuyade * Free Software Foundation, Inc., 18*4a61cd66SEric Lapuyade * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19*4a61cd66SEric Lapuyade */ 20*4a61cd66SEric Lapuyade 21*4a61cd66SEric Lapuyade #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ 22*4a61cd66SEric Lapuyade 23*4a61cd66SEric Lapuyade #include <linux/types.h> 24*4a61cd66SEric Lapuyade #include <linux/sched.h> 25*4a61cd66SEric Lapuyade #include <linux/export.h> 26*4a61cd66SEric Lapuyade #include <linux/wait.h> 27*4a61cd66SEric Lapuyade #include <linux/slab.h> 28*4a61cd66SEric Lapuyade #include <linux/skbuff.h> 29*4a61cd66SEric Lapuyade 30*4a61cd66SEric Lapuyade #include "llc.h" 31*4a61cd66SEric Lapuyade 32*4a61cd66SEric Lapuyade enum shdlc_state { 33*4a61cd66SEric Lapuyade SHDLC_DISCONNECTED = 0, 34*4a61cd66SEric Lapuyade SHDLC_CONNECTING = 1, 35*4a61cd66SEric Lapuyade SHDLC_NEGOCIATING = 2, 36*4a61cd66SEric Lapuyade SHDLC_CONNECTED = 3 37*4a61cd66SEric Lapuyade }; 38*4a61cd66SEric Lapuyade 39*4a61cd66SEric Lapuyade struct llc_shdlc { 40*4a61cd66SEric Lapuyade struct nfc_hci_dev *hdev; 41*4a61cd66SEric Lapuyade xmit_to_drv_t xmit_to_drv; 42*4a61cd66SEric Lapuyade rcv_to_hci_t rcv_to_hci; 43*4a61cd66SEric Lapuyade 44*4a61cd66SEric Lapuyade struct mutex state_mutex; 45*4a61cd66SEric Lapuyade enum shdlc_state state; 46*4a61cd66SEric Lapuyade int hard_fault; 47*4a61cd66SEric Lapuyade 48*4a61cd66SEric Lapuyade wait_queue_head_t *connect_wq; 49*4a61cd66SEric Lapuyade int connect_tries; 50*4a61cd66SEric Lapuyade int connect_result; 51*4a61cd66SEric Lapuyade struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ 52*4a61cd66SEric Lapuyade 53*4a61cd66SEric Lapuyade u8 w; /* window size */ 54*4a61cd66SEric Lapuyade bool srej_support; 55*4a61cd66SEric Lapuyade 56*4a61cd66SEric Lapuyade struct timer_list t1_timer; /* send ack timeout */ 57*4a61cd66SEric Lapuyade bool t1_active; 58*4a61cd66SEric Lapuyade 59*4a61cd66SEric Lapuyade struct timer_list t2_timer; /* guard/retransmit timeout */ 60*4a61cd66SEric Lapuyade bool t2_active; 61*4a61cd66SEric Lapuyade 62*4a61cd66SEric Lapuyade int ns; /* next seq num for send */ 63*4a61cd66SEric Lapuyade int nr; /* next expected seq num for receive */ 64*4a61cd66SEric Lapuyade int dnr; /* oldest sent unacked seq num */ 65*4a61cd66SEric Lapuyade 66*4a61cd66SEric Lapuyade struct sk_buff_head rcv_q; 67*4a61cd66SEric Lapuyade 68*4a61cd66SEric Lapuyade struct sk_buff_head send_q; 69*4a61cd66SEric Lapuyade bool rnr; /* other side is not ready to receive */ 70*4a61cd66SEric Lapuyade 71*4a61cd66SEric Lapuyade struct sk_buff_head ack_pending_q; 72*4a61cd66SEric Lapuyade 73*4a61cd66SEric Lapuyade struct work_struct sm_work; 74*4a61cd66SEric Lapuyade 75*4a61cd66SEric Lapuyade int tx_headroom; 76*4a61cd66SEric Lapuyade int tx_tailroom; 77*4a61cd66SEric Lapuyade 78*4a61cd66SEric Lapuyade llc_failure_t llc_failure; 79*4a61cd66SEric Lapuyade }; 80*4a61cd66SEric Lapuyade 81*4a61cd66SEric Lapuyade #define SHDLC_LLC_HEAD_ROOM 2 82*4a61cd66SEric Lapuyade 83*4a61cd66SEric Lapuyade #define SHDLC_MAX_WINDOW 4 84*4a61cd66SEric Lapuyade #define SHDLC_SREJ_SUPPORT false 85*4a61cd66SEric Lapuyade 86*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_MASK 0xe0 87*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_I 0x80 88*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_I2 0xa0 89*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_S 0xc0 90*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_U 0xe0 91*4a61cd66SEric Lapuyade 92*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_NS_MASK 0x38 93*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_NR_MASK 0x07 94*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_TYPE_MASK 0x18 95*4a61cd66SEric Lapuyade 96*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_M_MASK 0x1f 97*4a61cd66SEric Lapuyade 98*4a61cd66SEric Lapuyade enum sframe_type { 99*4a61cd66SEric Lapuyade S_FRAME_RR = 0x00, 100*4a61cd66SEric Lapuyade S_FRAME_REJ = 0x01, 101*4a61cd66SEric Lapuyade S_FRAME_RNR = 0x02, 102*4a61cd66SEric Lapuyade S_FRAME_SREJ = 0x03 103*4a61cd66SEric Lapuyade }; 104*4a61cd66SEric Lapuyade 105*4a61cd66SEric Lapuyade enum uframe_modifier { 106*4a61cd66SEric Lapuyade U_FRAME_UA = 0x06, 107*4a61cd66SEric Lapuyade U_FRAME_RSET = 0x19 108*4a61cd66SEric Lapuyade }; 109*4a61cd66SEric Lapuyade 110*4a61cd66SEric Lapuyade #define SHDLC_CONNECT_VALUE_MS 5 111*4a61cd66SEric Lapuyade #define SHDLC_T1_VALUE_MS(w) ((5 * w) / 4) 112*4a61cd66SEric Lapuyade #define SHDLC_T2_VALUE_MS 300 113*4a61cd66SEric Lapuyade 114*4a61cd66SEric Lapuyade #define SHDLC_DUMP_SKB(info, skb) \ 115*4a61cd66SEric Lapuyade do { \ 116*4a61cd66SEric Lapuyade pr_debug("%s:\n", info); \ 117*4a61cd66SEric Lapuyade print_hex_dump(KERN_DEBUG, "shdlc: ", DUMP_PREFIX_OFFSET, \ 118*4a61cd66SEric Lapuyade 16, 1, skb->data, skb->len, 0); \ 119*4a61cd66SEric Lapuyade } while (0) 120*4a61cd66SEric Lapuyade 121*4a61cd66SEric Lapuyade /* checks x < y <= z modulo 8 */ 122*4a61cd66SEric Lapuyade static bool llc_shdlc_x_lt_y_lteq_z(int x, int y, int z) 123*4a61cd66SEric Lapuyade { 124*4a61cd66SEric Lapuyade if (x < z) 125*4a61cd66SEric Lapuyade return ((x < y) && (y <= z)) ? true : false; 126*4a61cd66SEric Lapuyade else 127*4a61cd66SEric Lapuyade return ((y > x) || (y <= z)) ? true : false; 128*4a61cd66SEric Lapuyade } 129*4a61cd66SEric Lapuyade 130*4a61cd66SEric Lapuyade /* checks x <= y < z modulo 8 */ 131*4a61cd66SEric Lapuyade static bool llc_shdlc_x_lteq_y_lt_z(int x, int y, int z) 132*4a61cd66SEric Lapuyade { 133*4a61cd66SEric Lapuyade if (x <= z) 134*4a61cd66SEric Lapuyade return ((x <= y) && (y < z)) ? true : false; 135*4a61cd66SEric Lapuyade else /* x > z -> z+8 > x */ 136*4a61cd66SEric Lapuyade return ((y >= x) || (y < z)) ? true : false; 137*4a61cd66SEric Lapuyade } 138*4a61cd66SEric Lapuyade 139*4a61cd66SEric Lapuyade static struct sk_buff *llc_shdlc_alloc_skb(struct llc_shdlc *shdlc, 140*4a61cd66SEric Lapuyade int payload_len) 141*4a61cd66SEric Lapuyade { 142*4a61cd66SEric Lapuyade struct sk_buff *skb; 143*4a61cd66SEric Lapuyade 144*4a61cd66SEric Lapuyade skb = alloc_skb(shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM + 145*4a61cd66SEric Lapuyade shdlc->tx_tailroom + payload_len, GFP_KERNEL); 146*4a61cd66SEric Lapuyade if (skb) 147*4a61cd66SEric Lapuyade skb_reserve(skb, shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM); 148*4a61cd66SEric Lapuyade 149*4a61cd66SEric Lapuyade return skb; 150*4a61cd66SEric Lapuyade } 151*4a61cd66SEric Lapuyade 152*4a61cd66SEric Lapuyade /* immediately sends an S frame. */ 153*4a61cd66SEric Lapuyade static int llc_shdlc_send_s_frame(struct llc_shdlc *shdlc, 154*4a61cd66SEric Lapuyade enum sframe_type sframe_type, int nr) 155*4a61cd66SEric Lapuyade { 156*4a61cd66SEric Lapuyade int r; 157*4a61cd66SEric Lapuyade struct sk_buff *skb; 158*4a61cd66SEric Lapuyade 159*4a61cd66SEric Lapuyade pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); 160*4a61cd66SEric Lapuyade 161*4a61cd66SEric Lapuyade skb = llc_shdlc_alloc_skb(shdlc, 0); 162*4a61cd66SEric Lapuyade if (skb == NULL) 163*4a61cd66SEric Lapuyade return -ENOMEM; 164*4a61cd66SEric Lapuyade 165*4a61cd66SEric Lapuyade *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; 166*4a61cd66SEric Lapuyade 167*4a61cd66SEric Lapuyade r = shdlc->xmit_to_drv(shdlc->hdev, skb); 168*4a61cd66SEric Lapuyade 169*4a61cd66SEric Lapuyade kfree_skb(skb); 170*4a61cd66SEric Lapuyade 171*4a61cd66SEric Lapuyade return r; 172*4a61cd66SEric Lapuyade } 173*4a61cd66SEric Lapuyade 174*4a61cd66SEric Lapuyade /* immediately sends an U frame. skb may contain optional payload */ 175*4a61cd66SEric Lapuyade static int llc_shdlc_send_u_frame(struct llc_shdlc *shdlc, 176*4a61cd66SEric Lapuyade struct sk_buff *skb, 177*4a61cd66SEric Lapuyade enum uframe_modifier uframe_modifier) 178*4a61cd66SEric Lapuyade { 179*4a61cd66SEric Lapuyade int r; 180*4a61cd66SEric Lapuyade 181*4a61cd66SEric Lapuyade pr_debug("uframe_modifier=%d\n", uframe_modifier); 182*4a61cd66SEric Lapuyade 183*4a61cd66SEric Lapuyade *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; 184*4a61cd66SEric Lapuyade 185*4a61cd66SEric Lapuyade r = shdlc->xmit_to_drv(shdlc->hdev, skb); 186*4a61cd66SEric Lapuyade 187*4a61cd66SEric Lapuyade kfree_skb(skb); 188*4a61cd66SEric Lapuyade 189*4a61cd66SEric Lapuyade return r; 190*4a61cd66SEric Lapuyade } 191*4a61cd66SEric Lapuyade 192*4a61cd66SEric Lapuyade /* 193*4a61cd66SEric Lapuyade * Free ack_pending frames until y_nr - 1, and reset t2 according to 194*4a61cd66SEric Lapuyade * the remaining oldest ack_pending frame sent time 195*4a61cd66SEric Lapuyade */ 196*4a61cd66SEric Lapuyade static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr) 197*4a61cd66SEric Lapuyade { 198*4a61cd66SEric Lapuyade struct sk_buff *skb; 199*4a61cd66SEric Lapuyade int dnr = shdlc->dnr; /* MUST initially be < y_nr */ 200*4a61cd66SEric Lapuyade 201*4a61cd66SEric Lapuyade pr_debug("release ack pending up to frame %d excluded\n", y_nr); 202*4a61cd66SEric Lapuyade 203*4a61cd66SEric Lapuyade while (dnr != y_nr) { 204*4a61cd66SEric Lapuyade pr_debug("release ack pending frame %d\n", dnr); 205*4a61cd66SEric Lapuyade 206*4a61cd66SEric Lapuyade skb = skb_dequeue(&shdlc->ack_pending_q); 207*4a61cd66SEric Lapuyade kfree_skb(skb); 208*4a61cd66SEric Lapuyade 209*4a61cd66SEric Lapuyade dnr = (dnr + 1) % 8; 210*4a61cd66SEric Lapuyade } 211*4a61cd66SEric Lapuyade 212*4a61cd66SEric Lapuyade if (skb_queue_empty(&shdlc->ack_pending_q)) { 213*4a61cd66SEric Lapuyade if (shdlc->t2_active) { 214*4a61cd66SEric Lapuyade del_timer_sync(&shdlc->t2_timer); 215*4a61cd66SEric Lapuyade shdlc->t2_active = false; 216*4a61cd66SEric Lapuyade 217*4a61cd66SEric Lapuyade pr_debug 218*4a61cd66SEric Lapuyade ("All sent frames acked. Stopped T2(retransmit)\n"); 219*4a61cd66SEric Lapuyade } 220*4a61cd66SEric Lapuyade } else { 221*4a61cd66SEric Lapuyade skb = skb_peek(&shdlc->ack_pending_q); 222*4a61cd66SEric Lapuyade 223*4a61cd66SEric Lapuyade mod_timer(&shdlc->t2_timer, *(unsigned long *)skb->cb + 224*4a61cd66SEric Lapuyade msecs_to_jiffies(SHDLC_T2_VALUE_MS)); 225*4a61cd66SEric Lapuyade shdlc->t2_active = true; 226*4a61cd66SEric Lapuyade 227*4a61cd66SEric Lapuyade pr_debug 228*4a61cd66SEric Lapuyade ("Start T2(retransmit) for remaining unacked sent frames\n"); 229*4a61cd66SEric Lapuyade } 230*4a61cd66SEric Lapuyade } 231*4a61cd66SEric Lapuyade 232*4a61cd66SEric Lapuyade /* 233*4a61cd66SEric Lapuyade * Receive validated frames from lower layer. skb contains HCI payload only. 234*4a61cd66SEric Lapuyade * Handle according to algorithm at spec:10.8.2 235*4a61cd66SEric Lapuyade */ 236*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_i_frame(struct llc_shdlc *shdlc, 237*4a61cd66SEric Lapuyade struct sk_buff *skb, int ns, int nr) 238*4a61cd66SEric Lapuyade { 239*4a61cd66SEric Lapuyade int x_ns = ns; 240*4a61cd66SEric Lapuyade int y_nr = nr; 241*4a61cd66SEric Lapuyade 242*4a61cd66SEric Lapuyade pr_debug("recvd I-frame %d, remote waiting frame %d\n", ns, nr); 243*4a61cd66SEric Lapuyade 244*4a61cd66SEric Lapuyade if (shdlc->state != SHDLC_CONNECTED) 245*4a61cd66SEric Lapuyade goto exit; 246*4a61cd66SEric Lapuyade 247*4a61cd66SEric Lapuyade if (x_ns != shdlc->nr) { 248*4a61cd66SEric Lapuyade llc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); 249*4a61cd66SEric Lapuyade goto exit; 250*4a61cd66SEric Lapuyade } 251*4a61cd66SEric Lapuyade 252*4a61cd66SEric Lapuyade if (shdlc->t1_active == false) { 253*4a61cd66SEric Lapuyade shdlc->t1_active = true; 254*4a61cd66SEric Lapuyade mod_timer(&shdlc->t1_timer, jiffies + 255*4a61cd66SEric Lapuyade msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); 256*4a61cd66SEric Lapuyade pr_debug("(re)Start T1(send ack)\n"); 257*4a61cd66SEric Lapuyade } 258*4a61cd66SEric Lapuyade 259*4a61cd66SEric Lapuyade if (skb->len) { 260*4a61cd66SEric Lapuyade shdlc->rcv_to_hci(shdlc->hdev, skb); 261*4a61cd66SEric Lapuyade skb = NULL; 262*4a61cd66SEric Lapuyade } 263*4a61cd66SEric Lapuyade 264*4a61cd66SEric Lapuyade shdlc->nr = (shdlc->nr + 1) % 8; 265*4a61cd66SEric Lapuyade 266*4a61cd66SEric Lapuyade if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { 267*4a61cd66SEric Lapuyade llc_shdlc_reset_t2(shdlc, y_nr); 268*4a61cd66SEric Lapuyade 269*4a61cd66SEric Lapuyade shdlc->dnr = y_nr; 270*4a61cd66SEric Lapuyade } 271*4a61cd66SEric Lapuyade 272*4a61cd66SEric Lapuyade exit: 273*4a61cd66SEric Lapuyade kfree_skb(skb); 274*4a61cd66SEric Lapuyade } 275*4a61cd66SEric Lapuyade 276*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_ack(struct llc_shdlc *shdlc, int y_nr) 277*4a61cd66SEric Lapuyade { 278*4a61cd66SEric Lapuyade pr_debug("remote acked up to frame %d excluded\n", y_nr); 279*4a61cd66SEric Lapuyade 280*4a61cd66SEric Lapuyade if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { 281*4a61cd66SEric Lapuyade llc_shdlc_reset_t2(shdlc, y_nr); 282*4a61cd66SEric Lapuyade shdlc->dnr = y_nr; 283*4a61cd66SEric Lapuyade } 284*4a61cd66SEric Lapuyade } 285*4a61cd66SEric Lapuyade 286*4a61cd66SEric Lapuyade static void llc_shdlc_requeue_ack_pending(struct llc_shdlc *shdlc) 287*4a61cd66SEric Lapuyade { 288*4a61cd66SEric Lapuyade struct sk_buff *skb; 289*4a61cd66SEric Lapuyade 290*4a61cd66SEric Lapuyade pr_debug("ns reset to %d\n", shdlc->dnr); 291*4a61cd66SEric Lapuyade 292*4a61cd66SEric Lapuyade while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { 293*4a61cd66SEric Lapuyade skb_pull(skb, 1); /* remove control field */ 294*4a61cd66SEric Lapuyade skb_queue_head(&shdlc->send_q, skb); 295*4a61cd66SEric Lapuyade } 296*4a61cd66SEric Lapuyade shdlc->ns = shdlc->dnr; 297*4a61cd66SEric Lapuyade } 298*4a61cd66SEric Lapuyade 299*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr) 300*4a61cd66SEric Lapuyade { 301*4a61cd66SEric Lapuyade struct sk_buff *skb; 302*4a61cd66SEric Lapuyade 303*4a61cd66SEric Lapuyade pr_debug("remote asks retransmition from frame %d\n", y_nr); 304*4a61cd66SEric Lapuyade 305*4a61cd66SEric Lapuyade if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { 306*4a61cd66SEric Lapuyade if (shdlc->t2_active) { 307*4a61cd66SEric Lapuyade del_timer_sync(&shdlc->t2_timer); 308*4a61cd66SEric Lapuyade shdlc->t2_active = false; 309*4a61cd66SEric Lapuyade pr_debug("Stopped T2(retransmit)\n"); 310*4a61cd66SEric Lapuyade } 311*4a61cd66SEric Lapuyade 312*4a61cd66SEric Lapuyade if (shdlc->dnr != y_nr) { 313*4a61cd66SEric Lapuyade while ((shdlc->dnr = ((shdlc->dnr + 1) % 8)) != y_nr) { 314*4a61cd66SEric Lapuyade skb = skb_dequeue(&shdlc->ack_pending_q); 315*4a61cd66SEric Lapuyade kfree_skb(skb); 316*4a61cd66SEric Lapuyade } 317*4a61cd66SEric Lapuyade } 318*4a61cd66SEric Lapuyade 319*4a61cd66SEric Lapuyade llc_shdlc_requeue_ack_pending(shdlc); 320*4a61cd66SEric Lapuyade } 321*4a61cd66SEric Lapuyade } 322*4a61cd66SEric Lapuyade 323*4a61cd66SEric Lapuyade /* See spec RR:10.8.3 REJ:10.8.4 */ 324*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_s_frame(struct llc_shdlc *shdlc, 325*4a61cd66SEric Lapuyade enum sframe_type s_frame_type, int nr) 326*4a61cd66SEric Lapuyade { 327*4a61cd66SEric Lapuyade struct sk_buff *skb; 328*4a61cd66SEric Lapuyade 329*4a61cd66SEric Lapuyade if (shdlc->state != SHDLC_CONNECTED) 330*4a61cd66SEric Lapuyade return; 331*4a61cd66SEric Lapuyade 332*4a61cd66SEric Lapuyade switch (s_frame_type) { 333*4a61cd66SEric Lapuyade case S_FRAME_RR: 334*4a61cd66SEric Lapuyade llc_shdlc_rcv_ack(shdlc, nr); 335*4a61cd66SEric Lapuyade if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ 336*4a61cd66SEric Lapuyade shdlc->rnr = false; 337*4a61cd66SEric Lapuyade if (shdlc->send_q.qlen == 0) { 338*4a61cd66SEric Lapuyade skb = llc_shdlc_alloc_skb(shdlc, 0); 339*4a61cd66SEric Lapuyade if (skb) 340*4a61cd66SEric Lapuyade skb_queue_tail(&shdlc->send_q, skb); 341*4a61cd66SEric Lapuyade } 342*4a61cd66SEric Lapuyade } 343*4a61cd66SEric Lapuyade break; 344*4a61cd66SEric Lapuyade case S_FRAME_REJ: 345*4a61cd66SEric Lapuyade llc_shdlc_rcv_rej(shdlc, nr); 346*4a61cd66SEric Lapuyade break; 347*4a61cd66SEric Lapuyade case S_FRAME_RNR: 348*4a61cd66SEric Lapuyade llc_shdlc_rcv_ack(shdlc, nr); 349*4a61cd66SEric Lapuyade shdlc->rnr = true; 350*4a61cd66SEric Lapuyade break; 351*4a61cd66SEric Lapuyade default: 352*4a61cd66SEric Lapuyade break; 353*4a61cd66SEric Lapuyade } 354*4a61cd66SEric Lapuyade } 355*4a61cd66SEric Lapuyade 356*4a61cd66SEric Lapuyade static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r) 357*4a61cd66SEric Lapuyade { 358*4a61cd66SEric Lapuyade pr_debug("result=%d\n", r); 359*4a61cd66SEric Lapuyade 360*4a61cd66SEric Lapuyade del_timer_sync(&shdlc->connect_timer); 361*4a61cd66SEric Lapuyade 362*4a61cd66SEric Lapuyade if (r == 0) { 363*4a61cd66SEric Lapuyade shdlc->ns = 0; 364*4a61cd66SEric Lapuyade shdlc->nr = 0; 365*4a61cd66SEric Lapuyade shdlc->dnr = 0; 366*4a61cd66SEric Lapuyade 367*4a61cd66SEric Lapuyade shdlc->state = SHDLC_CONNECTED; 368*4a61cd66SEric Lapuyade } else { 369*4a61cd66SEric Lapuyade shdlc->state = SHDLC_DISCONNECTED; 370*4a61cd66SEric Lapuyade } 371*4a61cd66SEric Lapuyade 372*4a61cd66SEric Lapuyade shdlc->connect_result = r; 373*4a61cd66SEric Lapuyade 374*4a61cd66SEric Lapuyade wake_up(shdlc->connect_wq); 375*4a61cd66SEric Lapuyade } 376*4a61cd66SEric Lapuyade 377*4a61cd66SEric Lapuyade static int llc_shdlc_connect_initiate(struct llc_shdlc *shdlc) 378*4a61cd66SEric Lapuyade { 379*4a61cd66SEric Lapuyade struct sk_buff *skb; 380*4a61cd66SEric Lapuyade 381*4a61cd66SEric Lapuyade pr_debug("\n"); 382*4a61cd66SEric Lapuyade 383*4a61cd66SEric Lapuyade skb = llc_shdlc_alloc_skb(shdlc, 2); 384*4a61cd66SEric Lapuyade if (skb == NULL) 385*4a61cd66SEric Lapuyade return -ENOMEM; 386*4a61cd66SEric Lapuyade 387*4a61cd66SEric Lapuyade *skb_put(skb, 1) = SHDLC_MAX_WINDOW; 388*4a61cd66SEric Lapuyade *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; 389*4a61cd66SEric Lapuyade 390*4a61cd66SEric Lapuyade return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); 391*4a61cd66SEric Lapuyade } 392*4a61cd66SEric Lapuyade 393*4a61cd66SEric Lapuyade static int llc_shdlc_connect_send_ua(struct llc_shdlc *shdlc) 394*4a61cd66SEric Lapuyade { 395*4a61cd66SEric Lapuyade struct sk_buff *skb; 396*4a61cd66SEric Lapuyade 397*4a61cd66SEric Lapuyade pr_debug("\n"); 398*4a61cd66SEric Lapuyade 399*4a61cd66SEric Lapuyade skb = llc_shdlc_alloc_skb(shdlc, 0); 400*4a61cd66SEric Lapuyade if (skb == NULL) 401*4a61cd66SEric Lapuyade return -ENOMEM; 402*4a61cd66SEric Lapuyade 403*4a61cd66SEric Lapuyade return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); 404*4a61cd66SEric Lapuyade } 405*4a61cd66SEric Lapuyade 406*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc, 407*4a61cd66SEric Lapuyade struct sk_buff *skb, 408*4a61cd66SEric Lapuyade enum uframe_modifier u_frame_modifier) 409*4a61cd66SEric Lapuyade { 410*4a61cd66SEric Lapuyade u8 w = SHDLC_MAX_WINDOW; 411*4a61cd66SEric Lapuyade bool srej_support = SHDLC_SREJ_SUPPORT; 412*4a61cd66SEric Lapuyade int r; 413*4a61cd66SEric Lapuyade 414*4a61cd66SEric Lapuyade pr_debug("u_frame_modifier=%d\n", u_frame_modifier); 415*4a61cd66SEric Lapuyade 416*4a61cd66SEric Lapuyade switch (u_frame_modifier) { 417*4a61cd66SEric Lapuyade case U_FRAME_RSET: 418*4a61cd66SEric Lapuyade if (shdlc->state == SHDLC_NEGOCIATING) { 419*4a61cd66SEric Lapuyade /* we sent RSET, but chip wants to negociate */ 420*4a61cd66SEric Lapuyade if (skb->len > 0) 421*4a61cd66SEric Lapuyade w = skb->data[0]; 422*4a61cd66SEric Lapuyade 423*4a61cd66SEric Lapuyade if (skb->len > 1) 424*4a61cd66SEric Lapuyade srej_support = skb->data[1] & 0x01 ? true : 425*4a61cd66SEric Lapuyade false; 426*4a61cd66SEric Lapuyade 427*4a61cd66SEric Lapuyade if ((w <= SHDLC_MAX_WINDOW) && 428*4a61cd66SEric Lapuyade (SHDLC_SREJ_SUPPORT || (srej_support == false))) { 429*4a61cd66SEric Lapuyade shdlc->w = w; 430*4a61cd66SEric Lapuyade shdlc->srej_support = srej_support; 431*4a61cd66SEric Lapuyade r = llc_shdlc_connect_send_ua(shdlc); 432*4a61cd66SEric Lapuyade llc_shdlc_connect_complete(shdlc, r); 433*4a61cd66SEric Lapuyade } 434*4a61cd66SEric Lapuyade } else if (shdlc->state == SHDLC_CONNECTED) { 435*4a61cd66SEric Lapuyade /* 436*4a61cd66SEric Lapuyade * Chip wants to reset link. This is unexpected and 437*4a61cd66SEric Lapuyade * unsupported. 438*4a61cd66SEric Lapuyade */ 439*4a61cd66SEric Lapuyade shdlc->hard_fault = -ECONNRESET; 440*4a61cd66SEric Lapuyade } 441*4a61cd66SEric Lapuyade break; 442*4a61cd66SEric Lapuyade case U_FRAME_UA: 443*4a61cd66SEric Lapuyade if ((shdlc->state == SHDLC_CONNECTING && 444*4a61cd66SEric Lapuyade shdlc->connect_tries > 0) || 445*4a61cd66SEric Lapuyade (shdlc->state == SHDLC_NEGOCIATING)) 446*4a61cd66SEric Lapuyade llc_shdlc_connect_complete(shdlc, 0); 447*4a61cd66SEric Lapuyade break; 448*4a61cd66SEric Lapuyade default: 449*4a61cd66SEric Lapuyade break; 450*4a61cd66SEric Lapuyade } 451*4a61cd66SEric Lapuyade 452*4a61cd66SEric Lapuyade kfree_skb(skb); 453*4a61cd66SEric Lapuyade } 454*4a61cd66SEric Lapuyade 455*4a61cd66SEric Lapuyade static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc) 456*4a61cd66SEric Lapuyade { 457*4a61cd66SEric Lapuyade struct sk_buff *skb; 458*4a61cd66SEric Lapuyade u8 control; 459*4a61cd66SEric Lapuyade int nr; 460*4a61cd66SEric Lapuyade int ns; 461*4a61cd66SEric Lapuyade enum sframe_type s_frame_type; 462*4a61cd66SEric Lapuyade enum uframe_modifier u_frame_modifier; 463*4a61cd66SEric Lapuyade 464*4a61cd66SEric Lapuyade if (shdlc->rcv_q.qlen) 465*4a61cd66SEric Lapuyade pr_debug("rcvQlen=%d\n", shdlc->rcv_q.qlen); 466*4a61cd66SEric Lapuyade 467*4a61cd66SEric Lapuyade while ((skb = skb_dequeue(&shdlc->rcv_q)) != NULL) { 468*4a61cd66SEric Lapuyade control = skb->data[0]; 469*4a61cd66SEric Lapuyade skb_pull(skb, 1); 470*4a61cd66SEric Lapuyade switch (control & SHDLC_CONTROL_HEAD_MASK) { 471*4a61cd66SEric Lapuyade case SHDLC_CONTROL_HEAD_I: 472*4a61cd66SEric Lapuyade case SHDLC_CONTROL_HEAD_I2: 473*4a61cd66SEric Lapuyade ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; 474*4a61cd66SEric Lapuyade nr = control & SHDLC_CONTROL_NR_MASK; 475*4a61cd66SEric Lapuyade llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); 476*4a61cd66SEric Lapuyade break; 477*4a61cd66SEric Lapuyade case SHDLC_CONTROL_HEAD_S: 478*4a61cd66SEric Lapuyade s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; 479*4a61cd66SEric Lapuyade nr = control & SHDLC_CONTROL_NR_MASK; 480*4a61cd66SEric Lapuyade llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); 481*4a61cd66SEric Lapuyade kfree_skb(skb); 482*4a61cd66SEric Lapuyade break; 483*4a61cd66SEric Lapuyade case SHDLC_CONTROL_HEAD_U: 484*4a61cd66SEric Lapuyade u_frame_modifier = control & SHDLC_CONTROL_M_MASK; 485*4a61cd66SEric Lapuyade llc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); 486*4a61cd66SEric Lapuyade break; 487*4a61cd66SEric Lapuyade default: 488*4a61cd66SEric Lapuyade pr_err("UNKNOWN Control=%d\n", control); 489*4a61cd66SEric Lapuyade kfree_skb(skb); 490*4a61cd66SEric Lapuyade break; 491*4a61cd66SEric Lapuyade } 492*4a61cd66SEric Lapuyade } 493*4a61cd66SEric Lapuyade } 494*4a61cd66SEric Lapuyade 495*4a61cd66SEric Lapuyade static int llc_shdlc_w_used(int ns, int dnr) 496*4a61cd66SEric Lapuyade { 497*4a61cd66SEric Lapuyade int unack_count; 498*4a61cd66SEric Lapuyade 499*4a61cd66SEric Lapuyade if (dnr <= ns) 500*4a61cd66SEric Lapuyade unack_count = ns - dnr; 501*4a61cd66SEric Lapuyade else 502*4a61cd66SEric Lapuyade unack_count = 8 - dnr + ns; 503*4a61cd66SEric Lapuyade 504*4a61cd66SEric Lapuyade return unack_count; 505*4a61cd66SEric Lapuyade } 506*4a61cd66SEric Lapuyade 507*4a61cd66SEric Lapuyade /* Send frames according to algorithm at spec:10.8.1 */ 508*4a61cd66SEric Lapuyade static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) 509*4a61cd66SEric Lapuyade { 510*4a61cd66SEric Lapuyade struct sk_buff *skb; 511*4a61cd66SEric Lapuyade int r; 512*4a61cd66SEric Lapuyade unsigned long time_sent; 513*4a61cd66SEric Lapuyade 514*4a61cd66SEric Lapuyade if (shdlc->send_q.qlen) 515*4a61cd66SEric Lapuyade pr_debug 516*4a61cd66SEric Lapuyade ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", 517*4a61cd66SEric Lapuyade shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, 518*4a61cd66SEric Lapuyade shdlc->rnr == false ? "false" : "true", 519*4a61cd66SEric Lapuyade shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr), 520*4a61cd66SEric Lapuyade shdlc->ack_pending_q.qlen); 521*4a61cd66SEric Lapuyade 522*4a61cd66SEric Lapuyade while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && 523*4a61cd66SEric Lapuyade (shdlc->rnr == false)) { 524*4a61cd66SEric Lapuyade 525*4a61cd66SEric Lapuyade if (shdlc->t1_active) { 526*4a61cd66SEric Lapuyade del_timer_sync(&shdlc->t1_timer); 527*4a61cd66SEric Lapuyade shdlc->t1_active = false; 528*4a61cd66SEric Lapuyade pr_debug("Stopped T1(send ack)\n"); 529*4a61cd66SEric Lapuyade } 530*4a61cd66SEric Lapuyade 531*4a61cd66SEric Lapuyade skb = skb_dequeue(&shdlc->send_q); 532*4a61cd66SEric Lapuyade 533*4a61cd66SEric Lapuyade *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_I | (shdlc->ns << 3) | 534*4a61cd66SEric Lapuyade shdlc->nr; 535*4a61cd66SEric Lapuyade 536*4a61cd66SEric Lapuyade pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, 537*4a61cd66SEric Lapuyade shdlc->nr); 538*4a61cd66SEric Lapuyade /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ 539*4a61cd66SEric Lapuyade 540*4a61cd66SEric Lapuyade r = shdlc->xmit_to_drv(shdlc->hdev, skb); 541*4a61cd66SEric Lapuyade if (r < 0) { 542*4a61cd66SEric Lapuyade shdlc->hard_fault = r; 543*4a61cd66SEric Lapuyade break; 544*4a61cd66SEric Lapuyade } 545*4a61cd66SEric Lapuyade 546*4a61cd66SEric Lapuyade shdlc->ns = (shdlc->ns + 1) % 8; 547*4a61cd66SEric Lapuyade 548*4a61cd66SEric Lapuyade time_sent = jiffies; 549*4a61cd66SEric Lapuyade *(unsigned long *)skb->cb = time_sent; 550*4a61cd66SEric Lapuyade 551*4a61cd66SEric Lapuyade skb_queue_tail(&shdlc->ack_pending_q, skb); 552*4a61cd66SEric Lapuyade 553*4a61cd66SEric Lapuyade if (shdlc->t2_active == false) { 554*4a61cd66SEric Lapuyade shdlc->t2_active = true; 555*4a61cd66SEric Lapuyade mod_timer(&shdlc->t2_timer, time_sent + 556*4a61cd66SEric Lapuyade msecs_to_jiffies(SHDLC_T2_VALUE_MS)); 557*4a61cd66SEric Lapuyade pr_debug("Started T2 (retransmit)\n"); 558*4a61cd66SEric Lapuyade } 559*4a61cd66SEric Lapuyade } 560*4a61cd66SEric Lapuyade } 561*4a61cd66SEric Lapuyade 562*4a61cd66SEric Lapuyade static void llc_shdlc_connect_timeout(unsigned long data) 563*4a61cd66SEric Lapuyade { 564*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = (struct llc_shdlc *)data; 565*4a61cd66SEric Lapuyade 566*4a61cd66SEric Lapuyade pr_debug("\n"); 567*4a61cd66SEric Lapuyade 568*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 569*4a61cd66SEric Lapuyade } 570*4a61cd66SEric Lapuyade 571*4a61cd66SEric Lapuyade static void llc_shdlc_t1_timeout(unsigned long data) 572*4a61cd66SEric Lapuyade { 573*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = (struct llc_shdlc *)data; 574*4a61cd66SEric Lapuyade 575*4a61cd66SEric Lapuyade pr_debug("SoftIRQ: need to send ack\n"); 576*4a61cd66SEric Lapuyade 577*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 578*4a61cd66SEric Lapuyade } 579*4a61cd66SEric Lapuyade 580*4a61cd66SEric Lapuyade static void llc_shdlc_t2_timeout(unsigned long data) 581*4a61cd66SEric Lapuyade { 582*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = (struct llc_shdlc *)data; 583*4a61cd66SEric Lapuyade 584*4a61cd66SEric Lapuyade pr_debug("SoftIRQ: need to retransmit\n"); 585*4a61cd66SEric Lapuyade 586*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 587*4a61cd66SEric Lapuyade } 588*4a61cd66SEric Lapuyade 589*4a61cd66SEric Lapuyade static void llc_shdlc_sm_work(struct work_struct *work) 590*4a61cd66SEric Lapuyade { 591*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = container_of(work, struct llc_shdlc, sm_work); 592*4a61cd66SEric Lapuyade int r; 593*4a61cd66SEric Lapuyade 594*4a61cd66SEric Lapuyade pr_debug("\n"); 595*4a61cd66SEric Lapuyade 596*4a61cd66SEric Lapuyade mutex_lock(&shdlc->state_mutex); 597*4a61cd66SEric Lapuyade 598*4a61cd66SEric Lapuyade switch (shdlc->state) { 599*4a61cd66SEric Lapuyade case SHDLC_DISCONNECTED: 600*4a61cd66SEric Lapuyade skb_queue_purge(&shdlc->rcv_q); 601*4a61cd66SEric Lapuyade skb_queue_purge(&shdlc->send_q); 602*4a61cd66SEric Lapuyade skb_queue_purge(&shdlc->ack_pending_q); 603*4a61cd66SEric Lapuyade break; 604*4a61cd66SEric Lapuyade case SHDLC_CONNECTING: 605*4a61cd66SEric Lapuyade if (shdlc->hard_fault) { 606*4a61cd66SEric Lapuyade llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); 607*4a61cd66SEric Lapuyade break; 608*4a61cd66SEric Lapuyade } 609*4a61cd66SEric Lapuyade 610*4a61cd66SEric Lapuyade if (shdlc->connect_tries++ < 5) 611*4a61cd66SEric Lapuyade r = llc_shdlc_connect_initiate(shdlc); 612*4a61cd66SEric Lapuyade else 613*4a61cd66SEric Lapuyade r = -ETIME; 614*4a61cd66SEric Lapuyade if (r < 0) 615*4a61cd66SEric Lapuyade llc_shdlc_connect_complete(shdlc, r); 616*4a61cd66SEric Lapuyade else { 617*4a61cd66SEric Lapuyade mod_timer(&shdlc->connect_timer, jiffies + 618*4a61cd66SEric Lapuyade msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); 619*4a61cd66SEric Lapuyade 620*4a61cd66SEric Lapuyade shdlc->state = SHDLC_NEGOCIATING; 621*4a61cd66SEric Lapuyade } 622*4a61cd66SEric Lapuyade break; 623*4a61cd66SEric Lapuyade case SHDLC_NEGOCIATING: 624*4a61cd66SEric Lapuyade if (timer_pending(&shdlc->connect_timer) == 0) { 625*4a61cd66SEric Lapuyade shdlc->state = SHDLC_CONNECTING; 626*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 627*4a61cd66SEric Lapuyade } 628*4a61cd66SEric Lapuyade 629*4a61cd66SEric Lapuyade llc_shdlc_handle_rcv_queue(shdlc); 630*4a61cd66SEric Lapuyade 631*4a61cd66SEric Lapuyade if (shdlc->hard_fault) { 632*4a61cd66SEric Lapuyade llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); 633*4a61cd66SEric Lapuyade break; 634*4a61cd66SEric Lapuyade } 635*4a61cd66SEric Lapuyade break; 636*4a61cd66SEric Lapuyade case SHDLC_CONNECTED: 637*4a61cd66SEric Lapuyade llc_shdlc_handle_rcv_queue(shdlc); 638*4a61cd66SEric Lapuyade llc_shdlc_handle_send_queue(shdlc); 639*4a61cd66SEric Lapuyade 640*4a61cd66SEric Lapuyade if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { 641*4a61cd66SEric Lapuyade pr_debug 642*4a61cd66SEric Lapuyade ("Handle T1(send ack) elapsed (T1 now inactive)\n"); 643*4a61cd66SEric Lapuyade 644*4a61cd66SEric Lapuyade shdlc->t1_active = false; 645*4a61cd66SEric Lapuyade r = llc_shdlc_send_s_frame(shdlc, S_FRAME_RR, 646*4a61cd66SEric Lapuyade shdlc->nr); 647*4a61cd66SEric Lapuyade if (r < 0) 648*4a61cd66SEric Lapuyade shdlc->hard_fault = r; 649*4a61cd66SEric Lapuyade } 650*4a61cd66SEric Lapuyade 651*4a61cd66SEric Lapuyade if (shdlc->t2_active && timer_pending(&shdlc->t2_timer) == 0) { 652*4a61cd66SEric Lapuyade pr_debug 653*4a61cd66SEric Lapuyade ("Handle T2(retransmit) elapsed (T2 inactive)\n"); 654*4a61cd66SEric Lapuyade 655*4a61cd66SEric Lapuyade shdlc->t2_active = false; 656*4a61cd66SEric Lapuyade 657*4a61cd66SEric Lapuyade llc_shdlc_requeue_ack_pending(shdlc); 658*4a61cd66SEric Lapuyade llc_shdlc_handle_send_queue(shdlc); 659*4a61cd66SEric Lapuyade } 660*4a61cd66SEric Lapuyade 661*4a61cd66SEric Lapuyade if (shdlc->hard_fault) { 662*4a61cd66SEric Lapuyade shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault); 663*4a61cd66SEric Lapuyade } 664*4a61cd66SEric Lapuyade break; 665*4a61cd66SEric Lapuyade default: 666*4a61cd66SEric Lapuyade break; 667*4a61cd66SEric Lapuyade } 668*4a61cd66SEric Lapuyade mutex_unlock(&shdlc->state_mutex); 669*4a61cd66SEric Lapuyade } 670*4a61cd66SEric Lapuyade 671*4a61cd66SEric Lapuyade /* 672*4a61cd66SEric Lapuyade * Called from syscall context to establish shdlc link. Sleeps until 673*4a61cd66SEric Lapuyade * link is ready or failure. 674*4a61cd66SEric Lapuyade */ 675*4a61cd66SEric Lapuyade static int llc_shdlc_connect(struct llc_shdlc *shdlc) 676*4a61cd66SEric Lapuyade { 677*4a61cd66SEric Lapuyade DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); 678*4a61cd66SEric Lapuyade 679*4a61cd66SEric Lapuyade pr_debug("\n"); 680*4a61cd66SEric Lapuyade 681*4a61cd66SEric Lapuyade mutex_lock(&shdlc->state_mutex); 682*4a61cd66SEric Lapuyade 683*4a61cd66SEric Lapuyade shdlc->state = SHDLC_CONNECTING; 684*4a61cd66SEric Lapuyade shdlc->connect_wq = &connect_wq; 685*4a61cd66SEric Lapuyade shdlc->connect_tries = 0; 686*4a61cd66SEric Lapuyade shdlc->connect_result = 1; 687*4a61cd66SEric Lapuyade 688*4a61cd66SEric Lapuyade mutex_unlock(&shdlc->state_mutex); 689*4a61cd66SEric Lapuyade 690*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 691*4a61cd66SEric Lapuyade 692*4a61cd66SEric Lapuyade wait_event(connect_wq, shdlc->connect_result != 1); 693*4a61cd66SEric Lapuyade 694*4a61cd66SEric Lapuyade return shdlc->connect_result; 695*4a61cd66SEric Lapuyade } 696*4a61cd66SEric Lapuyade 697*4a61cd66SEric Lapuyade static void llc_shdlc_disconnect(struct llc_shdlc *shdlc) 698*4a61cd66SEric Lapuyade { 699*4a61cd66SEric Lapuyade pr_debug("\n"); 700*4a61cd66SEric Lapuyade 701*4a61cd66SEric Lapuyade mutex_lock(&shdlc->state_mutex); 702*4a61cd66SEric Lapuyade 703*4a61cd66SEric Lapuyade shdlc->state = SHDLC_DISCONNECTED; 704*4a61cd66SEric Lapuyade 705*4a61cd66SEric Lapuyade mutex_unlock(&shdlc->state_mutex); 706*4a61cd66SEric Lapuyade 707*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 708*4a61cd66SEric Lapuyade } 709*4a61cd66SEric Lapuyade 710*4a61cd66SEric Lapuyade /* 711*4a61cd66SEric Lapuyade * Receive an incoming shdlc frame. Frame has already been crc-validated. 712*4a61cd66SEric Lapuyade * skb contains only LLC header and payload. 713*4a61cd66SEric Lapuyade * If skb == NULL, it is a notification that the link below is dead. 714*4a61cd66SEric Lapuyade */ 715*4a61cd66SEric Lapuyade static void llc_shdlc_recv_frame(struct llc_shdlc *shdlc, struct sk_buff *skb) 716*4a61cd66SEric Lapuyade { 717*4a61cd66SEric Lapuyade if (skb == NULL) { 718*4a61cd66SEric Lapuyade pr_err("NULL Frame -> link is dead\n"); 719*4a61cd66SEric Lapuyade shdlc->hard_fault = -EREMOTEIO; 720*4a61cd66SEric Lapuyade } else { 721*4a61cd66SEric Lapuyade SHDLC_DUMP_SKB("incoming frame", skb); 722*4a61cd66SEric Lapuyade skb_queue_tail(&shdlc->rcv_q, skb); 723*4a61cd66SEric Lapuyade } 724*4a61cd66SEric Lapuyade 725*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 726*4a61cd66SEric Lapuyade } 727*4a61cd66SEric Lapuyade 728*4a61cd66SEric Lapuyade static void *llc_shdlc_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, 729*4a61cd66SEric Lapuyade rcv_to_hci_t rcv_to_hci, int tx_headroom, 730*4a61cd66SEric Lapuyade int tx_tailroom, int *rx_headroom, int *rx_tailroom, 731*4a61cd66SEric Lapuyade llc_failure_t llc_failure) 732*4a61cd66SEric Lapuyade { 733*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc; 734*4a61cd66SEric Lapuyade 735*4a61cd66SEric Lapuyade *rx_headroom = SHDLC_LLC_HEAD_ROOM; 736*4a61cd66SEric Lapuyade *rx_tailroom = 0; 737*4a61cd66SEric Lapuyade 738*4a61cd66SEric Lapuyade shdlc = kzalloc(sizeof(struct llc_shdlc), GFP_KERNEL); 739*4a61cd66SEric Lapuyade if (shdlc == NULL) 740*4a61cd66SEric Lapuyade return NULL; 741*4a61cd66SEric Lapuyade 742*4a61cd66SEric Lapuyade mutex_init(&shdlc->state_mutex); 743*4a61cd66SEric Lapuyade shdlc->state = SHDLC_DISCONNECTED; 744*4a61cd66SEric Lapuyade 745*4a61cd66SEric Lapuyade init_timer(&shdlc->connect_timer); 746*4a61cd66SEric Lapuyade shdlc->connect_timer.data = (unsigned long)shdlc; 747*4a61cd66SEric Lapuyade shdlc->connect_timer.function = llc_shdlc_connect_timeout; 748*4a61cd66SEric Lapuyade 749*4a61cd66SEric Lapuyade init_timer(&shdlc->t1_timer); 750*4a61cd66SEric Lapuyade shdlc->t1_timer.data = (unsigned long)shdlc; 751*4a61cd66SEric Lapuyade shdlc->t1_timer.function = llc_shdlc_t1_timeout; 752*4a61cd66SEric Lapuyade 753*4a61cd66SEric Lapuyade init_timer(&shdlc->t2_timer); 754*4a61cd66SEric Lapuyade shdlc->t2_timer.data = (unsigned long)shdlc; 755*4a61cd66SEric Lapuyade shdlc->t2_timer.function = llc_shdlc_t2_timeout; 756*4a61cd66SEric Lapuyade 757*4a61cd66SEric Lapuyade shdlc->w = SHDLC_MAX_WINDOW; 758*4a61cd66SEric Lapuyade shdlc->srej_support = SHDLC_SREJ_SUPPORT; 759*4a61cd66SEric Lapuyade 760*4a61cd66SEric Lapuyade skb_queue_head_init(&shdlc->rcv_q); 761*4a61cd66SEric Lapuyade skb_queue_head_init(&shdlc->send_q); 762*4a61cd66SEric Lapuyade skb_queue_head_init(&shdlc->ack_pending_q); 763*4a61cd66SEric Lapuyade 764*4a61cd66SEric Lapuyade INIT_WORK(&shdlc->sm_work, llc_shdlc_sm_work); 765*4a61cd66SEric Lapuyade 766*4a61cd66SEric Lapuyade shdlc->hdev = hdev; 767*4a61cd66SEric Lapuyade shdlc->xmit_to_drv = xmit_to_drv; 768*4a61cd66SEric Lapuyade shdlc->rcv_to_hci = rcv_to_hci; 769*4a61cd66SEric Lapuyade shdlc->tx_headroom = tx_headroom; 770*4a61cd66SEric Lapuyade shdlc->tx_tailroom = tx_tailroom; 771*4a61cd66SEric Lapuyade shdlc->llc_failure = llc_failure; 772*4a61cd66SEric Lapuyade 773*4a61cd66SEric Lapuyade return shdlc; 774*4a61cd66SEric Lapuyade } 775*4a61cd66SEric Lapuyade 776*4a61cd66SEric Lapuyade static void llc_shdlc_deinit(struct nfc_llc *llc) 777*4a61cd66SEric Lapuyade { 778*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = nfc_llc_get_data(llc); 779*4a61cd66SEric Lapuyade 780*4a61cd66SEric Lapuyade skb_queue_purge(&shdlc->rcv_q); 781*4a61cd66SEric Lapuyade skb_queue_purge(&shdlc->send_q); 782*4a61cd66SEric Lapuyade skb_queue_purge(&shdlc->ack_pending_q); 783*4a61cd66SEric Lapuyade 784*4a61cd66SEric Lapuyade kfree(shdlc); 785*4a61cd66SEric Lapuyade } 786*4a61cd66SEric Lapuyade 787*4a61cd66SEric Lapuyade static int llc_shdlc_start(struct nfc_llc *llc) 788*4a61cd66SEric Lapuyade { 789*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = nfc_llc_get_data(llc); 790*4a61cd66SEric Lapuyade 791*4a61cd66SEric Lapuyade return llc_shdlc_connect(shdlc); 792*4a61cd66SEric Lapuyade } 793*4a61cd66SEric Lapuyade 794*4a61cd66SEric Lapuyade static int llc_shdlc_stop(struct nfc_llc *llc) 795*4a61cd66SEric Lapuyade { 796*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = nfc_llc_get_data(llc); 797*4a61cd66SEric Lapuyade 798*4a61cd66SEric Lapuyade llc_shdlc_disconnect(shdlc); 799*4a61cd66SEric Lapuyade 800*4a61cd66SEric Lapuyade return 0; 801*4a61cd66SEric Lapuyade } 802*4a61cd66SEric Lapuyade 803*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) 804*4a61cd66SEric Lapuyade { 805*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = nfc_llc_get_data(llc); 806*4a61cd66SEric Lapuyade 807*4a61cd66SEric Lapuyade llc_shdlc_recv_frame(shdlc, skb); 808*4a61cd66SEric Lapuyade } 809*4a61cd66SEric Lapuyade 810*4a61cd66SEric Lapuyade static int llc_shdlc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) 811*4a61cd66SEric Lapuyade { 812*4a61cd66SEric Lapuyade struct llc_shdlc *shdlc = nfc_llc_get_data(llc); 813*4a61cd66SEric Lapuyade 814*4a61cd66SEric Lapuyade skb_queue_tail(&shdlc->send_q, skb); 815*4a61cd66SEric Lapuyade 816*4a61cd66SEric Lapuyade queue_work(system_nrt_wq, &shdlc->sm_work); 817*4a61cd66SEric Lapuyade 818*4a61cd66SEric Lapuyade return 0; 819*4a61cd66SEric Lapuyade } 820*4a61cd66SEric Lapuyade 821*4a61cd66SEric Lapuyade static struct nfc_llc_ops llc_shdlc_ops = { 822*4a61cd66SEric Lapuyade .init = llc_shdlc_init, 823*4a61cd66SEric Lapuyade .deinit = llc_shdlc_deinit, 824*4a61cd66SEric Lapuyade .start = llc_shdlc_start, 825*4a61cd66SEric Lapuyade .stop = llc_shdlc_stop, 826*4a61cd66SEric Lapuyade .rcv_from_drv = llc_shdlc_rcv_from_drv, 827*4a61cd66SEric Lapuyade .xmit_from_hci = llc_shdlc_xmit_from_hci, 828*4a61cd66SEric Lapuyade }; 829*4a61cd66SEric Lapuyade 830*4a61cd66SEric Lapuyade int nfc_llc_shdlc_register() 831*4a61cd66SEric Lapuyade { 832*4a61cd66SEric Lapuyade return nfc_llc_register(LLC_SHDLC_NAME, &llc_shdlc_ops); 833*4a61cd66SEric Lapuyade } 834*4a61cd66SEric Lapuyade EXPORT_SYMBOL(nfc_llc_shdlc_register); 835