11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h> 185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ax25.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h> 24c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/tcp_states.h> 25dc8e54165f1dc8ee946c953512a877676f8bbe3fFabian Frederick#include <linux/uaccess.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/netrom.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine purges all of the queues of frames. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid nr_clear_queues(struct sock *sk) 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nr_sock *nr = nr_sk(sk); 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_purge(&sk->sk_write_queue); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_purge(&nr->ack_queue); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_purge(&nr->reseq_queue); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_purge(&nr->frag_queue); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine purges the input queue of those frames that have been 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SDL diagram. 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid nr_frames_acked(struct sock *sk, unsigned short nr) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nr_sock *nrom = nr_sk(sk); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove all the ack-ed frames from the ack queue. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nrom->va != nr) { 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) { 595f8f59d6641a3726985593f3e52430daa90c7933YOSHIFUJI Hideaki skb = skb_dequeue(&nrom->ack_queue); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nrom->va = (nrom->va + 1) % NR_MODULUS; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Requeue all the un-ack-ed frames on the output queue to be picked 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * up by nr_kick called from the timer. This arrangement handles the 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * possibility of an empty output queue. 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid nr_requeue_frames(struct sock *sk) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, *skb_prev = NULL; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) { 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_prev == NULL) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_head(&sk->sk_write_queue, skb); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 798728b834b226ffcf2c94a58530090e292af2a7bfDavid S. Miller skb_append(skb_prev, skb, &sk->sk_write_queue); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_prev = skb; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Validate that the value of nr is between va and vs. Return true or 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * false for testing. 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint nr_validate_nr(struct sock *sk, unsigned short nr) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nr_sock *nrom = nr_sk(sk); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vc = nrom->va; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (vc != nrom->vs) { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr == vc) return 1; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc = (vc + 1) % NR_MODULUS; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return nr == nrom->vs; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check that ns is within the receive window. 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint nr_in_rx_window(struct sock *sk, unsigned short ns) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nr_sock *nr = nr_sk(sk); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vc = nr->vr; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vt = (nr->vl + nr->window) % NR_MODULUS; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (vc != vt) { 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ns == vc) return 1; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc = (vc + 1) % NR_MODULUS; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called when the HDLC layer internally generates a 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * control frame. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid nr_write_internal(struct sock *sk, int frametype) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nr_sock *nr = nr_sk(sk); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *dptr; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len, timeout; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (frametype & 0x0F) { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_CONNREQ: 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len += 17; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_CONNACK: 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len += (nr->bpqext) ? 2 : 1; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_DISCREQ: 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_DISCACK: 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_INFOACK: 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Space for AX.25 and NET/ROM network header 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, NR_NETWORK_LEN); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr = skb_put(skb, skb_tailroom(skb)); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (frametype & 0x0F) { 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_CONNREQ: 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = nr->t1 / HZ; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->my_index; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->my_id; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = frametype; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->window; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_CBIT; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_EBIT; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] |= AX25_SSSID_SPARE; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr += AX25_ADDR_LEN; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_CBIT; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_EBIT; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] |= AX25_SSSID_SPARE; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr += AX25_ADDR_LEN; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = timeout % 256; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = timeout / 256; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_CONNACK: 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->your_index; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->your_id; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->my_index; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->my_id; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = frametype; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->window; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_DISCREQ: 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_DISCACK: 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->your_index; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->your_id; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = frametype; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NR_INFOACK: 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->your_index; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->your_id; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = nr->vr; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = frametype; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_transmit_buffer(sk, skb); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 212e21ce8c7c013fb223a002c70bb0a547de6c26c12Ralf Baechle * This routine is called to send an error reply. 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 214e21ce8c7c013fb223a002c70bb0a547de6c26c12Ralf Baechlevoid __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skbn; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *dptr; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skbn, 0); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 229d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_CBIT; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_EBIT; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] |= AX25_SSSID_SPARE; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr += AX25_ADDR_LEN; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 235d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] &= ~AX25_CBIT; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] |= AX25_EBIT; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr[6] |= AX25_SSSID_SPARE; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dptr += AX25_ADDR_LEN; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = sysctl_netrom_network_ttl_initialiser; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mine) { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = skb->data[15]; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = skb->data[16]; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = skb->data[15]; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = skb->data[16]; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 255e21ce8c7c013fb223a002c70bb0a547de6c26c12Ralf Baechle *dptr++ = cmdflags; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dptr++ = 0; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nr_route_frame(skbn, NULL)) 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skbn); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid nr_disconnect(struct sock *sk, int reason) 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_stop_t1timer(sk); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_stop_t2timer(sk); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_stop_t4timer(sk); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_stop_idletimer(sk); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_clear_queues(sk); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_sk(sk)->state = NR_STATE_0; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state = TCP_CLOSE; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_err = reason; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_shutdown |= SEND_SHUTDOWN; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) { 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state_change(sk); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_set_flag(sk, SOCK_DEAD); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 282