12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
51da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
61da177e4SLinus Torvalds * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
71da177e4SLinus Torvalds * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds #include <linux/errno.h>
101da177e4SLinus Torvalds #include <linux/types.h>
111da177e4SLinus Torvalds #include <linux/socket.h>
121da177e4SLinus Torvalds #include <linux/in.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/timer.h>
151da177e4SLinus Torvalds #include <linux/string.h>
161da177e4SLinus Torvalds #include <linux/sockios.h>
171da177e4SLinus Torvalds #include <linux/net.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
191da177e4SLinus Torvalds #include <net/ax25.h>
201da177e4SLinus Torvalds #include <linux/inet.h>
211da177e4SLinus Torvalds #include <linux/netdevice.h>
221da177e4SLinus Torvalds #include <linux/skbuff.h>
231da177e4SLinus Torvalds #include <net/sock.h>
24c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h>
257c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
261da177e4SLinus Torvalds #include <linux/fcntl.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/interrupt.h>
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds * This routine purges all the queues of frames.
321da177e4SLinus Torvalds */
ax25_clear_queues(ax25_cb * ax25)331da177e4SLinus Torvalds void ax25_clear_queues(ax25_cb *ax25)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds skb_queue_purge(&ax25->write_queue);
361da177e4SLinus Torvalds skb_queue_purge(&ax25->ack_queue);
371da177e4SLinus Torvalds skb_queue_purge(&ax25->reseq_queue);
381da177e4SLinus Torvalds skb_queue_purge(&ax25->frag_queue);
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds /*
421da177e4SLinus Torvalds * This routine purges the input queue of those frames that have been
431da177e4SLinus Torvalds * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
441da177e4SLinus Torvalds * SDL diagram.
451da177e4SLinus Torvalds */
ax25_frames_acked(ax25_cb * ax25,unsigned short nr)461da177e4SLinus Torvalds void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds struct sk_buff *skb;
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds /*
511da177e4SLinus Torvalds * Remove all the ack-ed frames from the ack queue.
521da177e4SLinus Torvalds */
531da177e4SLinus Torvalds if (ax25->va != nr) {
541da177e4SLinus Torvalds while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) {
551da177e4SLinus Torvalds skb = skb_dequeue(&ax25->ack_queue);
561da177e4SLinus Torvalds kfree_skb(skb);
571da177e4SLinus Torvalds ax25->va = (ax25->va + 1) % ax25->modulus;
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
ax25_requeue_frames(ax25_cb * ax25)621da177e4SLinus Torvalds void ax25_requeue_frames(ax25_cb *ax25)
631da177e4SLinus Torvalds {
647dccf1f4SJarek Poplawski struct sk_buff *skb;
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds /*
671da177e4SLinus Torvalds * Requeue all the un-ack-ed frames on the output queue to be picked
681da177e4SLinus Torvalds * up by ax25_kick called from the timer. This arrangement handles the
691da177e4SLinus Torvalds * possibility of an empty output queue.
701da177e4SLinus Torvalds */
717dccf1f4SJarek Poplawski while ((skb = skb_dequeue_tail(&ax25->ack_queue)) != NULL)
721da177e4SLinus Torvalds skb_queue_head(&ax25->write_queue, skb);
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds /*
761da177e4SLinus Torvalds * Validate that the value of nr is between va and vs. Return true or
771da177e4SLinus Torvalds * false for testing.
781da177e4SLinus Torvalds */
ax25_validate_nr(ax25_cb * ax25,unsigned short nr)791da177e4SLinus Torvalds int ax25_validate_nr(ax25_cb *ax25, unsigned short nr)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds unsigned short vc = ax25->va;
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds while (vc != ax25->vs) {
841da177e4SLinus Torvalds if (nr == vc) return 1;
851da177e4SLinus Torvalds vc = (vc + 1) % ax25->modulus;
861da177e4SLinus Torvalds }
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds if (nr == ax25->vs) return 1;
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds return 0;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds /*
941da177e4SLinus Torvalds * This routine is the centralised routine for parsing the control
951da177e4SLinus Torvalds * information for the different frame formats.
961da177e4SLinus Torvalds */
ax25_decode(ax25_cb * ax25,struct sk_buff * skb,int * ns,int * nr,int * pf)971da177e4SLinus Torvalds int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
981da177e4SLinus Torvalds {
991da177e4SLinus Torvalds unsigned char *frame;
1001da177e4SLinus Torvalds int frametype = AX25_ILLEGAL;
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds frame = skb->data;
1031da177e4SLinus Torvalds *ns = *nr = *pf = 0;
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds if (ax25->modulus == AX25_MODULUS) {
1061da177e4SLinus Torvalds if ((frame[0] & AX25_S) == 0) {
1071da177e4SLinus Torvalds frametype = AX25_I; /* I frame - carries NR/NS/PF */
1081da177e4SLinus Torvalds *ns = (frame[0] >> 1) & 0x07;
1091da177e4SLinus Torvalds *nr = (frame[0] >> 5) & 0x07;
1101da177e4SLinus Torvalds *pf = frame[0] & AX25_PF;
1111da177e4SLinus Torvalds } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */
1121da177e4SLinus Torvalds frametype = frame[0] & 0x0F;
1131da177e4SLinus Torvalds *nr = (frame[0] >> 5) & 0x07;
1141da177e4SLinus Torvalds *pf = frame[0] & AX25_PF;
1151da177e4SLinus Torvalds } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */
1161da177e4SLinus Torvalds frametype = frame[0] & ~AX25_PF;
1171da177e4SLinus Torvalds *pf = frame[0] & AX25_PF;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds skb_pull(skb, 1);
1201da177e4SLinus Torvalds } else {
1211da177e4SLinus Torvalds if ((frame[0] & AX25_S) == 0) {
1221da177e4SLinus Torvalds frametype = AX25_I; /* I frame - carries NR/NS/PF */
1231da177e4SLinus Torvalds *ns = (frame[0] >> 1) & 0x7F;
1241da177e4SLinus Torvalds *nr = (frame[1] >> 1) & 0x7F;
1251da177e4SLinus Torvalds *pf = frame[1] & AX25_EPF;
1261da177e4SLinus Torvalds skb_pull(skb, 2);
1271da177e4SLinus Torvalds } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */
1281da177e4SLinus Torvalds frametype = frame[0] & 0x0F;
1291da177e4SLinus Torvalds *nr = (frame[1] >> 1) & 0x7F;
1301da177e4SLinus Torvalds *pf = frame[1] & AX25_EPF;
1311da177e4SLinus Torvalds skb_pull(skb, 2);
1321da177e4SLinus Torvalds } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */
1331da177e4SLinus Torvalds frametype = frame[0] & ~AX25_PF;
1341da177e4SLinus Torvalds *pf = frame[0] & AX25_PF;
1351da177e4SLinus Torvalds skb_pull(skb, 1);
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds return frametype;
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds /*
1431da177e4SLinus Torvalds * This routine is called when the HDLC layer internally generates a
1441da177e4SLinus Torvalds * command or response for the remote machine ( eg. RR, UA etc. ).
1451da177e4SLinus Torvalds * Only supervisory or unnumbered frames are processed.
1461da177e4SLinus Torvalds */
ax25_send_control(ax25_cb * ax25,int frametype,int poll_bit,int type)1471da177e4SLinus Torvalds void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds struct sk_buff *skb;
1501da177e4SLinus Torvalds unsigned char *dptr;
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL)
1531da177e4SLinus Torvalds return;
1541da177e4SLinus Torvalds
1551da177e4SLinus Torvalds skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len);
1561da177e4SLinus Torvalds
157c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb);
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds /* Assume a response - address structure for DTE */
1601da177e4SLinus Torvalds if (ax25->modulus == AX25_MODULUS) {
1611da177e4SLinus Torvalds dptr = skb_put(skb, 1);
1621da177e4SLinus Torvalds *dptr = frametype;
1631da177e4SLinus Torvalds *dptr |= (poll_bit) ? AX25_PF : 0;
1641da177e4SLinus Torvalds if ((frametype & AX25_U) == AX25_S) /* S frames carry NR */
1651da177e4SLinus Torvalds *dptr |= (ax25->vr << 5);
1661da177e4SLinus Torvalds } else {
1671da177e4SLinus Torvalds if ((frametype & AX25_U) == AX25_U) {
1681da177e4SLinus Torvalds dptr = skb_put(skb, 1);
1691da177e4SLinus Torvalds *dptr = frametype;
1701da177e4SLinus Torvalds *dptr |= (poll_bit) ? AX25_PF : 0;
1711da177e4SLinus Torvalds } else {
1721da177e4SLinus Torvalds dptr = skb_put(skb, 2);
1731da177e4SLinus Torvalds dptr[0] = frametype;
1741da177e4SLinus Torvalds dptr[1] = (ax25->vr << 1);
1751da177e4SLinus Torvalds dptr[1] |= (poll_bit) ? AX25_EPF : 0;
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds
1791da177e4SLinus Torvalds ax25_transmit_buffer(ax25, skb, type);
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds
1821da177e4SLinus Torvalds /*
1831da177e4SLinus Torvalds * Send a 'DM' to an unknown connection attempt, or an invalid caller.
1841da177e4SLinus Torvalds *
1851da177e4SLinus Torvalds * Note: src here is the sender, thus it's the target of the DM
1861da177e4SLinus Torvalds */
ax25_return_dm(struct net_device * dev,ax25_address * src,ax25_address * dest,ax25_digi * digi)1871da177e4SLinus Torvalds void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
1881da177e4SLinus Torvalds {
1891da177e4SLinus Torvalds struct sk_buff *skb;
1901da177e4SLinus Torvalds char *dptr;
1911da177e4SLinus Torvalds ax25_digi retdigi;
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds if (dev == NULL)
1941da177e4SLinus Torvalds return;
1951da177e4SLinus Torvalds
1961da177e4SLinus Torvalds if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL)
1971da177e4SLinus Torvalds return; /* Next SABM will get DM'd */
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds skb_reserve(skb, dev->hard_header_len);
200c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb);
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds ax25_digi_invert(digi, &retdigi);
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds dptr = skb_put(skb, 1);
2051da177e4SLinus Torvalds
2061da177e4SLinus Torvalds *dptr = AX25_DM | AX25_PF;
2071da177e4SLinus Torvalds
2081da177e4SLinus Torvalds /*
2091da177e4SLinus Torvalds * Do the address ourselves
2101da177e4SLinus Torvalds */
2111da177e4SLinus Torvalds dptr = skb_push(skb, ax25_addr_size(digi));
2121da177e4SLinus Torvalds dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
2131da177e4SLinus Torvalds
21429c4be51SArnaldo Carvalho de Melo ax25_queue_xmit(skb, dev);
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds /*
2181da177e4SLinus Torvalds * Exponential backoff for AX.25
2191da177e4SLinus Torvalds */
ax25_calculate_t1(ax25_cb * ax25)2201da177e4SLinus Torvalds void ax25_calculate_t1(ax25_cb *ax25)
2211da177e4SLinus Torvalds {
2221da177e4SLinus Torvalds int n, t = 2;
2231da177e4SLinus Torvalds
2241da177e4SLinus Torvalds switch (ax25->backoff) {
2251da177e4SLinus Torvalds case 0:
2261da177e4SLinus Torvalds break;
2271da177e4SLinus Torvalds
2281da177e4SLinus Torvalds case 1:
2291da177e4SLinus Torvalds t += 2 * ax25->n2count;
2301da177e4SLinus Torvalds break;
2311da177e4SLinus Torvalds
2321da177e4SLinus Torvalds case 2:
2331da177e4SLinus Torvalds for (n = 0; n < ax25->n2count; n++)
2341da177e4SLinus Torvalds t *= 2;
2351da177e4SLinus Torvalds if (t > 8) t = 8;
2361da177e4SLinus Torvalds break;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds
2391da177e4SLinus Torvalds ax25->t1 = t * ax25->rtt;
2401da177e4SLinus Torvalds }
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds /*
2431da177e4SLinus Torvalds * Calculate the Round Trip Time
2441da177e4SLinus Torvalds */
ax25_calculate_rtt(ax25_cb * ax25)2451da177e4SLinus Torvalds void ax25_calculate_rtt(ax25_cb *ax25)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds if (ax25->backoff == 0)
2481da177e4SLinus Torvalds return;
2491da177e4SLinus Torvalds
2501da177e4SLinus Torvalds if (ax25_t1timer_running(ax25) && ax25->n2count == 0)
2511da177e4SLinus Torvalds ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10;
2521da177e4SLinus Torvalds
2531da177e4SLinus Torvalds if (ax25->rtt < AX25_T1CLAMPLO)
2541da177e4SLinus Torvalds ax25->rtt = AX25_T1CLAMPLO;
2551da177e4SLinus Torvalds
2561da177e4SLinus Torvalds if (ax25->rtt > AX25_T1CLAMPHI)
2571da177e4SLinus Torvalds ax25->rtt = AX25_T1CLAMPHI;
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds
ax25_disconnect(ax25_cb * ax25,int reason)2601da177e4SLinus Torvalds void ax25_disconnect(ax25_cb *ax25, int reason)
2611da177e4SLinus Torvalds {
2621da177e4SLinus Torvalds ax25_clear_queues(ax25);
2631da177e4SLinus Torvalds
264fc6d01ffSDuoming Zhou if (reason == ENETUNREACH) {
265fc6d01ffSDuoming Zhou del_timer_sync(&ax25->timer);
266fc6d01ffSDuoming Zhou del_timer_sync(&ax25->t1timer);
267fc6d01ffSDuoming Zhou del_timer_sync(&ax25->t2timer);
268fc6d01ffSDuoming Zhou del_timer_sync(&ax25->t3timer);
269fc6d01ffSDuoming Zhou del_timer_sync(&ax25->idletimer);
270fc6d01ffSDuoming Zhou } else {
271*7d8a3a47SDuoming Zhou if (ax25->sk && !sock_flag(ax25->sk, SOCK_DESTROY))
272da278622SRichard Stearn ax25_stop_heartbeat(ax25);
2731da177e4SLinus Torvalds ax25_stop_t1timer(ax25);
2741da177e4SLinus Torvalds ax25_stop_t2timer(ax25);
2751da177e4SLinus Torvalds ax25_stop_t3timer(ax25);
2761da177e4SLinus Torvalds ax25_stop_idletimer(ax25);
277fc6d01ffSDuoming Zhou }
2781da177e4SLinus Torvalds
2791da177e4SLinus Torvalds ax25->state = AX25_STATE_0;
2801da177e4SLinus Torvalds
2811da177e4SLinus Torvalds ax25_link_failed(ax25, reason);
2821da177e4SLinus Torvalds
2831da177e4SLinus Torvalds if (ax25->sk != NULL) {
284215f7b08SJarek Poplawski local_bh_disable();
2851da177e4SLinus Torvalds bh_lock_sock(ax25->sk);
2861da177e4SLinus Torvalds ax25->sk->sk_state = TCP_CLOSE;
2871da177e4SLinus Torvalds ax25->sk->sk_err = reason;
2881da177e4SLinus Torvalds ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
2891da177e4SLinus Torvalds if (!sock_flag(ax25->sk, SOCK_DEAD)) {
2901da177e4SLinus Torvalds ax25->sk->sk_state_change(ax25->sk);
2911da177e4SLinus Torvalds sock_set_flag(ax25->sk, SOCK_DEAD);
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds bh_unlock_sock(ax25->sk);
294215f7b08SJarek Poplawski local_bh_enable();
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds }
297