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 Naylor Started Coding 962306a36Sopenharmony_ci * LAPB 002 Jonathan Naylor New timer architecture. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci#include <linux/socket.h> 1762306a36Sopenharmony_ci#include <linux/in.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/timer.h> 2062306a36Sopenharmony_ci#include <linux/string.h> 2162306a36Sopenharmony_ci#include <linux/sockios.h> 2262306a36Sopenharmony_ci#include <linux/net.h> 2362306a36Sopenharmony_ci#include <linux/inet.h> 2462306a36Sopenharmony_ci#include <linux/skbuff.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <net/sock.h> 2762306a36Sopenharmony_ci#include <linux/uaccess.h> 2862306a36Sopenharmony_ci#include <linux/fcntl.h> 2962306a36Sopenharmony_ci#include <linux/mm.h> 3062306a36Sopenharmony_ci#include <linux/interrupt.h> 3162306a36Sopenharmony_ci#include <net/lapb.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * This procedure is passed a buffer descriptor for an iframe. It builds 3562306a36Sopenharmony_ci * the rest of the control part of the frame and then writes it out. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci unsigned char *frame; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (!skb) 4262306a36Sopenharmony_ci return; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 4562306a36Sopenharmony_ci frame = skb_push(skb, 2); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci frame[0] = LAPB_I; 4862306a36Sopenharmony_ci frame[0] |= lapb->vs << 1; 4962306a36Sopenharmony_ci frame[1] = poll_bit ? LAPB_EPF : 0; 5062306a36Sopenharmony_ci frame[1] |= lapb->vr << 1; 5162306a36Sopenharmony_ci } else { 5262306a36Sopenharmony_ci frame = skb_push(skb, 1); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci *frame = LAPB_I; 5562306a36Sopenharmony_ci *frame |= poll_bit ? LAPB_SPF : 0; 5662306a36Sopenharmony_ci *frame |= lapb->vr << 5; 5762306a36Sopenharmony_ci *frame |= lapb->vs << 1; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX I(%d) S%d R%d\n", 6162306a36Sopenharmony_ci lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci lapb_transmit_buffer(lapb, skb, LAPB_COMMAND); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid lapb_kick(struct lapb_cb *lapb) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct sk_buff *skb, *skbn; 6962306a36Sopenharmony_ci unsigned short modulus, start, end; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; 7262306a36Sopenharmony_ci start = !skb_peek(&lapb->ack_queue) ? lapb->va : lapb->vs; 7362306a36Sopenharmony_ci end = (lapb->va + lapb->window) % modulus; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) && 7662306a36Sopenharmony_ci start != end && skb_peek(&lapb->write_queue)) { 7762306a36Sopenharmony_ci lapb->vs = start; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * Dequeue the frame and copy it. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci skb = skb_dequeue(&lapb->write_queue); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci do { 8562306a36Sopenharmony_ci skbn = skb_copy(skb, GFP_ATOMIC); 8662306a36Sopenharmony_ci if (!skbn) { 8762306a36Sopenharmony_ci skb_queue_head(&lapb->write_queue, skb); 8862306a36Sopenharmony_ci break; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (skb->sk) 9262306a36Sopenharmony_ci skb_set_owner_w(skbn, skb->sk); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * Transmit the frame copy. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci lapb_send_iframe(lapb, skbn, LAPB_POLLOFF); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci lapb->vs = (lapb->vs + 1) % modulus; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * Requeue the original data frame. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci skb_queue_tail(&lapb->ack_queue, skb); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci } while (lapb->vs != end && (skb = skb_dequeue(&lapb->write_queue)) != NULL); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (!lapb_t1timer_running(lapb)) 11162306a36Sopenharmony_ci lapb_start_t1timer(lapb); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_civoid lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci unsigned char *ptr; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ptr = skb_push(skb, 1); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (lapb->mode & LAPB_MLP) { 12262306a36Sopenharmony_ci if (lapb->mode & LAPB_DCE) { 12362306a36Sopenharmony_ci if (type == LAPB_COMMAND) 12462306a36Sopenharmony_ci *ptr = LAPB_ADDR_C; 12562306a36Sopenharmony_ci if (type == LAPB_RESPONSE) 12662306a36Sopenharmony_ci *ptr = LAPB_ADDR_D; 12762306a36Sopenharmony_ci } else { 12862306a36Sopenharmony_ci if (type == LAPB_COMMAND) 12962306a36Sopenharmony_ci *ptr = LAPB_ADDR_D; 13062306a36Sopenharmony_ci if (type == LAPB_RESPONSE) 13162306a36Sopenharmony_ci *ptr = LAPB_ADDR_C; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } else { 13462306a36Sopenharmony_ci if (lapb->mode & LAPB_DCE) { 13562306a36Sopenharmony_ci if (type == LAPB_COMMAND) 13662306a36Sopenharmony_ci *ptr = LAPB_ADDR_A; 13762306a36Sopenharmony_ci if (type == LAPB_RESPONSE) 13862306a36Sopenharmony_ci *ptr = LAPB_ADDR_B; 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci if (type == LAPB_COMMAND) 14162306a36Sopenharmony_ci *ptr = LAPB_ADDR_B; 14262306a36Sopenharmony_ci if (type == LAPB_RESPONSE) 14362306a36Sopenharmony_ci *ptr = LAPB_ADDR_A; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci lapb_dbg(2, "(%p) S%d TX %3ph\n", lapb->dev, lapb->state, skb->data); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!lapb_data_transmit(lapb, skb)) 15062306a36Sopenharmony_ci kfree_skb(skb); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_civoid lapb_establish_data_link(struct lapb_cb *lapb) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci lapb->condition = 0x00; 15662306a36Sopenharmony_ci lapb->n2count = 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 15962306a36Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX SABME(1)\n", lapb->dev, lapb->state); 16062306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX SABM(1)\n", lapb->dev, lapb->state); 16362306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci lapb_start_t1timer(lapb); 16762306a36Sopenharmony_ci lapb_stop_t2timer(lapb); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_civoid lapb_enquiry_response(struct lapb_cb *lapb) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX RR(1) R%d\n", 17362306a36Sopenharmony_ci lapb->dev, lapb->state, lapb->vr); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_civoid lapb_timeout_response(struct lapb_cb *lapb) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX RR(0) R%d\n", 18362306a36Sopenharmony_ci lapb->dev, lapb->state, lapb->vr); 18462306a36Sopenharmony_ci lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_civoid lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci if (lapb->vs == nr) { 19262306a36Sopenharmony_ci lapb_frames_acked(lapb, nr); 19362306a36Sopenharmony_ci lapb_stop_t1timer(lapb); 19462306a36Sopenharmony_ci lapb->n2count = 0; 19562306a36Sopenharmony_ci } else if (lapb->va != nr) { 19662306a36Sopenharmony_ci lapb_frames_acked(lapb, nr); 19762306a36Sopenharmony_ci lapb_start_t1timer(lapb); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_civoid lapb_check_need_response(struct lapb_cb *lapb, int type, int pf) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci if (type == LAPB_COMMAND && pf) 20462306a36Sopenharmony_ci lapb_enquiry_response(lapb); 20562306a36Sopenharmony_ci} 206