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 Naylor Started Coding 98c2ecf20Sopenharmony_ci * LAPB 002 Jonathan Naylor New timer architecture. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/socket.h> 178c2ecf20Sopenharmony_ci#include <linux/in.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/timer.h> 208c2ecf20Sopenharmony_ci#include <linux/string.h> 218c2ecf20Sopenharmony_ci#include <linux/sockios.h> 228c2ecf20Sopenharmony_ci#include <linux/net.h> 238c2ecf20Sopenharmony_ci#include <linux/inet.h> 248c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <net/sock.h> 278c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 288c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 298c2ecf20Sopenharmony_ci#include <linux/mm.h> 308c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 318c2ecf20Sopenharmony_ci#include <net/lapb.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * This procedure is passed a buffer descriptor for an iframe. It builds 358c2ecf20Sopenharmony_ci * the rest of the control part of the frame and then writes it out. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci unsigned char *frame; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (!skb) 428c2ecf20Sopenharmony_ci return; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 458c2ecf20Sopenharmony_ci frame = skb_push(skb, 2); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci frame[0] = LAPB_I; 488c2ecf20Sopenharmony_ci frame[0] |= lapb->vs << 1; 498c2ecf20Sopenharmony_ci frame[1] = poll_bit ? LAPB_EPF : 0; 508c2ecf20Sopenharmony_ci frame[1] |= lapb->vr << 1; 518c2ecf20Sopenharmony_ci } else { 528c2ecf20Sopenharmony_ci frame = skb_push(skb, 1); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci *frame = LAPB_I; 558c2ecf20Sopenharmony_ci *frame |= poll_bit ? LAPB_SPF : 0; 568c2ecf20Sopenharmony_ci *frame |= lapb->vr << 5; 578c2ecf20Sopenharmony_ci *frame |= lapb->vs << 1; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX I(%d) S%d R%d\n", 618c2ecf20Sopenharmony_ci lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci lapb_transmit_buffer(lapb, skb, LAPB_COMMAND); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid lapb_kick(struct lapb_cb *lapb) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct sk_buff *skb, *skbn; 698c2ecf20Sopenharmony_ci unsigned short modulus, start, end; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; 728c2ecf20Sopenharmony_ci start = !skb_peek(&lapb->ack_queue) ? lapb->va : lapb->vs; 738c2ecf20Sopenharmony_ci end = (lapb->va + lapb->window) % modulus; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) && 768c2ecf20Sopenharmony_ci start != end && skb_peek(&lapb->write_queue)) { 778c2ecf20Sopenharmony_ci lapb->vs = start; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * Dequeue the frame and copy it. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci skb = skb_dequeue(&lapb->write_queue); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci do { 858c2ecf20Sopenharmony_ci skbn = skb_copy(skb, GFP_ATOMIC); 868c2ecf20Sopenharmony_ci if (!skbn) { 878c2ecf20Sopenharmony_ci skb_queue_head(&lapb->write_queue, skb); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (skb->sk) 928c2ecf20Sopenharmony_ci skb_set_owner_w(skbn, skb->sk); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * Transmit the frame copy. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci lapb_send_iframe(lapb, skbn, LAPB_POLLOFF); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci lapb->vs = (lapb->vs + 1) % modulus; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * Requeue the original data frame. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci skb_queue_tail(&lapb->ack_queue, skb); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci } while (lapb->vs != end && (skb = skb_dequeue(&lapb->write_queue)) != NULL); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!lapb_t1timer_running(lapb)) 1118c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci unsigned char *ptr; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ptr = skb_push(skb, 1); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_MLP) { 1228c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_DCE) { 1238c2ecf20Sopenharmony_ci if (type == LAPB_COMMAND) 1248c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_C; 1258c2ecf20Sopenharmony_ci if (type == LAPB_RESPONSE) 1268c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_D; 1278c2ecf20Sopenharmony_ci } else { 1288c2ecf20Sopenharmony_ci if (type == LAPB_COMMAND) 1298c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_D; 1308c2ecf20Sopenharmony_ci if (type == LAPB_RESPONSE) 1318c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_C; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_DCE) { 1358c2ecf20Sopenharmony_ci if (type == LAPB_COMMAND) 1368c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_A; 1378c2ecf20Sopenharmony_ci if (type == LAPB_RESPONSE) 1388c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_B; 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci if (type == LAPB_COMMAND) 1418c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_B; 1428c2ecf20Sopenharmony_ci if (type == LAPB_RESPONSE) 1438c2ecf20Sopenharmony_ci *ptr = LAPB_ADDR_A; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci lapb_dbg(2, "(%p) S%d TX %3ph\n", lapb->dev, lapb->state, skb->data); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!lapb_data_transmit(lapb, skb)) 1508c2ecf20Sopenharmony_ci kfree_skb(skb); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_civoid lapb_establish_data_link(struct lapb_cb *lapb) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci lapb->condition = 0x00; 1568c2ecf20Sopenharmony_ci lapb->n2count = 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (lapb->mode & LAPB_EXTENDED) { 1598c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX SABME(1)\n", lapb->dev, lapb->state); 1608c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); 1618c2ecf20Sopenharmony_ci } else { 1628c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX SABM(1)\n", lapb->dev, lapb->state); 1638c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 1678c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_civoid lapb_enquiry_response(struct lapb_cb *lapb) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX RR(1) R%d\n", 1738c2ecf20Sopenharmony_ci lapb->dev, lapb->state, lapb->vr); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_civoid lapb_timeout_response(struct lapb_cb *lapb) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S%d TX RR(0) R%d\n", 1838c2ecf20Sopenharmony_ci lapb->dev, lapb->state, lapb->vr); 1848c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_civoid lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci if (lapb->vs == nr) { 1928c2ecf20Sopenharmony_ci lapb_frames_acked(lapb, nr); 1938c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 1948c2ecf20Sopenharmony_ci lapb->n2count = 0; 1958c2ecf20Sopenharmony_ci } else if (lapb->va != nr) { 1968c2ecf20Sopenharmony_ci lapb_frames_acked(lapb, nr); 1978c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_civoid lapb_check_need_response(struct lapb_cb *lapb, int type, int pf) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci if (type == LAPB_COMMAND && pf) 2048c2ecf20Sopenharmony_ci lapb_enquiry_response(lapb); 2058c2ecf20Sopenharmony_ci} 206