nr_dev.c 4.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*
 * 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/sched.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 <asm/system.h>
#include <asm/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 = netdev_priv(dev);

	if (!netif_running(dev)) {
R
Ralf Baechle 已提交
49
		stats->rx_dropped++;
L
Linus Torvalds 已提交
50 51 52 53 54 55 56 57 58 59
		return 0;
	}

	stats->rx_packets++;
	stats->rx_bytes += skb->len;

	skb->protocol = htons(ETH_P_IP);

	/* Spoof incoming device */
	skb->dev      = dev;
R
Ralf Baechle 已提交
60
	skb->mac.raw  = skb->nh.raw;
L
Linus Torvalds 已提交
61 62 63
	skb->nh.raw   = skb->data;
	skb->pkt_type = PACKET_HOST;

64
	netif_rx(skb);
L
Linus Torvalds 已提交
65 66 67 68

	return 1;
}

69
#ifdef CONFIG_INET
L
Linus Torvalds 已提交
70 71 72 73 74

static int nr_rebuild_header(struct sk_buff *skb)
{
	unsigned char *bp = skb->data;

R
Ralf Baechle 已提交
75
	if (arp_find(bp + 7, skb))
L
Linus Torvalds 已提交
76 77 78 79 80 81 82 83 84 85 86
		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;

R
Ralf Baechle 已提交
87
	return 0;
L
Linus Torvalds 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
}

#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,
	void *daddr, void *saddr, unsigned 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;
}

131
static int __must_check nr_set_mac_address(struct net_device *dev, void *addr)
L
Linus Torvalds 已提交
132 133
{
	struct sockaddr *sa = addr;
134 135 136 137 138 139 140 141 142
	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;
L
Linus Torvalds 已提交
143 144

		ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
145
	}
L
Linus Torvalds 已提交
146 147 148 149 150 151 152 153

	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);

	return 0;
}

static int nr_open(struct net_device *dev)
{
154 155 156 157 158 159
	int err;

	err = ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
	if (err)
		return err;

L
Linus Torvalds 已提交
160
	netif_start_queue(dev);
161

L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169 170 171 172 173
	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 int nr_xmit(struct sk_buff *skb, struct net_device *dev)
{
174 175 176
	struct nr_private *nr = netdev_priv(dev);
	struct net_device_stats *stats = &nr->stats;
	unsigned int len = skb->len;
R
Ralf Baechle 已提交
177 178 179 180 181 182 183 184 185 186

	if (!nr_route_frame(skb, NULL)) {
		kfree_skb(skb);
		stats->tx_errors++;
		return 0;
	}

	stats->tx_packets++;
	stats->tx_bytes += len;

L
Linus Torvalds 已提交
187 188 189 190 191
	return 0;
}

static struct net_device_stats *nr_get_stats(struct net_device *dev)
{
192 193 194
	struct nr_private *nr = netdev_priv(dev);

	return &nr->stats;
L
Linus Torvalds 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
}

void nr_setup(struct net_device *dev)
{
	dev->mtu		= NR_MAX_PACKET_SIZE;
	dev->hard_start_xmit	= nr_xmit;
	dev->open		= nr_open;
	dev->stop		= nr_close;

	dev->hard_header	= nr_header;
	dev->hard_header_len	= NR_NETWORK_LEN + NR_TRANSPORT_LEN;
	dev->addr_len		= AX25_ADDR_LEN;
	dev->type		= ARPHRD_NETROM;
	dev->rebuild_header	= nr_rebuild_header;
	dev->set_mac_address    = nr_set_mac_address;

	/* New-style flags. */
R
Ralf Baechle 已提交
212
	dev->flags		= IFF_NOARP;
L
Linus Torvalds 已提交
213 214 215

	dev->get_stats 		= nr_get_stats;
}