linux/net/netrom/nr_subr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *
   4 * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   5 */
   6#include <linux/errno.h>
   7#include <linux/types.h>
   8#include <linux/socket.h>
   9#include <linux/in.h>
  10#include <linux/kernel.h>
  11#include <linux/timer.h>
  12#include <linux/string.h>
  13#include <linux/sockios.h>
  14#include <linux/net.h>
  15#include <linux/slab.h>
  16#include <net/ax25.h>
  17#include <linux/inet.h>
  18#include <linux/netdevice.h>
  19#include <linux/skbuff.h>
  20#include <net/sock.h>
  21#include <net/tcp_states.h>
  22#include <linux/uaccess.h>
  23#include <linux/fcntl.h>
  24#include <linux/mm.h>
  25#include <linux/interrupt.h>
  26#include <net/netrom.h>
  27
  28/*
  29 *      This routine purges all of the queues of frames.
  30 */
  31void nr_clear_queues(struct sock *sk)
  32{
  33        struct nr_sock *nr = nr_sk(sk);
  34
  35        skb_queue_purge(&sk->sk_write_queue);
  36        skb_queue_purge(&nr->ack_queue);
  37        skb_queue_purge(&nr->reseq_queue);
  38        skb_queue_purge(&nr->frag_queue);
  39}
  40
  41/*
  42 * This routine purges the input queue of those frames that have been
  43 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
  44 * SDL diagram.
  45 */
  46void nr_frames_acked(struct sock *sk, unsigned short nr)
  47{
  48        struct nr_sock *nrom = nr_sk(sk);
  49        struct sk_buff *skb;
  50
  51        /*
  52         * Remove all the ack-ed frames from the ack queue.
  53         */
  54        if (nrom->va != nr) {
  55                while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) {
  56                        skb = skb_dequeue(&nrom->ack_queue);
  57                        kfree_skb(skb);
  58                        nrom->va = (nrom->va + 1) % NR_MODULUS;
  59                }
  60        }
  61}
  62
  63/*
  64 * Requeue all the un-ack-ed frames on the output queue to be picked
  65 * up by nr_kick called from the timer. This arrangement handles the
  66 * possibility of an empty output queue.
  67 */
  68void nr_requeue_frames(struct sock *sk)
  69{
  70        struct sk_buff *skb, *skb_prev = NULL;
  71
  72        while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) {
  73                if (skb_prev == NULL)
  74                        skb_queue_head(&sk->sk_write_queue, skb);
  75                else
  76                        skb_append(skb_prev, skb, &sk->sk_write_queue);
  77                skb_prev = skb;
  78        }
  79}
  80
  81/*
  82 *      Validate that the value of nr is between va and vs. Return true or
  83 *      false for testing.
  84 */
  85int nr_validate_nr(struct sock *sk, unsigned short nr)
  86{
  87        struct nr_sock *nrom = nr_sk(sk);
  88        unsigned short vc = nrom->va;
  89
  90        while (vc != nrom->vs) {
  91                if (nr == vc) return 1;
  92                vc = (vc + 1) % NR_MODULUS;
  93        }
  94
  95        return nr == nrom->vs;
  96}
  97
  98/*
  99 *      Check that ns is within the receive window.
 100 */
 101int nr_in_rx_window(struct sock *sk, unsigned short ns)
 102{
 103        struct nr_sock *nr = nr_sk(sk);
 104        unsigned short vc = nr->vr;
 105        unsigned short vt = (nr->vl + nr->window) % NR_MODULUS;
 106
 107        while (vc != vt) {
 108                if (ns == vc) return 1;
 109                vc = (vc + 1) % NR_MODULUS;
 110        }
 111
 112        return 0;
 113}
 114
 115/*
 116 *  This routine is called when the HDLC layer internally generates a
 117 *  control frame.
 118 */
 119void nr_write_internal(struct sock *sk, int frametype)
 120{
 121        struct nr_sock *nr = nr_sk(sk);
 122        struct sk_buff *skb;
 123        unsigned char  *dptr;
 124        int len, timeout;
 125
 126        len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 127
 128        switch (frametype & 0x0F) {
 129        case NR_CONNREQ:
 130                len += 17;
 131                break;
 132        case NR_CONNACK:
 133                len += (nr->bpqext) ? 2 : 1;
 134                break;
 135        case NR_DISCREQ:
 136        case NR_DISCACK:
 137        case NR_INFOACK:
 138                break;
 139        default:
 140                printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
 141                return;
 142        }
 143
 144        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 145                return;
 146
 147        /*
 148         *      Space for AX.25 and NET/ROM network header
 149         */
 150        skb_reserve(skb, NR_NETWORK_LEN);
 151
 152        dptr = skb_put(skb, skb_tailroom(skb));
 153
 154        switch (frametype & 0x0F) {
 155        case NR_CONNREQ:
 156                timeout  = nr->t1 / HZ;
 157                *dptr++  = nr->my_index;
 158                *dptr++  = nr->my_id;
 159                *dptr++  = 0;
 160                *dptr++  = 0;
 161                *dptr++  = frametype;
 162                *dptr++  = nr->window;
 163                memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN);
 164                dptr[6] &= ~AX25_CBIT;
 165                dptr[6] &= ~AX25_EBIT;
 166                dptr[6] |= AX25_SSSID_SPARE;
 167                dptr    += AX25_ADDR_LEN;
 168                memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
 169                dptr[6] &= ~AX25_CBIT;
 170                dptr[6] &= ~AX25_EBIT;
 171                dptr[6] |= AX25_SSSID_SPARE;
 172                dptr    += AX25_ADDR_LEN;
 173                *dptr++  = timeout % 256;
 174                *dptr++  = timeout / 256;
 175                break;
 176
 177        case NR_CONNACK:
 178                *dptr++ = nr->your_index;
 179                *dptr++ = nr->your_id;
 180                *dptr++ = nr->my_index;
 181                *dptr++ = nr->my_id;
 182                *dptr++ = frametype;
 183                *dptr++ = nr->window;
 184                if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
 185                break;
 186
 187        case NR_DISCREQ:
 188        case NR_DISCACK:
 189                *dptr++ = nr->your_index;
 190                *dptr++ = nr->your_id;
 191                *dptr++ = 0;
 192                *dptr++ = 0;
 193                *dptr++ = frametype;
 194                break;
 195
 196        case NR_INFOACK:
 197                *dptr++ = nr->your_index;
 198                *dptr++ = nr->your_id;
 199                *dptr++ = 0;
 200                *dptr++ = nr->vr;
 201                *dptr++ = frametype;
 202                break;
 203        }
 204
 205        nr_transmit_buffer(sk, skb);
 206}
 207
 208/*
 209 * This routine is called to send an error reply.
 210 */
 211void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
 212{
 213        struct sk_buff *skbn;
 214        unsigned char *dptr;
 215        int len;
 216
 217        len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
 218
 219        if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
 220                return;
 221
 222        skb_reserve(skbn, 0);
 223
 224        dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 225
 226        skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN);
 227        dptr[6] &= ~AX25_CBIT;
 228        dptr[6] &= ~AX25_EBIT;
 229        dptr[6] |= AX25_SSSID_SPARE;
 230        dptr += AX25_ADDR_LEN;
 231
 232        skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN);
 233        dptr[6] &= ~AX25_CBIT;
 234        dptr[6] |= AX25_EBIT;
 235        dptr[6] |= AX25_SSSID_SPARE;
 236        dptr += AX25_ADDR_LEN;
 237
 238        *dptr++ = sysctl_netrom_network_ttl_initialiser;
 239
 240        if (mine) {
 241                *dptr++ = 0;
 242                *dptr++ = 0;
 243                *dptr++ = skb->data[15];
 244                *dptr++ = skb->data[16];
 245        } else {
 246                *dptr++ = skb->data[15];
 247                *dptr++ = skb->data[16];
 248                *dptr++ = 0;
 249                *dptr++ = 0;
 250        }
 251
 252        *dptr++ = cmdflags;
 253        *dptr++ = 0;
 254
 255        if (!nr_route_frame(skbn, NULL))
 256                kfree_skb(skbn);
 257}
 258
 259void nr_disconnect(struct sock *sk, int reason)
 260{
 261        nr_stop_t1timer(sk);
 262        nr_stop_t2timer(sk);
 263        nr_stop_t4timer(sk);
 264        nr_stop_idletimer(sk);
 265
 266        nr_clear_queues(sk);
 267
 268        nr_sk(sk)->state = NR_STATE_0;
 269
 270        sk->sk_state     = TCP_CLOSE;
 271        sk->sk_err       = reason;
 272        sk->sk_shutdown |= SEND_SHUTDOWN;
 273
 274        if (!sock_flag(sk, SOCK_DEAD)) {
 275                sk->sk_state_change(sk);
 276                sock_set_flag(sk, SOCK_DEAD);
 277        }
 278}
 279