18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * LAPB release 002 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This code REQUIRES 2.1.15 or higher/ NET3.038 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * History 88c2ecf20Sopenharmony_ci * LAPB 001 Jonathan Naulor Started Coding 98c2ecf20Sopenharmony_ci * LAPB 002 Jonathan Naylor New timer architecture. 108c2ecf20Sopenharmony_ci * 2000-10-29 Henner Eisen lapb_data_indication() return status. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/types.h> 178c2ecf20Sopenharmony_ci#include <linux/socket.h> 188c2ecf20Sopenharmony_ci#include <linux/in.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/timer.h> 218c2ecf20Sopenharmony_ci#include <linux/string.h> 228c2ecf20Sopenharmony_ci#include <linux/sockios.h> 238c2ecf20Sopenharmony_ci#include <linux/net.h> 248c2ecf20Sopenharmony_ci#include <linux/inet.h> 258c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 268c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <net/sock.h> 298c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 308c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 318c2ecf20Sopenharmony_ci#include <linux/mm.h> 328c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 338c2ecf20Sopenharmony_ci#include <net/lapb.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * State machine for state 0, Disconnected State. 378c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistatic void lapb_state0_machine(struct lapb_cb *lapb, struct sk_buff *skb, 408c2ecf20Sopenharmony_ci struct lapb_frame *frame) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci switch (frame->type) { 438c2ecf20Sopenharmony_ci case LAPB_SABM: 448c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 RX SABM(%d)\n", lapb->dev, frame->pf); 458c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 468c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX DM(%d)\n", 478c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 488c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 498c2ecf20Sopenharmony_ci LAPB_RESPONSE); 508c2ecf20Sopenharmony_ci } else { 518c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX UA(%d)\n", 528c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 538c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S0 -> S3\n", lapb->dev); 548c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 558c2ecf20Sopenharmony_ci LAPB_RESPONSE); 568c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 578c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 588c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_3; 598c2ecf20Sopenharmony_ci lapb->condition = 0x00; 608c2ecf20Sopenharmony_ci lapb->n2count = 0; 618c2ecf20Sopenharmony_ci lapb->vs = 0; 628c2ecf20Sopenharmony_ci lapb->vr = 0; 638c2ecf20Sopenharmony_ci lapb->va = 0; 648c2ecf20Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci case LAPB_SABME: 698c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 RX SABME(%d)\n", lapb->dev, frame->pf); 708c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 718c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX UA(%d)\n", 728c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 738c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S0 -> S3\n", lapb->dev); 748c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 758c2ecf20Sopenharmony_ci LAPB_RESPONSE); 768c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 778c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 788c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_3; 798c2ecf20Sopenharmony_ci lapb->condition = 0x00; 808c2ecf20Sopenharmony_ci lapb->n2count = 0; 818c2ecf20Sopenharmony_ci lapb->vs = 0; 828c2ecf20Sopenharmony_ci lapb->vr = 0; 838c2ecf20Sopenharmony_ci lapb->va = 0; 848c2ecf20Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 858c2ecf20Sopenharmony_ci } else { 868c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX DM(%d)\n", 878c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 888c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 898c2ecf20Sopenharmony_ci LAPB_RESPONSE); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci case LAPB_DISC: 948c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 RX DISC(%d)\n", lapb->dev, frame->pf); 958c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX UA(%d)\n", lapb->dev, frame->pf); 968c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci default: 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci kfree_skb(skb); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * State machine for state 1, Awaiting Connection State. 1088c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistatic void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb, 1118c2ecf20Sopenharmony_ci struct lapb_frame *frame) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci switch (frame->type) { 1148c2ecf20Sopenharmony_ci case LAPB_SABM: 1158c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX SABM(%d)\n", lapb->dev, frame->pf); 1168c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 1178c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DM(%d)\n", 1188c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 1198c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 1208c2ecf20Sopenharmony_ci LAPB_RESPONSE); 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX UA(%d)\n", 1238c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 1248c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 1258c2ecf20Sopenharmony_ci LAPB_RESPONSE); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci case LAPB_SABME: 1308c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX SABME(%d)\n", lapb->dev, frame->pf); 1318c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 1328c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX UA(%d)\n", 1338c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 1348c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 1358c2ecf20Sopenharmony_ci LAPB_RESPONSE); 1368c2ecf20Sopenharmony_ci } else { 1378c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DM(%d)\n", 1388c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 1398c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 1408c2ecf20Sopenharmony_ci LAPB_RESPONSE); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci case LAPB_DISC: 1458c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX DISC(%d)\n", lapb->dev, frame->pf); 1468c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DM(%d)\n", lapb->dev, frame->pf); 1478c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci case LAPB_UA: 1518c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX UA(%d)\n", lapb->dev, frame->pf); 1528c2ecf20Sopenharmony_ci if (frame->pf) { 1538c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S1 -> S3\n", lapb->dev); 1548c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 1558c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 1568c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_3; 1578c2ecf20Sopenharmony_ci lapb->condition = 0x00; 1588c2ecf20Sopenharmony_ci lapb->n2count = 0; 1598c2ecf20Sopenharmony_ci lapb->vs = 0; 1608c2ecf20Sopenharmony_ci lapb->vr = 0; 1618c2ecf20Sopenharmony_ci lapb->va = 0; 1628c2ecf20Sopenharmony_ci lapb_connect_confirmation(lapb, LAPB_OK); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci case LAPB_DM: 1678c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX DM(%d)\n", lapb->dev, frame->pf); 1688c2ecf20Sopenharmony_ci if (frame->pf) { 1698c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); 1708c2ecf20Sopenharmony_ci lapb_clear_queues(lapb); 1718c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 1728c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 1738c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 1748c2ecf20Sopenharmony_ci lapb_disconnect_indication(lapb, LAPB_REFUSED); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci kfree_skb(skb); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * State machine for state 2, Awaiting Release State. 1848c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb, 1878c2ecf20Sopenharmony_ci struct lapb_frame *frame) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci switch (frame->type) { 1908c2ecf20Sopenharmony_ci case LAPB_SABM: 1918c2ecf20Sopenharmony_ci case LAPB_SABME: 1928c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX {SABM,SABME}(%d)\n", 1938c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 1948c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 TX DM(%d)\n", lapb->dev, frame->pf); 1958c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci case LAPB_DISC: 1998c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX DISC(%d)\n", lapb->dev, frame->pf); 2008c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 TX UA(%d)\n", lapb->dev, frame->pf); 2018c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci case LAPB_UA: 2058c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX UA(%d)\n", lapb->dev, frame->pf); 2068c2ecf20Sopenharmony_ci if (frame->pf) { 2078c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); 2088c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 2098c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 2108c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 2118c2ecf20Sopenharmony_ci lapb_disconnect_confirmation(lapb, LAPB_OK); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci case LAPB_DM: 2168c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf); 2178c2ecf20Sopenharmony_ci if (frame->pf) { 2188c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); 2198c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 2208c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 2218c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 2228c2ecf20Sopenharmony_ci lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci case LAPB_I: 2278c2ecf20Sopenharmony_ci case LAPB_REJ: 2288c2ecf20Sopenharmony_ci case LAPB_RNR: 2298c2ecf20Sopenharmony_ci case LAPB_RR: 2308c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX {I,REJ,RNR,RR}(%d)\n", 2318c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 2328c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf); 2338c2ecf20Sopenharmony_ci if (frame->pf) 2348c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 2358c2ecf20Sopenharmony_ci LAPB_RESPONSE); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci kfree_skb(skb); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* 2438c2ecf20Sopenharmony_ci * State machine for state 3, Connected State. 2448c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cistatic void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb, 2478c2ecf20Sopenharmony_ci struct lapb_frame *frame) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int queued = 0; 2508c2ecf20Sopenharmony_ci int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : 2518c2ecf20Sopenharmony_ci LAPB_SMODULUS; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci switch (frame->type) { 2548c2ecf20Sopenharmony_ci case LAPB_SABM: 2558c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX SABM(%d)\n", lapb->dev, frame->pf); 2568c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 2578c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX DM(%d)\n", 2588c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 2598c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 2608c2ecf20Sopenharmony_ci LAPB_RESPONSE); 2618c2ecf20Sopenharmony_ci } else { 2628c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX UA(%d)\n", 2638c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 2648c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 2658c2ecf20Sopenharmony_ci LAPB_RESPONSE); 2668c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 2678c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 2688c2ecf20Sopenharmony_ci lapb->condition = 0x00; 2698c2ecf20Sopenharmony_ci lapb->n2count = 0; 2708c2ecf20Sopenharmony_ci lapb->vs = 0; 2718c2ecf20Sopenharmony_ci lapb->vr = 0; 2728c2ecf20Sopenharmony_ci lapb->va = 0; 2738c2ecf20Sopenharmony_ci lapb_requeue_frames(lapb); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci case LAPB_SABME: 2788c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX SABME(%d)\n", lapb->dev, frame->pf); 2798c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 2808c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX UA(%d)\n", 2818c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 2828c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 2838c2ecf20Sopenharmony_ci LAPB_RESPONSE); 2848c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 2858c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 2868c2ecf20Sopenharmony_ci lapb->condition = 0x00; 2878c2ecf20Sopenharmony_ci lapb->n2count = 0; 2888c2ecf20Sopenharmony_ci lapb->vs = 0; 2898c2ecf20Sopenharmony_ci lapb->vr = 0; 2908c2ecf20Sopenharmony_ci lapb->va = 0; 2918c2ecf20Sopenharmony_ci lapb_requeue_frames(lapb); 2928c2ecf20Sopenharmony_ci } else { 2938c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX DM(%d)\n", 2948c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 2958c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 2968c2ecf20Sopenharmony_ci LAPB_RESPONSE); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci case LAPB_DISC: 3018c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX DISC(%d)\n", lapb->dev, frame->pf); 3028c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); 3038c2ecf20Sopenharmony_ci lapb_clear_queues(lapb); 3048c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); 3058c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3068c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3078c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 3088c2ecf20Sopenharmony_ci lapb_disconnect_indication(lapb, LAPB_OK); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci case LAPB_DM: 3128c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX DM(%d)\n", lapb->dev, frame->pf); 3138c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); 3148c2ecf20Sopenharmony_ci lapb_clear_queues(lapb); 3158c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 3168c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3178c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3188c2ecf20Sopenharmony_ci lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED); 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci case LAPB_RNR: 3228c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX RNR(%d) R%d\n", 3238c2ecf20Sopenharmony_ci lapb->dev, frame->pf, frame->nr); 3248c2ecf20Sopenharmony_ci lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; 3258c2ecf20Sopenharmony_ci lapb_check_need_response(lapb, frame->cr, frame->pf); 3268c2ecf20Sopenharmony_ci if (lapb_validate_nr(lapb, frame->nr)) { 3278c2ecf20Sopenharmony_ci lapb_check_iframes_acked(lapb, frame->nr); 3288c2ecf20Sopenharmony_ci } else { 3298c2ecf20Sopenharmony_ci lapb->frmr_data = *frame; 3308c2ecf20Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 3318c2ecf20Sopenharmony_ci lapb_transmit_frmr(lapb); 3328c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 3338c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3348c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3358c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_4; 3368c2ecf20Sopenharmony_ci lapb->n2count = 0; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci case LAPB_RR: 3418c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX RR(%d) R%d\n", 3428c2ecf20Sopenharmony_ci lapb->dev, frame->pf, frame->nr); 3438c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; 3448c2ecf20Sopenharmony_ci lapb_check_need_response(lapb, frame->cr, frame->pf); 3458c2ecf20Sopenharmony_ci if (lapb_validate_nr(lapb, frame->nr)) { 3468c2ecf20Sopenharmony_ci lapb_check_iframes_acked(lapb, frame->nr); 3478c2ecf20Sopenharmony_ci } else { 3488c2ecf20Sopenharmony_ci lapb->frmr_data = *frame; 3498c2ecf20Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 3508c2ecf20Sopenharmony_ci lapb_transmit_frmr(lapb); 3518c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 3528c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3538c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3548c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_4; 3558c2ecf20Sopenharmony_ci lapb->n2count = 0; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci case LAPB_REJ: 3608c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX REJ(%d) R%d\n", 3618c2ecf20Sopenharmony_ci lapb->dev, frame->pf, frame->nr); 3628c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; 3638c2ecf20Sopenharmony_ci lapb_check_need_response(lapb, frame->cr, frame->pf); 3648c2ecf20Sopenharmony_ci if (lapb_validate_nr(lapb, frame->nr)) { 3658c2ecf20Sopenharmony_ci lapb_frames_acked(lapb, frame->nr); 3668c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 3678c2ecf20Sopenharmony_ci lapb->n2count = 0; 3688c2ecf20Sopenharmony_ci lapb_requeue_frames(lapb); 3698c2ecf20Sopenharmony_ci } else { 3708c2ecf20Sopenharmony_ci lapb->frmr_data = *frame; 3718c2ecf20Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 3728c2ecf20Sopenharmony_ci lapb_transmit_frmr(lapb); 3738c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 3748c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3758c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3768c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_4; 3778c2ecf20Sopenharmony_ci lapb->n2count = 0; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci case LAPB_I: 3828c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX I(%d) S%d R%d\n", 3838c2ecf20Sopenharmony_ci lapb->dev, frame->pf, frame->ns, frame->nr); 3848c2ecf20Sopenharmony_ci if (!lapb_validate_nr(lapb, frame->nr)) { 3858c2ecf20Sopenharmony_ci lapb->frmr_data = *frame; 3868c2ecf20Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 3878c2ecf20Sopenharmony_ci lapb_transmit_frmr(lapb); 3888c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 3898c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3908c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3918c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_4; 3928c2ecf20Sopenharmony_ci lapb->n2count = 0; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) 3968c2ecf20Sopenharmony_ci lapb_frames_acked(lapb, frame->nr); 3978c2ecf20Sopenharmony_ci else 3988c2ecf20Sopenharmony_ci lapb_check_iframes_acked(lapb, frame->nr); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (frame->ns == lapb->vr) { 4018c2ecf20Sopenharmony_ci int cn; 4028c2ecf20Sopenharmony_ci cn = lapb_data_indication(lapb, skb); 4038c2ecf20Sopenharmony_ci queued = 1; 4048c2ecf20Sopenharmony_ci /* 4058c2ecf20Sopenharmony_ci * If upper layer has dropped the frame, we 4068c2ecf20Sopenharmony_ci * basically ignore any further protocol 4078c2ecf20Sopenharmony_ci * processing. This will cause the peer 4088c2ecf20Sopenharmony_ci * to re-transmit the frame later like 4098c2ecf20Sopenharmony_ci * a frame lost on the wire. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci if (cn == NET_RX_DROP) { 4128c2ecf20Sopenharmony_ci pr_debug("rx congestion\n"); 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci lapb->vr = (lapb->vr + 1) % modulus; 4168c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_REJECT_CONDITION; 4178c2ecf20Sopenharmony_ci if (frame->pf) 4188c2ecf20Sopenharmony_ci lapb_enquiry_response(lapb); 4198c2ecf20Sopenharmony_ci else { 4208c2ecf20Sopenharmony_ci if (!(lapb->condition & 4218c2ecf20Sopenharmony_ci LAPB_ACK_PENDING_CONDITION)) { 4228c2ecf20Sopenharmony_ci lapb->condition |= LAPB_ACK_PENDING_CONDITION; 4238c2ecf20Sopenharmony_ci lapb_start_t2timer(lapb); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci } else { 4278c2ecf20Sopenharmony_ci if (lapb->condition & LAPB_REJECT_CONDITION) { 4288c2ecf20Sopenharmony_ci if (frame->pf) 4298c2ecf20Sopenharmony_ci lapb_enquiry_response(lapb); 4308c2ecf20Sopenharmony_ci } else { 4318c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX REJ(%d) R%d\n", 4328c2ecf20Sopenharmony_ci lapb->dev, frame->pf, lapb->vr); 4338c2ecf20Sopenharmony_ci lapb->condition |= LAPB_REJECT_CONDITION; 4348c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_REJ, frame->pf, 4358c2ecf20Sopenharmony_ci LAPB_RESPONSE); 4368c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci case LAPB_FRMR: 4428c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX FRMR(%d) %5ph\n", 4438c2ecf20Sopenharmony_ci lapb->dev, frame->pf, 4448c2ecf20Sopenharmony_ci skb->data); 4458c2ecf20Sopenharmony_ci lapb_establish_data_link(lapb); 4468c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S1\n", lapb->dev); 4478c2ecf20Sopenharmony_ci lapb_requeue_frames(lapb); 4488c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_1; 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci case LAPB_ILLEGAL: 4528c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX ILLEGAL(%d)\n", lapb->dev, frame->pf); 4538c2ecf20Sopenharmony_ci lapb->frmr_data = *frame; 4548c2ecf20Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_W; 4558c2ecf20Sopenharmony_ci lapb_transmit_frmr(lapb); 4568c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 4578c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 4588c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 4598c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_4; 4608c2ecf20Sopenharmony_ci lapb->n2count = 0; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!queued) 4658c2ecf20Sopenharmony_ci kfree_skb(skb); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* 4698c2ecf20Sopenharmony_ci * State machine for state 4, Frame Reject State. 4708c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistatic void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb, 4738c2ecf20Sopenharmony_ci struct lapb_frame *frame) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci switch (frame->type) { 4768c2ecf20Sopenharmony_ci case LAPB_SABM: 4778c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S4 RX SABM(%d)\n", lapb->dev, frame->pf); 4788c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 4798c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX DM(%d)\n", 4808c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 4818c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 4828c2ecf20Sopenharmony_ci LAPB_RESPONSE); 4838c2ecf20Sopenharmony_ci } else { 4848c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX UA(%d)\n", 4858c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 4868c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev); 4878c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 4888c2ecf20Sopenharmony_ci LAPB_RESPONSE); 4898c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 4908c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 4918c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_3; 4928c2ecf20Sopenharmony_ci lapb->condition = 0x00; 4938c2ecf20Sopenharmony_ci lapb->n2count = 0; 4948c2ecf20Sopenharmony_ci lapb->vs = 0; 4958c2ecf20Sopenharmony_ci lapb->vr = 0; 4968c2ecf20Sopenharmony_ci lapb->va = 0; 4978c2ecf20Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci case LAPB_SABME: 5028c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S4 RX SABME(%d)\n", lapb->dev, frame->pf); 5038c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 5048c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX UA(%d)\n", 5058c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 5068c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev); 5078c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 5088c2ecf20Sopenharmony_ci LAPB_RESPONSE); 5098c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 5108c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 5118c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_3; 5128c2ecf20Sopenharmony_ci lapb->condition = 0x00; 5138c2ecf20Sopenharmony_ci lapb->n2count = 0; 5148c2ecf20Sopenharmony_ci lapb->vs = 0; 5158c2ecf20Sopenharmony_ci lapb->vr = 0; 5168c2ecf20Sopenharmony_ci lapb->va = 0; 5178c2ecf20Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 5188c2ecf20Sopenharmony_ci } else { 5198c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX DM(%d)\n", 5208c2ecf20Sopenharmony_ci lapb->dev, frame->pf); 5218c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 5228c2ecf20Sopenharmony_ci LAPB_RESPONSE); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci kfree_skb(skb); 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/* 5318c2ecf20Sopenharmony_ci * Process an incoming LAPB frame 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_civoid lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct lapb_frame frame; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (lapb_decode(lapb, skb, &frame) < 0) { 5388c2ecf20Sopenharmony_ci kfree_skb(skb); 5398c2ecf20Sopenharmony_ci return; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci switch (lapb->state) { 5438c2ecf20Sopenharmony_ci case LAPB_STATE_0: 5448c2ecf20Sopenharmony_ci lapb_state0_machine(lapb, skb, &frame); break; 5458c2ecf20Sopenharmony_ci case LAPB_STATE_1: 5468c2ecf20Sopenharmony_ci lapb_state1_machine(lapb, skb, &frame); break; 5478c2ecf20Sopenharmony_ci case LAPB_STATE_2: 5488c2ecf20Sopenharmony_ci lapb_state2_machine(lapb, skb, &frame); break; 5498c2ecf20Sopenharmony_ci case LAPB_STATE_3: 5508c2ecf20Sopenharmony_ci lapb_state3_machine(lapb, skb, &frame); break; 5518c2ecf20Sopenharmony_ci case LAPB_STATE_4: 5528c2ecf20Sopenharmony_ci lapb_state4_machine(lapb, skb, &frame); break; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci lapb_kick(lapb); 5568c2ecf20Sopenharmony_ci} 557