mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
9
net/netrom/Makefile
Normal file
9
net/netrom/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for the Linux NET/ROM layer.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NETROM) += netrom.o
|
||||
|
||||
netrom-y := af_netrom.o nr_dev.o nr_in.o nr_loopback.o \
|
||||
nr_out.o nr_route.o nr_subr.o nr_timer.o
|
||||
netrom-$(CONFIG_SYSCTL) += sysctl_net_netrom.o
|
1512
net/netrom/af_netrom.c
Normal file
1512
net/netrom/af_netrom.c
Normal file
File diff suppressed because it is too large
Load diff
212
net/netrom/nr_dev.c
Normal file
212
net/netrom/nr_dev.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/if_ether.h> /* For the statistics structure. */
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
#include <net/arp.h>
|
||||
|
||||
#include <net/ax25.h>
|
||||
#include <net/netrom.h>
|
||||
|
||||
/*
|
||||
* Only allow IP over NET/ROM frames through if the netrom device is up.
|
||||
*/
|
||||
|
||||
int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
|
||||
if (!netif_running(dev)) {
|
||||
stats->rx_dropped++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += skb->len;
|
||||
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
|
||||
/* Spoof incoming device */
|
||||
skb->dev = dev;
|
||||
skb->mac_header = skb->network_header;
|
||||
skb_reset_network_header(skb);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
netif_rx(skb);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
|
||||
static int nr_rebuild_header(struct sk_buff *skb)
|
||||
{
|
||||
unsigned char *bp = skb->data;
|
||||
|
||||
if (arp_find(bp + 7, skb))
|
||||
return 1;
|
||||
|
||||
bp[6] &= ~AX25_CBIT;
|
||||
bp[6] &= ~AX25_EBIT;
|
||||
bp[6] |= AX25_SSSID_SPARE;
|
||||
bp += AX25_ADDR_LEN;
|
||||
|
||||
bp[6] &= ~AX25_CBIT;
|
||||
bp[6] |= AX25_EBIT;
|
||||
bp[6] |= AX25_SSSID_SPARE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int nr_rebuild_header(struct sk_buff *skb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int nr_header(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned short type,
|
||||
const void *daddr, const void *saddr, unsigned int len)
|
||||
{
|
||||
unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
|
||||
|
||||
memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
|
||||
buff[6] &= ~AX25_CBIT;
|
||||
buff[6] &= ~AX25_EBIT;
|
||||
buff[6] |= AX25_SSSID_SPARE;
|
||||
buff += AX25_ADDR_LEN;
|
||||
|
||||
if (daddr != NULL)
|
||||
memcpy(buff, daddr, dev->addr_len);
|
||||
buff[6] &= ~AX25_CBIT;
|
||||
buff[6] |= AX25_EBIT;
|
||||
buff[6] |= AX25_SSSID_SPARE;
|
||||
buff += AX25_ADDR_LEN;
|
||||
|
||||
*buff++ = sysctl_netrom_network_ttl_initialiser;
|
||||
|
||||
*buff++ = NR_PROTO_IP;
|
||||
*buff++ = NR_PROTO_IP;
|
||||
*buff++ = 0;
|
||||
*buff++ = 0;
|
||||
*buff++ = NR_PROTOEXT;
|
||||
|
||||
if (daddr != NULL)
|
||||
return 37;
|
||||
|
||||
return -37;
|
||||
}
|
||||
|
||||
static int __must_check nr_set_mac_address(struct net_device *dev, void *addr)
|
||||
{
|
||||
struct sockaddr *sa = addr;
|
||||
int err;
|
||||
|
||||
if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len))
|
||||
return 0;
|
||||
|
||||
if (dev->flags & IFF_UP) {
|
||||
err = ax25_listen_register((ax25_address *)sa->sa_data, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
|
||||
}
|
||||
|
||||
memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nr_open(struct net_device *dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nr_close(struct net_device *dev)
|
||||
{
|
||||
ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
|
||||
netif_stop_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static netdev_tx_t nr_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
unsigned int len = skb->len;
|
||||
|
||||
if (!nr_route_frame(skb, NULL)) {
|
||||
kfree_skb(skb);
|
||||
stats->tx_errors++;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += len;
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static const struct header_ops nr_header_ops = {
|
||||
.create = nr_header,
|
||||
.rebuild= nr_rebuild_header,
|
||||
};
|
||||
|
||||
static const struct net_device_ops nr_netdev_ops = {
|
||||
.ndo_open = nr_open,
|
||||
.ndo_stop = nr_close,
|
||||
.ndo_start_xmit = nr_xmit,
|
||||
.ndo_set_mac_address = nr_set_mac_address,
|
||||
};
|
||||
|
||||
void nr_setup(struct net_device *dev)
|
||||
{
|
||||
dev->mtu = NR_MAX_PACKET_SIZE;
|
||||
dev->netdev_ops = &nr_netdev_ops;
|
||||
dev->header_ops = &nr_header_ops;
|
||||
dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
|
||||
dev->addr_len = AX25_ADDR_LEN;
|
||||
dev->type = ARPHRD_NETROM;
|
||||
|
||||
/* New-style flags. */
|
||||
dev->flags = IFF_NOARP;
|
||||
}
|
305
net/netrom/nr_in.c
Normal file
305
net/netrom/nr_in.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
|
||||
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/ax25.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/netrom.h>
|
||||
|
||||
static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
|
||||
{
|
||||
struct sk_buff *skbo, *skbn = skb;
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
|
||||
|
||||
nr_start_idletimer(sk);
|
||||
|
||||
if (more) {
|
||||
nr->fraglen += skb->len;
|
||||
skb_queue_tail(&nr->frag_queue, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!more && nr->fraglen > 0) { /* End of fragment */
|
||||
nr->fraglen += skb->len;
|
||||
skb_queue_tail(&nr->frag_queue, skb);
|
||||
|
||||
if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL)
|
||||
return 1;
|
||||
|
||||
skb_reset_transport_header(skbn);
|
||||
|
||||
while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) {
|
||||
skb_copy_from_linear_data(skbo,
|
||||
skb_put(skbn, skbo->len),
|
||||
skbo->len);
|
||||
kfree_skb(skbo);
|
||||
}
|
||||
|
||||
nr->fraglen = 0;
|
||||
}
|
||||
|
||||
return sock_queue_rcv_skb(sk, skbn);
|
||||
}
|
||||
|
||||
/*
|
||||
* State machine for state 1, Awaiting Connection State.
|
||||
* The handling of the timer(s) is in file nr_timer.c.
|
||||
* Handling of state 0 and connection release is in netrom.c.
|
||||
*/
|
||||
static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
|
||||
int frametype)
|
||||
{
|
||||
switch (frametype) {
|
||||
case NR_CONNACK: {
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
nr_stop_t1timer(sk);
|
||||
nr_start_idletimer(sk);
|
||||
nr->your_index = skb->data[17];
|
||||
nr->your_id = skb->data[18];
|
||||
nr->vs = 0;
|
||||
nr->va = 0;
|
||||
nr->vr = 0;
|
||||
nr->vl = 0;
|
||||
nr->state = NR_STATE_3;
|
||||
nr->n2count = 0;
|
||||
nr->window = skb->data[20];
|
||||
sk->sk_state = TCP_ESTABLISHED;
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_state_change(sk);
|
||||
break;
|
||||
}
|
||||
|
||||
case NR_CONNACK | NR_CHOKE_FLAG:
|
||||
nr_disconnect(sk, ECONNREFUSED);
|
||||
break;
|
||||
|
||||
case NR_RESET:
|
||||
if (sysctl_netrom_reset_circuit)
|
||||
nr_disconnect(sk, ECONNRESET);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* State machine for state 2, Awaiting Release State.
|
||||
* The handling of the timer(s) is in file nr_timer.c
|
||||
* Handling of state 0 and connection release is in netrom.c.
|
||||
*/
|
||||
static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
|
||||
int frametype)
|
||||
{
|
||||
switch (frametype) {
|
||||
case NR_CONNACK | NR_CHOKE_FLAG:
|
||||
nr_disconnect(sk, ECONNRESET);
|
||||
break;
|
||||
|
||||
case NR_DISCREQ:
|
||||
nr_write_internal(sk, NR_DISCACK);
|
||||
|
||||
case NR_DISCACK:
|
||||
nr_disconnect(sk, 0);
|
||||
break;
|
||||
|
||||
case NR_RESET:
|
||||
if (sysctl_netrom_reset_circuit)
|
||||
nr_disconnect(sk, ECONNRESET);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* State machine for state 3, Connected State.
|
||||
* The handling of the timer(s) is in file nr_timer.c
|
||||
* Handling of state 0 and connection release is in netrom.c.
|
||||
*/
|
||||
static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
|
||||
{
|
||||
struct nr_sock *nrom = nr_sk(sk);
|
||||
struct sk_buff_head temp_queue;
|
||||
struct sk_buff *skbn;
|
||||
unsigned short save_vr;
|
||||
unsigned short nr, ns;
|
||||
int queued = 0;
|
||||
|
||||
nr = skb->data[18];
|
||||
ns = skb->data[17];
|
||||
|
||||
switch (frametype) {
|
||||
case NR_CONNREQ:
|
||||
nr_write_internal(sk, NR_CONNACK);
|
||||
break;
|
||||
|
||||
case NR_DISCREQ:
|
||||
nr_write_internal(sk, NR_DISCACK);
|
||||
nr_disconnect(sk, 0);
|
||||
break;
|
||||
|
||||
case NR_CONNACK | NR_CHOKE_FLAG:
|
||||
case NR_DISCACK:
|
||||
nr_disconnect(sk, ECONNRESET);
|
||||
break;
|
||||
|
||||
case NR_INFOACK:
|
||||
case NR_INFOACK | NR_CHOKE_FLAG:
|
||||
case NR_INFOACK | NR_NAK_FLAG:
|
||||
case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
|
||||
if (frametype & NR_CHOKE_FLAG) {
|
||||
nrom->condition |= NR_COND_PEER_RX_BUSY;
|
||||
nr_start_t4timer(sk);
|
||||
} else {
|
||||
nrom->condition &= ~NR_COND_PEER_RX_BUSY;
|
||||
nr_stop_t4timer(sk);
|
||||
}
|
||||
if (!nr_validate_nr(sk, nr)) {
|
||||
break;
|
||||
}
|
||||
if (frametype & NR_NAK_FLAG) {
|
||||
nr_frames_acked(sk, nr);
|
||||
nr_send_nak_frame(sk);
|
||||
} else {
|
||||
if (nrom->condition & NR_COND_PEER_RX_BUSY) {
|
||||
nr_frames_acked(sk, nr);
|
||||
} else {
|
||||
nr_check_iframes_acked(sk, nr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_INFO:
|
||||
case NR_INFO | NR_NAK_FLAG:
|
||||
case NR_INFO | NR_CHOKE_FLAG:
|
||||
case NR_INFO | NR_MORE_FLAG:
|
||||
case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
|
||||
case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
|
||||
case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
|
||||
case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
|
||||
if (frametype & NR_CHOKE_FLAG) {
|
||||
nrom->condition |= NR_COND_PEER_RX_BUSY;
|
||||
nr_start_t4timer(sk);
|
||||
} else {
|
||||
nrom->condition &= ~NR_COND_PEER_RX_BUSY;
|
||||
nr_stop_t4timer(sk);
|
||||
}
|
||||
if (nr_validate_nr(sk, nr)) {
|
||||
if (frametype & NR_NAK_FLAG) {
|
||||
nr_frames_acked(sk, nr);
|
||||
nr_send_nak_frame(sk);
|
||||
} else {
|
||||
if (nrom->condition & NR_COND_PEER_RX_BUSY) {
|
||||
nr_frames_acked(sk, nr);
|
||||
} else {
|
||||
nr_check_iframes_acked(sk, nr);
|
||||
}
|
||||
}
|
||||
}
|
||||
queued = 1;
|
||||
skb_queue_head(&nrom->reseq_queue, skb);
|
||||
if (nrom->condition & NR_COND_OWN_RX_BUSY)
|
||||
break;
|
||||
skb_queue_head_init(&temp_queue);
|
||||
do {
|
||||
save_vr = nrom->vr;
|
||||
while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
|
||||
ns = skbn->data[17];
|
||||
if (ns == nrom->vr) {
|
||||
if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
|
||||
nrom->vr = (nrom->vr + 1) % NR_MODULUS;
|
||||
} else {
|
||||
nrom->condition |= NR_COND_OWN_RX_BUSY;
|
||||
skb_queue_tail(&temp_queue, skbn);
|
||||
}
|
||||
} else if (nr_in_rx_window(sk, ns)) {
|
||||
skb_queue_tail(&temp_queue, skbn);
|
||||
} else {
|
||||
kfree_skb(skbn);
|
||||
}
|
||||
}
|
||||
while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
|
||||
skb_queue_tail(&nrom->reseq_queue, skbn);
|
||||
}
|
||||
} while (save_vr != nrom->vr);
|
||||
/*
|
||||
* Window is full, ack it immediately.
|
||||
*/
|
||||
if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
|
||||
nr_enquiry_response(sk);
|
||||
} else {
|
||||
if (!(nrom->condition & NR_COND_ACK_PENDING)) {
|
||||
nrom->condition |= NR_COND_ACK_PENDING;
|
||||
nr_start_t2timer(sk);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_RESET:
|
||||
if (sysctl_netrom_reset_circuit)
|
||||
nr_disconnect(sk, ECONNRESET);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return queued;
|
||||
}
|
||||
|
||||
/* Higher level upcall for a LAPB frame - called with sk locked */
|
||||
int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
int queued = 0, frametype;
|
||||
|
||||
if (nr->state == NR_STATE_0)
|
||||
return 0;
|
||||
|
||||
frametype = skb->data[19];
|
||||
|
||||
switch (nr->state) {
|
||||
case NR_STATE_1:
|
||||
queued = nr_state1_machine(sk, skb, frametype);
|
||||
break;
|
||||
case NR_STATE_2:
|
||||
queued = nr_state2_machine(sk, skb, frametype);
|
||||
break;
|
||||
case NR_STATE_3:
|
||||
queued = nr_state3_machine(sk, skb, frametype);
|
||||
break;
|
||||
}
|
||||
|
||||
nr_kick(sk);
|
||||
|
||||
return queued;
|
||||
}
|
77
net/netrom/nr_loopback.c
Normal file
77
net/netrom/nr_loopback.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/ax25.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netrom.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
static void nr_loopback_timer(unsigned long);
|
||||
|
||||
static struct sk_buff_head loopback_queue;
|
||||
static DEFINE_TIMER(loopback_timer, nr_loopback_timer, 0, 0);
|
||||
|
||||
void __init nr_loopback_init(void)
|
||||
{
|
||||
skb_queue_head_init(&loopback_queue);
|
||||
}
|
||||
|
||||
static inline int nr_loopback_running(void)
|
||||
{
|
||||
return timer_pending(&loopback_timer);
|
||||
}
|
||||
|
||||
int nr_loopback_queue(struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *skbn;
|
||||
|
||||
if ((skbn = alloc_skb(skb->len, GFP_ATOMIC)) != NULL) {
|
||||
skb_copy_from_linear_data(skb, skb_put(skbn, skb->len), skb->len);
|
||||
skb_reset_transport_header(skbn);
|
||||
|
||||
skb_queue_tail(&loopback_queue, skbn);
|
||||
|
||||
if (!nr_loopback_running())
|
||||
mod_timer(&loopback_timer, jiffies + 10);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void nr_loopback_timer(unsigned long param)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
ax25_address *nr_dest;
|
||||
struct net_device *dev;
|
||||
|
||||
if ((skb = skb_dequeue(&loopback_queue)) != NULL) {
|
||||
nr_dest = (ax25_address *)(skb->data + 7);
|
||||
|
||||
dev = nr_dev_get(nr_dest);
|
||||
|
||||
if (dev == NULL || nr_rx_frame(skb, dev) == 0)
|
||||
kfree_skb(skb);
|
||||
|
||||
if (dev != NULL)
|
||||
dev_put(dev);
|
||||
|
||||
if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running())
|
||||
mod_timer(&loopback_timer, jiffies + 10);
|
||||
}
|
||||
}
|
||||
|
||||
void __exit nr_loopback_clear(void)
|
||||
{
|
||||
del_timer_sync(&loopback_timer);
|
||||
skb_queue_purge(&loopback_queue);
|
||||
}
|
273
net/netrom/nr_out.c
Normal file
273
net/netrom/nr_out.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
|
||||
* Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/ax25.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/netrom.h>
|
||||
|
||||
/*
|
||||
* This is where all NET/ROM frames pass, except for IP-over-NET/ROM which
|
||||
* cannot be fragmented in this manner.
|
||||
*/
|
||||
void nr_output(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *skbn;
|
||||
unsigned char transport[NR_TRANSPORT_LEN];
|
||||
int err, frontlen, len;
|
||||
|
||||
if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) {
|
||||
/* Save a copy of the Transport Header */
|
||||
skb_copy_from_linear_data(skb, transport, NR_TRANSPORT_LEN);
|
||||
skb_pull(skb, NR_TRANSPORT_LEN);
|
||||
|
||||
frontlen = skb_headroom(skb);
|
||||
|
||||
while (skb->len > 0) {
|
||||
if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL)
|
||||
return;
|
||||
|
||||
skb_reserve(skbn, frontlen);
|
||||
|
||||
len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE;
|
||||
|
||||
/* Copy the user data */
|
||||
skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
|
||||
skb_pull(skb, len);
|
||||
|
||||
/* Duplicate the Transport Header */
|
||||
skb_push(skbn, NR_TRANSPORT_LEN);
|
||||
skb_copy_to_linear_data(skbn, transport,
|
||||
NR_TRANSPORT_LEN);
|
||||
if (skb->len > 0)
|
||||
skbn->data[4] |= NR_MORE_FLAG;
|
||||
|
||||
skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
} else {
|
||||
skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */
|
||||
}
|
||||
|
||||
nr_kick(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure is passed a buffer descriptor for an iframe. It builds
|
||||
* the rest of the control part of the frame and then writes it out.
|
||||
*/
|
||||
static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
if (skb == NULL)
|
||||
return;
|
||||
|
||||
skb->data[2] = nr->vs;
|
||||
skb->data[3] = nr->vr;
|
||||
|
||||
if (nr->condition & NR_COND_OWN_RX_BUSY)
|
||||
skb->data[4] |= NR_CHOKE_FLAG;
|
||||
|
||||
nr_start_idletimer(sk);
|
||||
|
||||
nr_transmit_buffer(sk, skb);
|
||||
}
|
||||
|
||||
void nr_send_nak_frame(struct sock *sk)
|
||||
{
|
||||
struct sk_buff *skb, *skbn;
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
if ((skb = skb_peek(&nr->ack_queue)) == NULL)
|
||||
return;
|
||||
|
||||
if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL)
|
||||
return;
|
||||
|
||||
skbn->data[2] = nr->va;
|
||||
skbn->data[3] = nr->vr;
|
||||
|
||||
if (nr->condition & NR_COND_OWN_RX_BUSY)
|
||||
skbn->data[4] |= NR_CHOKE_FLAG;
|
||||
|
||||
nr_transmit_buffer(sk, skbn);
|
||||
|
||||
nr->condition &= ~NR_COND_ACK_PENDING;
|
||||
nr->vl = nr->vr;
|
||||
|
||||
nr_stop_t1timer(sk);
|
||||
}
|
||||
|
||||
void nr_kick(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
struct sk_buff *skb, *skbn;
|
||||
unsigned short start, end;
|
||||
|
||||
if (nr->state != NR_STATE_3)
|
||||
return;
|
||||
|
||||
if (nr->condition & NR_COND_PEER_RX_BUSY)
|
||||
return;
|
||||
|
||||
if (!skb_peek(&sk->sk_write_queue))
|
||||
return;
|
||||
|
||||
start = (skb_peek(&nr->ack_queue) == NULL) ? nr->va : nr->vs;
|
||||
end = (nr->va + nr->window) % NR_MODULUS;
|
||||
|
||||
if (start == end)
|
||||
return;
|
||||
|
||||
nr->vs = start;
|
||||
|
||||
/*
|
||||
* Transmit data until either we're out of data to send or
|
||||
* the window is full.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dequeue the frame and copy it.
|
||||
*/
|
||||
skb = skb_dequeue(&sk->sk_write_queue);
|
||||
|
||||
do {
|
||||
if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
|
||||
skb_queue_head(&sk->sk_write_queue, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
skb_set_owner_w(skbn, sk);
|
||||
|
||||
/*
|
||||
* Transmit the frame copy.
|
||||
*/
|
||||
nr_send_iframe(sk, skbn);
|
||||
|
||||
nr->vs = (nr->vs + 1) % NR_MODULUS;
|
||||
|
||||
/*
|
||||
* Requeue the original data frame.
|
||||
*/
|
||||
skb_queue_tail(&nr->ack_queue, skb);
|
||||
|
||||
} while (nr->vs != end &&
|
||||
(skb = skb_dequeue(&sk->sk_write_queue)) != NULL);
|
||||
|
||||
nr->vl = nr->vr;
|
||||
nr->condition &= ~NR_COND_ACK_PENDING;
|
||||
|
||||
if (!nr_t1timer_running(sk))
|
||||
nr_start_t1timer(sk);
|
||||
}
|
||||
|
||||
void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
unsigned char *dptr;
|
||||
|
||||
/*
|
||||
* Add the protocol byte and network header.
|
||||
*/
|
||||
dptr = skb_push(skb, NR_NETWORK_LEN);
|
||||
|
||||
memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
|
||||
dptr[6] &= ~AX25_CBIT;
|
||||
dptr[6] &= ~AX25_EBIT;
|
||||
dptr[6] |= AX25_SSSID_SPARE;
|
||||
dptr += AX25_ADDR_LEN;
|
||||
|
||||
memcpy(dptr, &nr->dest_addr, AX25_ADDR_LEN);
|
||||
dptr[6] &= ~AX25_CBIT;
|
||||
dptr[6] |= AX25_EBIT;
|
||||
dptr[6] |= AX25_SSSID_SPARE;
|
||||
dptr += AX25_ADDR_LEN;
|
||||
|
||||
*dptr++ = sysctl_netrom_network_ttl_initialiser;
|
||||
|
||||
if (!nr_route_frame(skb, NULL)) {
|
||||
kfree_skb(skb);
|
||||
nr_disconnect(sk, ENETUNREACH);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following routines are taken from page 170 of the 7th ARRL Computer
|
||||
* Networking Conference paper, as is the whole state machine.
|
||||
*/
|
||||
|
||||
void nr_establish_data_link(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
nr->condition = 0x00;
|
||||
nr->n2count = 0;
|
||||
|
||||
nr_write_internal(sk, NR_CONNREQ);
|
||||
|
||||
nr_stop_t2timer(sk);
|
||||
nr_stop_t4timer(sk);
|
||||
nr_stop_idletimer(sk);
|
||||
nr_start_t1timer(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Never send a NAK when we are CHOKEd.
|
||||
*/
|
||||
void nr_enquiry_response(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
int frametype = NR_INFOACK;
|
||||
|
||||
if (nr->condition & NR_COND_OWN_RX_BUSY) {
|
||||
frametype |= NR_CHOKE_FLAG;
|
||||
} else {
|
||||
if (skb_peek(&nr->reseq_queue) != NULL)
|
||||
frametype |= NR_NAK_FLAG;
|
||||
}
|
||||
|
||||
nr_write_internal(sk, frametype);
|
||||
|
||||
nr->vl = nr->vr;
|
||||
nr->condition &= ~NR_COND_ACK_PENDING;
|
||||
}
|
||||
|
||||
void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
|
||||
{
|
||||
struct nr_sock *nrom = nr_sk(sk);
|
||||
|
||||
if (nrom->vs == nr) {
|
||||
nr_frames_acked(sk, nr);
|
||||
nr_stop_t1timer(sk);
|
||||
nrom->n2count = 0;
|
||||
} else {
|
||||
if (nrom->va != nr) {
|
||||
nr_frames_acked(sk, nr);
|
||||
nr_start_t1timer(sk);
|
||||
}
|
||||
}
|
||||
}
|
1030
net/netrom/nr_route.c
Normal file
1030
net/netrom/nr_route.c
Normal file
File diff suppressed because it is too large
Load diff
281
net/netrom/nr_subr.c
Normal file
281
net/netrom/nr_subr.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/ax25.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/netrom.h>
|
||||
|
||||
/*
|
||||
* This routine purges all of the queues of frames.
|
||||
*/
|
||||
void nr_clear_queues(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
skb_queue_purge(&sk->sk_write_queue);
|
||||
skb_queue_purge(&nr->ack_queue);
|
||||
skb_queue_purge(&nr->reseq_queue);
|
||||
skb_queue_purge(&nr->frag_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine purges the input queue of those frames that have been
|
||||
* acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
|
||||
* SDL diagram.
|
||||
*/
|
||||
void nr_frames_acked(struct sock *sk, unsigned short nr)
|
||||
{
|
||||
struct nr_sock *nrom = nr_sk(sk);
|
||||
struct sk_buff *skb;
|
||||
|
||||
/*
|
||||
* Remove all the ack-ed frames from the ack queue.
|
||||
*/
|
||||
if (nrom->va != nr) {
|
||||
while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) {
|
||||
skb = skb_dequeue(&nrom->ack_queue);
|
||||
kfree_skb(skb);
|
||||
nrom->va = (nrom->va + 1) % NR_MODULUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Requeue all the un-ack-ed frames on the output queue to be picked
|
||||
* up by nr_kick called from the timer. This arrangement handles the
|
||||
* possibility of an empty output queue.
|
||||
*/
|
||||
void nr_requeue_frames(struct sock *sk)
|
||||
{
|
||||
struct sk_buff *skb, *skb_prev = NULL;
|
||||
|
||||
while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) {
|
||||
if (skb_prev == NULL)
|
||||
skb_queue_head(&sk->sk_write_queue, skb);
|
||||
else
|
||||
skb_append(skb_prev, skb, &sk->sk_write_queue);
|
||||
skb_prev = skb;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the value of nr is between va and vs. Return true or
|
||||
* false for testing.
|
||||
*/
|
||||
int nr_validate_nr(struct sock *sk, unsigned short nr)
|
||||
{
|
||||
struct nr_sock *nrom = nr_sk(sk);
|
||||
unsigned short vc = nrom->va;
|
||||
|
||||
while (vc != nrom->vs) {
|
||||
if (nr == vc) return 1;
|
||||
vc = (vc + 1) % NR_MODULUS;
|
||||
}
|
||||
|
||||
return nr == nrom->vs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that ns is within the receive window.
|
||||
*/
|
||||
int nr_in_rx_window(struct sock *sk, unsigned short ns)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
unsigned short vc = nr->vr;
|
||||
unsigned short vt = (nr->vl + nr->window) % NR_MODULUS;
|
||||
|
||||
while (vc != vt) {
|
||||
if (ns == vc) return 1;
|
||||
vc = (vc + 1) % NR_MODULUS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called when the HDLC layer internally generates a
|
||||
* control frame.
|
||||
*/
|
||||
void nr_write_internal(struct sock *sk, int frametype)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
struct sk_buff *skb;
|
||||
unsigned char *dptr;
|
||||
int len, timeout;
|
||||
|
||||
len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
|
||||
|
||||
switch (frametype & 0x0F) {
|
||||
case NR_CONNREQ:
|
||||
len += 17;
|
||||
break;
|
||||
case NR_CONNACK:
|
||||
len += (nr->bpqext) ? 2 : 1;
|
||||
break;
|
||||
case NR_DISCREQ:
|
||||
case NR_DISCACK:
|
||||
case NR_INFOACK:
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Space for AX.25 and NET/ROM network header
|
||||
*/
|
||||
skb_reserve(skb, NR_NETWORK_LEN);
|
||||
|
||||
dptr = skb_put(skb, skb_tailroom(skb));
|
||||
|
||||
switch (frametype & 0x0F) {
|
||||
case NR_CONNREQ:
|
||||
timeout = nr->t1 / HZ;
|
||||
*dptr++ = nr->my_index;
|
||||
*dptr++ = nr->my_id;
|
||||
*dptr++ = 0;
|
||||
*dptr++ = 0;
|
||||
*dptr++ = frametype;
|
||||
*dptr++ = nr->window;
|
||||
memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN);
|
||||
dptr[6] &= ~AX25_CBIT;
|
||||
dptr[6] &= ~AX25_EBIT;
|
||||
dptr[6] |= AX25_SSSID_SPARE;
|
||||
dptr += AX25_ADDR_LEN;
|
||||
memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
|
||||
dptr[6] &= ~AX25_CBIT;
|
||||
dptr[6] &= ~AX25_EBIT;
|
||||
dptr[6] |= AX25_SSSID_SPARE;
|
||||
dptr += AX25_ADDR_LEN;
|
||||
*dptr++ = timeout % 256;
|
||||
*dptr++ = timeout / 256;
|
||||
break;
|
||||
|
||||
case NR_CONNACK:
|
||||
*dptr++ = nr->your_index;
|
||||
*dptr++ = nr->your_id;
|
||||
*dptr++ = nr->my_index;
|
||||
*dptr++ = nr->my_id;
|
||||
*dptr++ = frametype;
|
||||
*dptr++ = nr->window;
|
||||
if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
|
||||
break;
|
||||
|
||||
case NR_DISCREQ:
|
||||
case NR_DISCACK:
|
||||
*dptr++ = nr->your_index;
|
||||
*dptr++ = nr->your_id;
|
||||
*dptr++ = 0;
|
||||
*dptr++ = 0;
|
||||
*dptr++ = frametype;
|
||||
break;
|
||||
|
||||
case NR_INFOACK:
|
||||
*dptr++ = nr->your_index;
|
||||
*dptr++ = nr->your_id;
|
||||
*dptr++ = 0;
|
||||
*dptr++ = nr->vr;
|
||||
*dptr++ = frametype;
|
||||
break;
|
||||
}
|
||||
|
||||
nr_transmit_buffer(sk, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called to send an error reply.
|
||||
*/
|
||||
void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
|
||||
{
|
||||
struct sk_buff *skbn;
|
||||
unsigned char *dptr;
|
||||
int len;
|
||||
|
||||
len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
|
||||
|
||||
if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
|
||||
return;
|
||||
|
||||
skb_reserve(skbn, 0);
|
||||
|
||||
dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
|
||||
|
||||
skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN);
|
||||
dptr[6] &= ~AX25_CBIT;
|
||||
dptr[6] &= ~AX25_EBIT;
|
||||
dptr[6] |= AX25_SSSID_SPARE;
|
||||
dptr += AX25_ADDR_LEN;
|
||||
|
||||
skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN);
|
||||
dptr[6] &= ~AX25_CBIT;
|
||||
dptr[6] |= AX25_EBIT;
|
||||
dptr[6] |= AX25_SSSID_SPARE;
|
||||
dptr += AX25_ADDR_LEN;
|
||||
|
||||
*dptr++ = sysctl_netrom_network_ttl_initialiser;
|
||||
|
||||
if (mine) {
|
||||
*dptr++ = 0;
|
||||
*dptr++ = 0;
|
||||
*dptr++ = skb->data[15];
|
||||
*dptr++ = skb->data[16];
|
||||
} else {
|
||||
*dptr++ = skb->data[15];
|
||||
*dptr++ = skb->data[16];
|
||||
*dptr++ = 0;
|
||||
*dptr++ = 0;
|
||||
}
|
||||
|
||||
*dptr++ = cmdflags;
|
||||
*dptr++ = 0;
|
||||
|
||||
if (!nr_route_frame(skbn, NULL))
|
||||
kfree_skb(skbn);
|
||||
}
|
||||
|
||||
void nr_disconnect(struct sock *sk, int reason)
|
||||
{
|
||||
nr_stop_t1timer(sk);
|
||||
nr_stop_t2timer(sk);
|
||||
nr_stop_t4timer(sk);
|
||||
nr_stop_idletimer(sk);
|
||||
|
||||
nr_clear_queues(sk);
|
||||
|
||||
nr_sk(sk)->state = NR_STATE_0;
|
||||
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sk->sk_err = reason;
|
||||
sk->sk_shutdown |= SEND_SHUTDOWN;
|
||||
|
||||
if (!sock_flag(sk, SOCK_DEAD)) {
|
||||
sk->sk_state_change(sk);
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
}
|
||||
}
|
248
net/netrom/nr_timer.c
Normal file
248
net/netrom/nr_timer.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
|
||||
* Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <net/ax25.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/netrom.h>
|
||||
|
||||
static void nr_heartbeat_expiry(unsigned long);
|
||||
static void nr_t1timer_expiry(unsigned long);
|
||||
static void nr_t2timer_expiry(unsigned long);
|
||||
static void nr_t4timer_expiry(unsigned long);
|
||||
static void nr_idletimer_expiry(unsigned long);
|
||||
|
||||
void nr_init_timers(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
setup_timer(&nr->t1timer, nr_t1timer_expiry, (unsigned long)sk);
|
||||
setup_timer(&nr->t2timer, nr_t2timer_expiry, (unsigned long)sk);
|
||||
setup_timer(&nr->t4timer, nr_t4timer_expiry, (unsigned long)sk);
|
||||
setup_timer(&nr->idletimer, nr_idletimer_expiry, (unsigned long)sk);
|
||||
|
||||
/* initialized by sock_init_data */
|
||||
sk->sk_timer.data = (unsigned long)sk;
|
||||
sk->sk_timer.function = &nr_heartbeat_expiry;
|
||||
}
|
||||
|
||||
void nr_start_t1timer(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
mod_timer(&nr->t1timer, jiffies + nr->t1);
|
||||
}
|
||||
|
||||
void nr_start_t2timer(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
mod_timer(&nr->t2timer, jiffies + nr->t2);
|
||||
}
|
||||
|
||||
void nr_start_t4timer(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
mod_timer(&nr->t4timer, jiffies + nr->t4);
|
||||
}
|
||||
|
||||
void nr_start_idletimer(struct sock *sk)
|
||||
{
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
if (nr->idle > 0)
|
||||
mod_timer(&nr->idletimer, jiffies + nr->idle);
|
||||
}
|
||||
|
||||
void nr_start_heartbeat(struct sock *sk)
|
||||
{
|
||||
mod_timer(&sk->sk_timer, jiffies + 5 * HZ);
|
||||
}
|
||||
|
||||
void nr_stop_t1timer(struct sock *sk)
|
||||
{
|
||||
del_timer(&nr_sk(sk)->t1timer);
|
||||
}
|
||||
|
||||
void nr_stop_t2timer(struct sock *sk)
|
||||
{
|
||||
del_timer(&nr_sk(sk)->t2timer);
|
||||
}
|
||||
|
||||
void nr_stop_t4timer(struct sock *sk)
|
||||
{
|
||||
del_timer(&nr_sk(sk)->t4timer);
|
||||
}
|
||||
|
||||
void nr_stop_idletimer(struct sock *sk)
|
||||
{
|
||||
del_timer(&nr_sk(sk)->idletimer);
|
||||
}
|
||||
|
||||
void nr_stop_heartbeat(struct sock *sk)
|
||||
{
|
||||
del_timer(&sk->sk_timer);
|
||||
}
|
||||
|
||||
int nr_t1timer_running(struct sock *sk)
|
||||
{
|
||||
return timer_pending(&nr_sk(sk)->t1timer);
|
||||
}
|
||||
|
||||
static void nr_heartbeat_expiry(unsigned long param)
|
||||
{
|
||||
struct sock *sk = (struct sock *)param;
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
bh_lock_sock(sk);
|
||||
switch (nr->state) {
|
||||
case NR_STATE_0:
|
||||
/* Magic here: If we listen() and a new link dies before it
|
||||
is accepted() it isn't 'dead' so doesn't get removed. */
|
||||
if (sock_flag(sk, SOCK_DESTROY) ||
|
||||
(sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
|
||||
sock_hold(sk);
|
||||
bh_unlock_sock(sk);
|
||||
nr_destroy_socket(sk);
|
||||
sock_put(sk);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_STATE_3:
|
||||
/*
|
||||
* Check for the state of the receive buffer.
|
||||
*/
|
||||
if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) &&
|
||||
(nr->condition & NR_COND_OWN_RX_BUSY)) {
|
||||
nr->condition &= ~NR_COND_OWN_RX_BUSY;
|
||||
nr->condition &= ~NR_COND_ACK_PENDING;
|
||||
nr->vl = nr->vr;
|
||||
nr_write_internal(sk, NR_INFOACK);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
nr_start_heartbeat(sk);
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
|
||||
static void nr_t2timer_expiry(unsigned long param)
|
||||
{
|
||||
struct sock *sk = (struct sock *)param;
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
bh_lock_sock(sk);
|
||||
if (nr->condition & NR_COND_ACK_PENDING) {
|
||||
nr->condition &= ~NR_COND_ACK_PENDING;
|
||||
nr_enquiry_response(sk);
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
|
||||
static void nr_t4timer_expiry(unsigned long param)
|
||||
{
|
||||
struct sock *sk = (struct sock *)param;
|
||||
|
||||
bh_lock_sock(sk);
|
||||
nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY;
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
|
||||
static void nr_idletimer_expiry(unsigned long param)
|
||||
{
|
||||
struct sock *sk = (struct sock *)param;
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
bh_lock_sock(sk);
|
||||
|
||||
nr_clear_queues(sk);
|
||||
|
||||
nr->n2count = 0;
|
||||
nr_write_internal(sk, NR_DISCREQ);
|
||||
nr->state = NR_STATE_2;
|
||||
|
||||
nr_start_t1timer(sk);
|
||||
nr_stop_t2timer(sk);
|
||||
nr_stop_t4timer(sk);
|
||||
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sk->sk_err = 0;
|
||||
sk->sk_shutdown |= SEND_SHUTDOWN;
|
||||
|
||||
if (!sock_flag(sk, SOCK_DEAD)) {
|
||||
sk->sk_state_change(sk);
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
|
||||
static void nr_t1timer_expiry(unsigned long param)
|
||||
{
|
||||
struct sock *sk = (struct sock *)param;
|
||||
struct nr_sock *nr = nr_sk(sk);
|
||||
|
||||
bh_lock_sock(sk);
|
||||
switch (nr->state) {
|
||||
case NR_STATE_1:
|
||||
if (nr->n2count == nr->n2) {
|
||||
nr_disconnect(sk, ETIMEDOUT);
|
||||
bh_unlock_sock(sk);
|
||||
return;
|
||||
} else {
|
||||
nr->n2count++;
|
||||
nr_write_internal(sk, NR_CONNREQ);
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_STATE_2:
|
||||
if (nr->n2count == nr->n2) {
|
||||
nr_disconnect(sk, ETIMEDOUT);
|
||||
bh_unlock_sock(sk);
|
||||
return;
|
||||
} else {
|
||||
nr->n2count++;
|
||||
nr_write_internal(sk, NR_DISCREQ);
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_STATE_3:
|
||||
if (nr->n2count == nr->n2) {
|
||||
nr_disconnect(sk, ETIMEDOUT);
|
||||
bh_unlock_sock(sk);
|
||||
return;
|
||||
} else {
|
||||
nr->n2count++;
|
||||
nr_requeue_frames(sk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
nr_start_t1timer(sk);
|
||||
bh_unlock_sock(sk);
|
||||
}
|
157
net/netrom/sysctl_net_netrom.c
Normal file
157
net/netrom/sysctl_net_netrom.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
|
||||
*/
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/ax25.h>
|
||||
#include <net/netrom.h>
|
||||
|
||||
/*
|
||||
* Values taken from NET/ROM documentation.
|
||||
*/
|
||||
static int min_quality[] = {0}, max_quality[] = {255};
|
||||
static int min_obs[] = {0}, max_obs[] = {255};
|
||||
static int min_ttl[] = {0}, max_ttl[] = {255};
|
||||
static int min_t1[] = {5 * HZ};
|
||||
static int max_t1[] = {600 * HZ};
|
||||
static int min_n2[] = {2}, max_n2[] = {127};
|
||||
static int min_t2[] = {1 * HZ};
|
||||
static int max_t2[] = {60 * HZ};
|
||||
static int min_t4[] = {1 * HZ};
|
||||
static int max_t4[] = {1000 * HZ};
|
||||
static int min_window[] = {1}, max_window[] = {127};
|
||||
static int min_idle[] = {0 * HZ};
|
||||
static int max_idle[] = {65535 * HZ};
|
||||
static int min_route[] = {0}, max_route[] = {1};
|
||||
static int min_fails[] = {1}, max_fails[] = {10};
|
||||
static int min_reset[] = {0}, max_reset[] = {1};
|
||||
|
||||
static struct ctl_table_header *nr_table_header;
|
||||
|
||||
static struct ctl_table nr_table[] = {
|
||||
{
|
||||
.procname = "default_path_quality",
|
||||
.data = &sysctl_netrom_default_path_quality,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_quality,
|
||||
.extra2 = &max_quality
|
||||
},
|
||||
{
|
||||
.procname = "obsolescence_count_initialiser",
|
||||
.data = &sysctl_netrom_obsolescence_count_initialiser,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_obs,
|
||||
.extra2 = &max_obs
|
||||
},
|
||||
{
|
||||
.procname = "network_ttl_initialiser",
|
||||
.data = &sysctl_netrom_network_ttl_initialiser,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_ttl,
|
||||
.extra2 = &max_ttl
|
||||
},
|
||||
{
|
||||
.procname = "transport_timeout",
|
||||
.data = &sysctl_netrom_transport_timeout,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_t1,
|
||||
.extra2 = &max_t1
|
||||
},
|
||||
{
|
||||
.procname = "transport_maximum_tries",
|
||||
.data = &sysctl_netrom_transport_maximum_tries,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_n2,
|
||||
.extra2 = &max_n2
|
||||
},
|
||||
{
|
||||
.procname = "transport_acknowledge_delay",
|
||||
.data = &sysctl_netrom_transport_acknowledge_delay,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_t2,
|
||||
.extra2 = &max_t2
|
||||
},
|
||||
{
|
||||
.procname = "transport_busy_delay",
|
||||
.data = &sysctl_netrom_transport_busy_delay,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_t4,
|
||||
.extra2 = &max_t4
|
||||
},
|
||||
{
|
||||
.procname = "transport_requested_window_size",
|
||||
.data = &sysctl_netrom_transport_requested_window_size,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_window,
|
||||
.extra2 = &max_window
|
||||
},
|
||||
{
|
||||
.procname = "transport_no_activity_timeout",
|
||||
.data = &sysctl_netrom_transport_no_activity_timeout,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_idle,
|
||||
.extra2 = &max_idle
|
||||
},
|
||||
{
|
||||
.procname = "routing_control",
|
||||
.data = &sysctl_netrom_routing_control,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_route,
|
||||
.extra2 = &max_route
|
||||
},
|
||||
{
|
||||
.procname = "link_fails_count",
|
||||
.data = &sysctl_netrom_link_fails_count,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_fails,
|
||||
.extra2 = &max_fails
|
||||
},
|
||||
{
|
||||
.procname = "reset",
|
||||
.data = &sysctl_netrom_reset_circuit,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &min_reset,
|
||||
.extra2 = &max_reset
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
void __init nr_register_sysctl(void)
|
||||
{
|
||||
nr_table_header = register_net_sysctl(&init_net, "net/netrom", nr_table);
|
||||
}
|
||||
|
||||
void nr_unregister_sysctl(void)
|
||||
{
|
||||
unregister_net_sysctl_table(nr_table_header);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue