1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds #include <linux/errno.h>
71da177e4SLinus Torvalds #include <linux/types.h>
81da177e4SLinus Torvalds #include <linux/socket.h>
91da177e4SLinus Torvalds #include <linux/in.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/timer.h>
121da177e4SLinus Torvalds #include <linux/string.h>
131da177e4SLinus Torvalds #include <linux/sockios.h>
141da177e4SLinus Torvalds #include <linux/net.h>
155a0e3ad6STejun Heo #include <linux/gfp.h>
161da177e4SLinus Torvalds #include <net/ax25.h>
171da177e4SLinus Torvalds #include <linux/inet.h>
181da177e4SLinus Torvalds #include <linux/netdevice.h>
191da177e4SLinus Torvalds #include <linux/skbuff.h>
201da177e4SLinus Torvalds #include <net/sock.h>
211da177e4SLinus Torvalds #include <linux/fcntl.h>
221da177e4SLinus Torvalds #include <linux/mm.h>
231da177e4SLinus Torvalds #include <linux/interrupt.h>
241da177e4SLinus Torvalds #include <net/rose.h>
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds /*
271da177e4SLinus Torvalds * This procedure is passed a buffer descriptor for an iframe. It builds
281da177e4SLinus Torvalds * the rest of the control part of the frame and then writes it out.
291da177e4SLinus Torvalds */
rose_send_iframe(struct sock * sk,struct sk_buff * skb)301da177e4SLinus Torvalds static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
311da177e4SLinus Torvalds {
321da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds if (skb == NULL)
351da177e4SLinus Torvalds return;
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds skb->data[2] |= (rose->vr << 5) & 0xE0;
381da177e4SLinus Torvalds skb->data[2] |= (rose->vs << 1) & 0x0E;
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds rose_start_idletimer(sk);
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds rose_transmit_link(skb, rose->neighbour);
431da177e4SLinus Torvalds }
441da177e4SLinus Torvalds
rose_kick(struct sock * sk)451da177e4SLinus Torvalds void rose_kick(struct sock *sk)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
481da177e4SLinus Torvalds struct sk_buff *skb, *skbn;
491da177e4SLinus Torvalds unsigned short start, end;
501da177e4SLinus Torvalds
511da177e4SLinus Torvalds if (rose->state != ROSE_STATE_3)
521da177e4SLinus Torvalds return;
531da177e4SLinus Torvalds
541da177e4SLinus Torvalds if (rose->condition & ROSE_COND_PEER_RX_BUSY)
551da177e4SLinus Torvalds return;
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds if (!skb_peek(&sk->sk_write_queue))
581da177e4SLinus Torvalds return;
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds start = (skb_peek(&rose->ack_queue) == NULL) ? rose->va : rose->vs;
611da177e4SLinus Torvalds end = (rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds if (start == end)
641da177e4SLinus Torvalds return;
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds rose->vs = start;
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds /*
691da177e4SLinus Torvalds * Transmit data until either we're out of data to send or
701da177e4SLinus Torvalds * the window is full.
711da177e4SLinus Torvalds */
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds skb = skb_dequeue(&sk->sk_write_queue);
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds do {
761da177e4SLinus Torvalds if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
771da177e4SLinus Torvalds skb_queue_head(&sk->sk_write_queue, skb);
781da177e4SLinus Torvalds break;
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds
811da177e4SLinus Torvalds skb_set_owner_w(skbn, sk);
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds /*
841da177e4SLinus Torvalds * Transmit the frame copy.
851da177e4SLinus Torvalds */
861da177e4SLinus Torvalds rose_send_iframe(sk, skbn);
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds rose->vs = (rose->vs + 1) % ROSE_MODULUS;
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds /*
911da177e4SLinus Torvalds * Requeue the original data frame.
921da177e4SLinus Torvalds */
931da177e4SLinus Torvalds skb_queue_tail(&rose->ack_queue, skb);
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds } while (rose->vs != end &&
961da177e4SLinus Torvalds (skb = skb_dequeue(&sk->sk_write_queue)) != NULL);
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds rose->vl = rose->vr;
991da177e4SLinus Torvalds rose->condition &= ~ROSE_COND_ACK_PENDING;
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds rose_stop_timer(sk);
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds
1041da177e4SLinus Torvalds /*
1051da177e4SLinus Torvalds * The following routines are taken from page 170 of the 7th ARRL Computer
1061da177e4SLinus Torvalds * Networking Conference paper, as is the whole state machine.
1071da177e4SLinus Torvalds */
1081da177e4SLinus Torvalds
rose_enquiry_response(struct sock * sk)1091da177e4SLinus Torvalds void rose_enquiry_response(struct sock *sk)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds struct rose_sock *rose = rose_sk(sk);
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds if (rose->condition & ROSE_COND_OWN_RX_BUSY)
1141da177e4SLinus Torvalds rose_write_internal(sk, ROSE_RNR);
1151da177e4SLinus Torvalds else
1161da177e4SLinus Torvalds rose_write_internal(sk, ROSE_RR);
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds rose->vl = rose->vr;
1191da177e4SLinus Torvalds rose->condition &= ~ROSE_COND_ACK_PENDING;
1201da177e4SLinus Torvalds
1211da177e4SLinus Torvalds rose_stop_timer(sk);
1221da177e4SLinus Torvalds }
123