162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * LAPB release 002 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This code REQUIRES 2.1.15 or higher/ NET3.038 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * History 862306a36Sopenharmony_ci * LAPB 001 Jonathan Naulor Started Coding 962306a36Sopenharmony_ci * LAPB 002 Jonathan Naylor New timer architecture. 1062306a36Sopenharmony_ci * 2000-10-29 Henner Eisen lapb_data_indication() return status. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/types.h> 1762306a36Sopenharmony_ci#include <linux/socket.h> 1862306a36Sopenharmony_ci#include <linux/in.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/timer.h> 2162306a36Sopenharmony_ci#include <linux/string.h> 2262306a36Sopenharmony_ci#include <linux/sockios.h> 2362306a36Sopenharmony_ci#include <linux/net.h> 2462306a36Sopenharmony_ci#include <linux/inet.h> 2562306a36Sopenharmony_ci#include <linux/netdevice.h> 2662306a36Sopenharmony_ci#include <linux/skbuff.h> 2762306a36Sopenharmony_ci#include <linux/slab.h> 2862306a36Sopenharmony_ci#include <net/sock.h> 2962306a36Sopenharmony_ci#include <linux/uaccess.h> 3062306a36Sopenharmony_ci#include <linux/fcntl.h> 3162306a36Sopenharmony_ci#include <linux/mm.h> 3262306a36Sopenharmony_ci#include <linux/interrupt.h> 3362306a36Sopenharmony_ci#include <net/lapb.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * State machine for state 0, Disconnected State. 3762306a36Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic void lapb_state0_machine(struct lapb_cb *lapb, struct sk_buff *skb, 4062306a36Sopenharmony_ci struct lapb_frame *frame) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci switch (frame->type) { 4362306a36Sopenharmony_ci case LAPB_SABM: 4462306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 RX SABM(%d)\n", lapb->dev, frame->pf); 4562306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 4662306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX DM(%d)\n", 4762306a36Sopenharmony_ci lapb->dev, frame->pf); 4862306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 4962306a36Sopenharmony_ci LAPB_RESPONSE); 5062306a36Sopenharmony_ci } else { 5162306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX UA(%d)\n", 5262306a36Sopenharmony_ci lapb->dev, frame->pf); 5362306a36Sopenharmony_ci lapb_dbg(0, "(%p) S0 -> S3\n", lapb->dev); 5462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 5562306a36Sopenharmony_ci LAPB_RESPONSE); 5662306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 5762306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 5862306a36Sopenharmony_ci lapb->state = LAPB_STATE_3; 5962306a36Sopenharmony_ci lapb->condition = 0x00; 6062306a36Sopenharmony_ci lapb->n2count = 0; 6162306a36Sopenharmony_ci lapb->vs = 0; 6262306a36Sopenharmony_ci lapb->vr = 0; 6362306a36Sopenharmony_ci lapb->va = 0; 6462306a36Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci case LAPB_SABME: 6962306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 RX SABME(%d)\n", lapb->dev, frame->pf); 7062306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 7162306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX UA(%d)\n", 7262306a36Sopenharmony_ci lapb->dev, frame->pf); 7362306a36Sopenharmony_ci lapb_dbg(0, "(%p) S0 -> S3\n", lapb->dev); 7462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 7562306a36Sopenharmony_ci LAPB_RESPONSE); 7662306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 7762306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 7862306a36Sopenharmony_ci lapb->state = LAPB_STATE_3; 7962306a36Sopenharmony_ci lapb->condition = 0x00; 8062306a36Sopenharmony_ci lapb->n2count = 0; 8162306a36Sopenharmony_ci lapb->vs = 0; 8262306a36Sopenharmony_ci lapb->vr = 0; 8362306a36Sopenharmony_ci lapb->va = 0; 8462306a36Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 8562306a36Sopenharmony_ci } else { 8662306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX DM(%d)\n", 8762306a36Sopenharmony_ci lapb->dev, frame->pf); 8862306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 8962306a36Sopenharmony_ci LAPB_RESPONSE); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci case LAPB_DISC: 9462306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 RX DISC(%d)\n", lapb->dev, frame->pf); 9562306a36Sopenharmony_ci lapb_dbg(1, "(%p) S0 TX UA(%d)\n", lapb->dev, frame->pf); 9662306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci default: 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci kfree_skb(skb); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * State machine for state 1, Awaiting Connection State. 10862306a36Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_cistatic void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb, 11162306a36Sopenharmony_ci struct lapb_frame *frame) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci switch (frame->type) { 11462306a36Sopenharmony_ci case LAPB_SABM: 11562306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX SABM(%d)\n", lapb->dev, frame->pf); 11662306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 11762306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DM(%d)\n", 11862306a36Sopenharmony_ci lapb->dev, frame->pf); 11962306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 12062306a36Sopenharmony_ci LAPB_RESPONSE); 12162306a36Sopenharmony_ci } else { 12262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX UA(%d)\n", 12362306a36Sopenharmony_ci lapb->dev, frame->pf); 12462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 12562306a36Sopenharmony_ci LAPB_RESPONSE); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci case LAPB_SABME: 13062306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX SABME(%d)\n", lapb->dev, frame->pf); 13162306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 13262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX UA(%d)\n", 13362306a36Sopenharmony_ci lapb->dev, frame->pf); 13462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 13562306a36Sopenharmony_ci LAPB_RESPONSE); 13662306a36Sopenharmony_ci } else { 13762306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DM(%d)\n", 13862306a36Sopenharmony_ci lapb->dev, frame->pf); 13962306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 14062306a36Sopenharmony_ci LAPB_RESPONSE); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci case LAPB_DISC: 14562306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX DISC(%d)\n", lapb->dev, frame->pf); 14662306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DM(%d)\n", lapb->dev, frame->pf); 14762306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci case LAPB_UA: 15162306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX UA(%d)\n", lapb->dev, frame->pf); 15262306a36Sopenharmony_ci if (frame->pf) { 15362306a36Sopenharmony_ci lapb_dbg(0, "(%p) S1 -> S3\n", lapb->dev); 15462306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 15562306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 15662306a36Sopenharmony_ci lapb->state = LAPB_STATE_3; 15762306a36Sopenharmony_ci lapb->condition = 0x00; 15862306a36Sopenharmony_ci lapb->n2count = 0; 15962306a36Sopenharmony_ci lapb->vs = 0; 16062306a36Sopenharmony_ci lapb->vr = 0; 16162306a36Sopenharmony_ci lapb->va = 0; 16262306a36Sopenharmony_ci lapb_connect_confirmation(lapb, LAPB_OK); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci case LAPB_DM: 16762306a36Sopenharmony_ci lapb_dbg(1, "(%p) S1 RX DM(%d)\n", lapb->dev, frame->pf); 16862306a36Sopenharmony_ci if (frame->pf) { 16962306a36Sopenharmony_ci lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); 17062306a36Sopenharmony_ci lapb_clear_queues(lapb); 17162306a36Sopenharmony_ci lapb->state = LAPB_STATE_0; 17262306a36Sopenharmony_ci lapb_start_t1timer(lapb); 17362306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 17462306a36Sopenharmony_ci lapb_disconnect_indication(lapb, LAPB_REFUSED); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci kfree_skb(skb); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * State machine for state 2, Awaiting Release State. 18462306a36Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_cistatic void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb, 18762306a36Sopenharmony_ci struct lapb_frame *frame) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci switch (frame->type) { 19062306a36Sopenharmony_ci case LAPB_SABM: 19162306a36Sopenharmony_ci case LAPB_SABME: 19262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX {SABM,SABME}(%d)\n", 19362306a36Sopenharmony_ci lapb->dev, frame->pf); 19462306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 TX DM(%d)\n", lapb->dev, frame->pf); 19562306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci case LAPB_DISC: 19962306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX DISC(%d)\n", lapb->dev, frame->pf); 20062306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 TX UA(%d)\n", lapb->dev, frame->pf); 20162306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci case LAPB_UA: 20562306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX UA(%d)\n", lapb->dev, frame->pf); 20662306a36Sopenharmony_ci if (frame->pf) { 20762306a36Sopenharmony_ci lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); 20862306a36Sopenharmony_ci lapb->state = LAPB_STATE_0; 20962306a36Sopenharmony_ci lapb_start_t1timer(lapb); 21062306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 21162306a36Sopenharmony_ci lapb_disconnect_confirmation(lapb, LAPB_OK); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci case LAPB_DM: 21662306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf); 21762306a36Sopenharmony_ci if (frame->pf) { 21862306a36Sopenharmony_ci lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); 21962306a36Sopenharmony_ci lapb->state = LAPB_STATE_0; 22062306a36Sopenharmony_ci lapb_start_t1timer(lapb); 22162306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 22262306a36Sopenharmony_ci lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci case LAPB_I: 22762306a36Sopenharmony_ci case LAPB_REJ: 22862306a36Sopenharmony_ci case LAPB_RNR: 22962306a36Sopenharmony_ci case LAPB_RR: 23062306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX {I,REJ,RNR,RR}(%d)\n", 23162306a36Sopenharmony_ci lapb->dev, frame->pf); 23262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf); 23362306a36Sopenharmony_ci if (frame->pf) 23462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 23562306a36Sopenharmony_ci LAPB_RESPONSE); 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci kfree_skb(skb); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* 24362306a36Sopenharmony_ci * State machine for state 3, Connected State. 24462306a36Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_cistatic void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb, 24762306a36Sopenharmony_ci struct lapb_frame *frame) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci int queued = 0; 25062306a36Sopenharmony_ci int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : 25162306a36Sopenharmony_ci LAPB_SMODULUS; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci switch (frame->type) { 25462306a36Sopenharmony_ci case LAPB_SABM: 25562306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX SABM(%d)\n", lapb->dev, frame->pf); 25662306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 25762306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX DM(%d)\n", 25862306a36Sopenharmony_ci lapb->dev, frame->pf); 25962306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 26062306a36Sopenharmony_ci LAPB_RESPONSE); 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX UA(%d)\n", 26362306a36Sopenharmony_ci lapb->dev, frame->pf); 26462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 26562306a36Sopenharmony_ci LAPB_RESPONSE); 26662306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 26762306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 26862306a36Sopenharmony_ci lapb->condition = 0x00; 26962306a36Sopenharmony_ci lapb->n2count = 0; 27062306a36Sopenharmony_ci lapb->vs = 0; 27162306a36Sopenharmony_ci lapb->vr = 0; 27262306a36Sopenharmony_ci lapb->va = 0; 27362306a36Sopenharmony_ci lapb_requeue_frames(lapb); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci case LAPB_SABME: 27862306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX SABME(%d)\n", lapb->dev, frame->pf); 27962306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 28062306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX UA(%d)\n", 28162306a36Sopenharmony_ci lapb->dev, frame->pf); 28262306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 28362306a36Sopenharmony_ci LAPB_RESPONSE); 28462306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 28562306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 28662306a36Sopenharmony_ci lapb->condition = 0x00; 28762306a36Sopenharmony_ci lapb->n2count = 0; 28862306a36Sopenharmony_ci lapb->vs = 0; 28962306a36Sopenharmony_ci lapb->vr = 0; 29062306a36Sopenharmony_ci lapb->va = 0; 29162306a36Sopenharmony_ci lapb_requeue_frames(lapb); 29262306a36Sopenharmony_ci } else { 29362306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX DM(%d)\n", 29462306a36Sopenharmony_ci lapb->dev, frame->pf); 29562306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 29662306a36Sopenharmony_ci LAPB_RESPONSE); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci case LAPB_DISC: 30162306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX DISC(%d)\n", lapb->dev, frame->pf); 30262306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); 30362306a36Sopenharmony_ci lapb_clear_queues(lapb); 30462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); 30562306a36Sopenharmony_ci lapb_start_t1timer(lapb); 30662306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 30762306a36Sopenharmony_ci lapb->state = LAPB_STATE_0; 30862306a36Sopenharmony_ci lapb_disconnect_indication(lapb, LAPB_OK); 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci case LAPB_DM: 31262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX DM(%d)\n", lapb->dev, frame->pf); 31362306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); 31462306a36Sopenharmony_ci lapb_clear_queues(lapb); 31562306a36Sopenharmony_ci lapb->state = LAPB_STATE_0; 31662306a36Sopenharmony_ci lapb_start_t1timer(lapb); 31762306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 31862306a36Sopenharmony_ci lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED); 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci case LAPB_RNR: 32262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX RNR(%d) R%d\n", 32362306a36Sopenharmony_ci lapb->dev, frame->pf, frame->nr); 32462306a36Sopenharmony_ci lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; 32562306a36Sopenharmony_ci lapb_check_need_response(lapb, frame->cr, frame->pf); 32662306a36Sopenharmony_ci if (lapb_validate_nr(lapb, frame->nr)) { 32762306a36Sopenharmony_ci lapb_check_iframes_acked(lapb, frame->nr); 32862306a36Sopenharmony_ci } else { 32962306a36Sopenharmony_ci lapb->frmr_data = *frame; 33062306a36Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 33162306a36Sopenharmony_ci lapb_transmit_frmr(lapb); 33262306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 33362306a36Sopenharmony_ci lapb_start_t1timer(lapb); 33462306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 33562306a36Sopenharmony_ci lapb->state = LAPB_STATE_4; 33662306a36Sopenharmony_ci lapb->n2count = 0; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci case LAPB_RR: 34162306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX RR(%d) R%d\n", 34262306a36Sopenharmony_ci lapb->dev, frame->pf, frame->nr); 34362306a36Sopenharmony_ci lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; 34462306a36Sopenharmony_ci lapb_check_need_response(lapb, frame->cr, frame->pf); 34562306a36Sopenharmony_ci if (lapb_validate_nr(lapb, frame->nr)) { 34662306a36Sopenharmony_ci lapb_check_iframes_acked(lapb, frame->nr); 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci lapb->frmr_data = *frame; 34962306a36Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 35062306a36Sopenharmony_ci lapb_transmit_frmr(lapb); 35162306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 35262306a36Sopenharmony_ci lapb_start_t1timer(lapb); 35362306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 35462306a36Sopenharmony_ci lapb->state = LAPB_STATE_4; 35562306a36Sopenharmony_ci lapb->n2count = 0; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci case LAPB_REJ: 36062306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX REJ(%d) R%d\n", 36162306a36Sopenharmony_ci lapb->dev, frame->pf, frame->nr); 36262306a36Sopenharmony_ci lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; 36362306a36Sopenharmony_ci lapb_check_need_response(lapb, frame->cr, frame->pf); 36462306a36Sopenharmony_ci if (lapb_validate_nr(lapb, frame->nr)) { 36562306a36Sopenharmony_ci lapb_frames_acked(lapb, frame->nr); 36662306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 36762306a36Sopenharmony_ci lapb->n2count = 0; 36862306a36Sopenharmony_ci lapb_requeue_frames(lapb); 36962306a36Sopenharmony_ci } else { 37062306a36Sopenharmony_ci lapb->frmr_data = *frame; 37162306a36Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 37262306a36Sopenharmony_ci lapb_transmit_frmr(lapb); 37362306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 37462306a36Sopenharmony_ci lapb_start_t1timer(lapb); 37562306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 37662306a36Sopenharmony_ci lapb->state = LAPB_STATE_4; 37762306a36Sopenharmony_ci lapb->n2count = 0; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci case LAPB_I: 38262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX I(%d) S%d R%d\n", 38362306a36Sopenharmony_ci lapb->dev, frame->pf, frame->ns, frame->nr); 38462306a36Sopenharmony_ci if (!lapb_validate_nr(lapb, frame->nr)) { 38562306a36Sopenharmony_ci lapb->frmr_data = *frame; 38662306a36Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_Z; 38762306a36Sopenharmony_ci lapb_transmit_frmr(lapb); 38862306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 38962306a36Sopenharmony_ci lapb_start_t1timer(lapb); 39062306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 39162306a36Sopenharmony_ci lapb->state = LAPB_STATE_4; 39262306a36Sopenharmony_ci lapb->n2count = 0; 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) 39662306a36Sopenharmony_ci lapb_frames_acked(lapb, frame->nr); 39762306a36Sopenharmony_ci else 39862306a36Sopenharmony_ci lapb_check_iframes_acked(lapb, frame->nr); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (frame->ns == lapb->vr) { 40162306a36Sopenharmony_ci int cn; 40262306a36Sopenharmony_ci cn = lapb_data_indication(lapb, skb); 40362306a36Sopenharmony_ci queued = 1; 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * If upper layer has dropped the frame, we 40662306a36Sopenharmony_ci * basically ignore any further protocol 40762306a36Sopenharmony_ci * processing. This will cause the peer 40862306a36Sopenharmony_ci * to re-transmit the frame later like 40962306a36Sopenharmony_ci * a frame lost on the wire. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci if (cn == NET_RX_DROP) { 41262306a36Sopenharmony_ci pr_debug("rx congestion\n"); 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci lapb->vr = (lapb->vr + 1) % modulus; 41662306a36Sopenharmony_ci lapb->condition &= ~LAPB_REJECT_CONDITION; 41762306a36Sopenharmony_ci if (frame->pf) 41862306a36Sopenharmony_ci lapb_enquiry_response(lapb); 41962306a36Sopenharmony_ci else { 42062306a36Sopenharmony_ci if (!(lapb->condition & 42162306a36Sopenharmony_ci LAPB_ACK_PENDING_CONDITION)) { 42262306a36Sopenharmony_ci lapb->condition |= LAPB_ACK_PENDING_CONDITION; 42362306a36Sopenharmony_ci lapb_start_t2timer(lapb); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } else { 42762306a36Sopenharmony_ci if (lapb->condition & LAPB_REJECT_CONDITION) { 42862306a36Sopenharmony_ci if (frame->pf) 42962306a36Sopenharmony_ci lapb_enquiry_response(lapb); 43062306a36Sopenharmony_ci } else { 43162306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 TX REJ(%d) R%d\n", 43262306a36Sopenharmony_ci lapb->dev, frame->pf, lapb->vr); 43362306a36Sopenharmony_ci lapb->condition |= LAPB_REJECT_CONDITION; 43462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_REJ, frame->pf, 43562306a36Sopenharmony_ci LAPB_RESPONSE); 43662306a36Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci case LAPB_FRMR: 44262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX FRMR(%d) %5ph\n", 44362306a36Sopenharmony_ci lapb->dev, frame->pf, 44462306a36Sopenharmony_ci skb->data); 44562306a36Sopenharmony_ci lapb_establish_data_link(lapb); 44662306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S1\n", lapb->dev); 44762306a36Sopenharmony_ci lapb_requeue_frames(lapb); 44862306a36Sopenharmony_ci lapb->state = LAPB_STATE_1; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci case LAPB_ILLEGAL: 45262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S3 RX ILLEGAL(%d)\n", lapb->dev, frame->pf); 45362306a36Sopenharmony_ci lapb->frmr_data = *frame; 45462306a36Sopenharmony_ci lapb->frmr_type = LAPB_FRMR_W; 45562306a36Sopenharmony_ci lapb_transmit_frmr(lapb); 45662306a36Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); 45762306a36Sopenharmony_ci lapb_start_t1timer(lapb); 45862306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 45962306a36Sopenharmony_ci lapb->state = LAPB_STATE_4; 46062306a36Sopenharmony_ci lapb->n2count = 0; 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (!queued) 46562306a36Sopenharmony_ci kfree_skb(skb); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/* 46962306a36Sopenharmony_ci * State machine for state 4, Frame Reject State. 47062306a36Sopenharmony_ci * The handling of the timer(s) is in file lapb_timer.c. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb, 47362306a36Sopenharmony_ci struct lapb_frame *frame) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci switch (frame->type) { 47662306a36Sopenharmony_ci case LAPB_SABM: 47762306a36Sopenharmony_ci lapb_dbg(1, "(%p) S4 RX SABM(%d)\n", lapb->dev, frame->pf); 47862306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 47962306a36Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX DM(%d)\n", 48062306a36Sopenharmony_ci lapb->dev, frame->pf); 48162306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 48262306a36Sopenharmony_ci LAPB_RESPONSE); 48362306a36Sopenharmony_ci } else { 48462306a36Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX UA(%d)\n", 48562306a36Sopenharmony_ci lapb->dev, frame->pf); 48662306a36Sopenharmony_ci lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev); 48762306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 48862306a36Sopenharmony_ci LAPB_RESPONSE); 48962306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 49062306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 49162306a36Sopenharmony_ci lapb->state = LAPB_STATE_3; 49262306a36Sopenharmony_ci lapb->condition = 0x00; 49362306a36Sopenharmony_ci lapb->n2count = 0; 49462306a36Sopenharmony_ci lapb->vs = 0; 49562306a36Sopenharmony_ci lapb->vr = 0; 49662306a36Sopenharmony_ci lapb->va = 0; 49762306a36Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci case LAPB_SABME: 50262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S4 RX SABME(%d)\n", lapb->dev, frame->pf); 50362306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 50462306a36Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX UA(%d)\n", 50562306a36Sopenharmony_ci lapb->dev, frame->pf); 50662306a36Sopenharmony_ci lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev); 50762306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_UA, frame->pf, 50862306a36Sopenharmony_ci LAPB_RESPONSE); 50962306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 51062306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 51162306a36Sopenharmony_ci lapb->state = LAPB_STATE_3; 51262306a36Sopenharmony_ci lapb->condition = 0x00; 51362306a36Sopenharmony_ci lapb->n2count = 0; 51462306a36Sopenharmony_ci lapb->vs = 0; 51562306a36Sopenharmony_ci lapb->vr = 0; 51662306a36Sopenharmony_ci lapb->va = 0; 51762306a36Sopenharmony_ci lapb_connect_indication(lapb, LAPB_OK); 51862306a36Sopenharmony_ci } else { 51962306a36Sopenharmony_ci lapb_dbg(1, "(%p) S4 TX DM(%d)\n", 52062306a36Sopenharmony_ci lapb->dev, frame->pf); 52162306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_DM, frame->pf, 52262306a36Sopenharmony_ci LAPB_RESPONSE); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci kfree_skb(skb); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci/* 53162306a36Sopenharmony_ci * Process an incoming LAPB frame 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_civoid lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct lapb_frame frame; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (lapb_decode(lapb, skb, &frame) < 0) { 53862306a36Sopenharmony_ci kfree_skb(skb); 53962306a36Sopenharmony_ci return; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci switch (lapb->state) { 54362306a36Sopenharmony_ci case LAPB_STATE_0: 54462306a36Sopenharmony_ci lapb_state0_machine(lapb, skb, &frame); break; 54562306a36Sopenharmony_ci case LAPB_STATE_1: 54662306a36Sopenharmony_ci lapb_state1_machine(lapb, skb, &frame); break; 54762306a36Sopenharmony_ci case LAPB_STATE_2: 54862306a36Sopenharmony_ci lapb_state2_machine(lapb, skb, &frame); break; 54962306a36Sopenharmony_ci case LAPB_STATE_3: 55062306a36Sopenharmony_ci lapb_state3_machine(lapb, skb, &frame); break; 55162306a36Sopenharmony_ci case LAPB_STATE_4: 55262306a36Sopenharmony_ci lapb_state4_machine(lapb, skb, &frame); break; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci lapb_kick(lapb); 55662306a36Sopenharmony_ci} 557