18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) 58c2ecf20Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 68c2ecf20Sopenharmony_ci * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) 78c2ecf20Sopenharmony_ci * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/socket.h> 128c2ecf20Sopenharmony_ci#include <linux/in.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/timer.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/sockios.h> 178c2ecf20Sopenharmony_ci#include <linux/net.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <net/ax25.h> 208c2ecf20Sopenharmony_ci#include <linux/inet.h> 218c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 228c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 238c2ecf20Sopenharmony_ci#include <net/sock.h> 248c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 278c2ecf20Sopenharmony_ci#include <linux/mm.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * This routine purges all the queues of frames. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_civoid ax25_clear_queues(ax25_cb *ax25) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci skb_queue_purge(&ax25->write_queue); 368c2ecf20Sopenharmony_ci skb_queue_purge(&ax25->ack_queue); 378c2ecf20Sopenharmony_ci skb_queue_purge(&ax25->reseq_queue); 388c2ecf20Sopenharmony_ci skb_queue_purge(&ax25->frag_queue); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * This routine purges the input queue of those frames that have been 438c2ecf20Sopenharmony_ci * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the 448c2ecf20Sopenharmony_ci * SDL diagram. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_civoid ax25_frames_acked(ax25_cb *ax25, unsigned short nr) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct sk_buff *skb; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* 518c2ecf20Sopenharmony_ci * Remove all the ack-ed frames from the ack queue. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci if (ax25->va != nr) { 548c2ecf20Sopenharmony_ci while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) { 558c2ecf20Sopenharmony_ci skb = skb_dequeue(&ax25->ack_queue); 568c2ecf20Sopenharmony_ci kfree_skb(skb); 578c2ecf20Sopenharmony_ci ax25->va = (ax25->va + 1) % ax25->modulus; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_civoid ax25_requeue_frames(ax25_cb *ax25) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct sk_buff *skb; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * Requeue all the un-ack-ed frames on the output queue to be picked 688c2ecf20Sopenharmony_ci * up by ax25_kick called from the timer. This arrangement handles the 698c2ecf20Sopenharmony_ci * possibility of an empty output queue. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci while ((skb = skb_dequeue_tail(&ax25->ack_queue)) != NULL) 728c2ecf20Sopenharmony_ci skb_queue_head(&ax25->write_queue, skb); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * Validate that the value of nr is between va and vs. Return true or 778c2ecf20Sopenharmony_ci * false for testing. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ciint ax25_validate_nr(ax25_cb *ax25, unsigned short nr) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci unsigned short vc = ax25->va; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci while (vc != ax25->vs) { 848c2ecf20Sopenharmony_ci if (nr == vc) return 1; 858c2ecf20Sopenharmony_ci vc = (vc + 1) % ax25->modulus; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (nr == ax25->vs) return 1; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * This routine is the centralised routine for parsing the control 958c2ecf20Sopenharmony_ci * information for the different frame formats. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ciint ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci unsigned char *frame; 1008c2ecf20Sopenharmony_ci int frametype = AX25_ILLEGAL; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci frame = skb->data; 1038c2ecf20Sopenharmony_ci *ns = *nr = *pf = 0; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (ax25->modulus == AX25_MODULUS) { 1068c2ecf20Sopenharmony_ci if ((frame[0] & AX25_S) == 0) { 1078c2ecf20Sopenharmony_ci frametype = AX25_I; /* I frame - carries NR/NS/PF */ 1088c2ecf20Sopenharmony_ci *ns = (frame[0] >> 1) & 0x07; 1098c2ecf20Sopenharmony_ci *nr = (frame[0] >> 5) & 0x07; 1108c2ecf20Sopenharmony_ci *pf = frame[0] & AX25_PF; 1118c2ecf20Sopenharmony_ci } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */ 1128c2ecf20Sopenharmony_ci frametype = frame[0] & 0x0F; 1138c2ecf20Sopenharmony_ci *nr = (frame[0] >> 5) & 0x07; 1148c2ecf20Sopenharmony_ci *pf = frame[0] & AX25_PF; 1158c2ecf20Sopenharmony_ci } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */ 1168c2ecf20Sopenharmony_ci frametype = frame[0] & ~AX25_PF; 1178c2ecf20Sopenharmony_ci *pf = frame[0] & AX25_PF; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci skb_pull(skb, 1); 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci if ((frame[0] & AX25_S) == 0) { 1228c2ecf20Sopenharmony_ci frametype = AX25_I; /* I frame - carries NR/NS/PF */ 1238c2ecf20Sopenharmony_ci *ns = (frame[0] >> 1) & 0x7F; 1248c2ecf20Sopenharmony_ci *nr = (frame[1] >> 1) & 0x7F; 1258c2ecf20Sopenharmony_ci *pf = frame[1] & AX25_EPF; 1268c2ecf20Sopenharmony_ci skb_pull(skb, 2); 1278c2ecf20Sopenharmony_ci } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */ 1288c2ecf20Sopenharmony_ci frametype = frame[0] & 0x0F; 1298c2ecf20Sopenharmony_ci *nr = (frame[1] >> 1) & 0x7F; 1308c2ecf20Sopenharmony_ci *pf = frame[1] & AX25_EPF; 1318c2ecf20Sopenharmony_ci skb_pull(skb, 2); 1328c2ecf20Sopenharmony_ci } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */ 1338c2ecf20Sopenharmony_ci frametype = frame[0] & ~AX25_PF; 1348c2ecf20Sopenharmony_ci *pf = frame[0] & AX25_PF; 1358c2ecf20Sopenharmony_ci skb_pull(skb, 1); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return frametype; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * This routine is called when the HDLC layer internally generates a 1448c2ecf20Sopenharmony_ci * command or response for the remote machine ( eg. RR, UA etc. ). 1458c2ecf20Sopenharmony_ci * Only supervisory or unnumbered frames are processed. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_civoid ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct sk_buff *skb; 1508c2ecf20Sopenharmony_ci unsigned char *dptr; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL) 1538c2ecf20Sopenharmony_ci return; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Assume a response - address structure for DTE */ 1608c2ecf20Sopenharmony_ci if (ax25->modulus == AX25_MODULUS) { 1618c2ecf20Sopenharmony_ci dptr = skb_put(skb, 1); 1628c2ecf20Sopenharmony_ci *dptr = frametype; 1638c2ecf20Sopenharmony_ci *dptr |= (poll_bit) ? AX25_PF : 0; 1648c2ecf20Sopenharmony_ci if ((frametype & AX25_U) == AX25_S) /* S frames carry NR */ 1658c2ecf20Sopenharmony_ci *dptr |= (ax25->vr << 5); 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci if ((frametype & AX25_U) == AX25_U) { 1688c2ecf20Sopenharmony_ci dptr = skb_put(skb, 1); 1698c2ecf20Sopenharmony_ci *dptr = frametype; 1708c2ecf20Sopenharmony_ci *dptr |= (poll_bit) ? AX25_PF : 0; 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci dptr = skb_put(skb, 2); 1738c2ecf20Sopenharmony_ci dptr[0] = frametype; 1748c2ecf20Sopenharmony_ci dptr[1] = (ax25->vr << 1); 1758c2ecf20Sopenharmony_ci dptr[1] |= (poll_bit) ? AX25_EPF : 0; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ax25_transmit_buffer(ax25, skb, type); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * Send a 'DM' to an unknown connection attempt, or an invalid caller. 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * Note: src here is the sender, thus it's the target of the DM 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_civoid ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct sk_buff *skb; 1908c2ecf20Sopenharmony_ci char *dptr; 1918c2ecf20Sopenharmony_ci ax25_digi retdigi; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (dev == NULL) 1948c2ecf20Sopenharmony_ci return; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL) 1978c2ecf20Sopenharmony_ci return; /* Next SABM will get DM'd */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci skb_reserve(skb, dev->hard_header_len); 2008c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ax25_digi_invert(digi, &retdigi); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci dptr = skb_put(skb, 1); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci *dptr = AX25_DM | AX25_PF; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* 2098c2ecf20Sopenharmony_ci * Do the address ourselves 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci dptr = skb_push(skb, ax25_addr_size(digi)); 2128c2ecf20Sopenharmony_ci dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ax25_queue_xmit(skb, dev); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* 2188c2ecf20Sopenharmony_ci * Exponential backoff for AX.25 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_civoid ax25_calculate_t1(ax25_cb *ax25) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int n, t = 2; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci switch (ax25->backoff) { 2258c2ecf20Sopenharmony_ci case 0: 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci case 1: 2298c2ecf20Sopenharmony_ci t += 2 * ax25->n2count; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci case 2: 2338c2ecf20Sopenharmony_ci for (n = 0; n < ax25->n2count; n++) 2348c2ecf20Sopenharmony_ci t *= 2; 2358c2ecf20Sopenharmony_ci if (t > 8) t = 8; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ax25->t1 = t * ax25->rtt; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* 2438c2ecf20Sopenharmony_ci * Calculate the Round Trip Time 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_civoid ax25_calculate_rtt(ax25_cb *ax25) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci if (ax25->backoff == 0) 2488c2ecf20Sopenharmony_ci return; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (ax25_t1timer_running(ax25) && ax25->n2count == 0) 2518c2ecf20Sopenharmony_ci ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (ax25->rtt < AX25_T1CLAMPLO) 2548c2ecf20Sopenharmony_ci ax25->rtt = AX25_T1CLAMPLO; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (ax25->rtt > AX25_T1CLAMPHI) 2578c2ecf20Sopenharmony_ci ax25->rtt = AX25_T1CLAMPHI; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid ax25_disconnect(ax25_cb *ax25, int reason) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci ax25_clear_queues(ax25); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (reason == ENETUNREACH) { 2658c2ecf20Sopenharmony_ci del_timer_sync(&ax25->timer); 2668c2ecf20Sopenharmony_ci del_timer_sync(&ax25->t1timer); 2678c2ecf20Sopenharmony_ci del_timer_sync(&ax25->t2timer); 2688c2ecf20Sopenharmony_ci del_timer_sync(&ax25->t3timer); 2698c2ecf20Sopenharmony_ci del_timer_sync(&ax25->idletimer); 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY)) 2728c2ecf20Sopenharmony_ci ax25_stop_heartbeat(ax25); 2738c2ecf20Sopenharmony_ci ax25_stop_t1timer(ax25); 2748c2ecf20Sopenharmony_ci ax25_stop_t2timer(ax25); 2758c2ecf20Sopenharmony_ci ax25_stop_t3timer(ax25); 2768c2ecf20Sopenharmony_ci ax25_stop_idletimer(ax25); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ax25->state = AX25_STATE_0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ax25_link_failed(ax25, reason); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (ax25->sk != NULL) { 2848c2ecf20Sopenharmony_ci local_bh_disable(); 2858c2ecf20Sopenharmony_ci bh_lock_sock(ax25->sk); 2868c2ecf20Sopenharmony_ci ax25->sk->sk_state = TCP_CLOSE; 2878c2ecf20Sopenharmony_ci ax25->sk->sk_err = reason; 2888c2ecf20Sopenharmony_ci ax25->sk->sk_shutdown |= SEND_SHUTDOWN; 2898c2ecf20Sopenharmony_ci if (!sock_flag(ax25->sk, SOCK_DEAD)) { 2908c2ecf20Sopenharmony_ci ax25->sk->sk_state_change(ax25->sk); 2918c2ecf20Sopenharmony_ci sock_set_flag(ax25->sk, SOCK_DEAD); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci bh_unlock_sock(ax25->sk); 2948c2ecf20Sopenharmony_ci local_bh_enable(); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci} 297