ax25_ip.c 5.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * 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)
 */
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
14
#include <linux/module.h>
L
Linus Torvalds 已提交
15 16 17 18
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
19
#include <linux/slab.h>
L
Linus Torvalds 已提交
20 21 22 23 24 25
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
26
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#include <linux/fcntl.h>
#include <linux/termios.h>	/* For TIOCINQ/OUTQ */
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/sysctl.h>
#include <net/ip.h>
#include <net/arp.h>

/*
 *	IP over AX.25 encapsulation.
 */

/*
 *	Shove an AX.25 UI header on an IP packet and handle ARP
 */

#ifdef CONFIG_INET

48 49 50
static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
			    unsigned short type, const void *daddr,
			    const void *saddr, unsigned int len)
L
Linus Torvalds 已提交
51 52 53 54 55 56 57
{
	unsigned char *buff;

	/* they sometimes come back to us... */
	if (type == ETH_P_AX25)
		return 0;

58 59 60
	/* header is an AX.25 UI frame from us to them */
	buff = skb_push(skb, AX25_HEADER_LEN);
	*buff++ = 0x00;	/* KISS DATA */
L
Linus Torvalds 已提交
61 62 63 64

	if (daddr != NULL)
		memcpy(buff, daddr, dev->addr_len);	/* Address specified */

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
	buff[6] &= ~AX25_CBIT;
	buff[6] &= ~AX25_EBIT;
	buff[6] |= AX25_SSSID_SPARE;
	buff    += AX25_ADDR_LEN;

	if (saddr != NULL)
		memcpy(buff, saddr, dev->addr_len);
	else
		memcpy(buff, dev->dev_addr, dev->addr_len);

	buff[6] &= ~AX25_CBIT;
	buff[6] |= AX25_EBIT;
	buff[6] |= AX25_SSSID_SPARE;
	buff    += AX25_ADDR_LEN;

	*buff++  = AX25_UI;	/* UI */

	/* Append a suitable AX.25 PID */
	switch (type) {
	case ETH_P_IP:
		*buff++ = AX25_P_IP;
		break;
	case ETH_P_ARP:
		*buff++ = AX25_P_ARP;
		break;
	default:
		printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type);
		*buff++ = 0;
		break;
	}
L
Linus Torvalds 已提交
95 96

	if (daddr != NULL)
97
		return AX25_HEADER_LEN;
L
Linus Torvalds 已提交
98 99 100 101

	return -AX25_HEADER_LEN;	/* Unfinished header */
}

102
netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
L
Linus Torvalds 已提交
103 104 105
{
	struct sk_buff *ourskb;
	unsigned char *bp  = skb->data;
106 107
	ax25_route *route;
	struct net_device *dev = NULL;
L
Linus Torvalds 已提交
108
	ax25_address *src, *dst;
109
	ax25_digi *digipeat = NULL;
L
Linus Torvalds 已提交
110 111
	ax25_dev *ax25_dev;
	ax25_cb *ax25;
112
	char ip_mode = ' ';
L
Linus Torvalds 已提交
113 114 115 116

	dst = (ax25_address *)(bp + 1);
	src = (ax25_address *)(bp + 8);

117 118 119 120 121
	route = ax25_get_route(dst, NULL);
	if (route) {
		digipeat = route->digipeat;
		dev = route->dev;
		ip_mode = route->ip_mode;
122
	}
L
Linus Torvalds 已提交
123 124 125 126

	if (dev == NULL)
		dev = skb->dev;

127
	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
128
		kfree_skb(skb);
129
		goto put;
L
Linus Torvalds 已提交
130 131 132
	}

	if (bp[16] == AX25_P_IP) {
133
		if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
L
Linus Torvalds 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
			/*
			 *	We copy the buffer and release the original thereby
			 *	keeping it straight
			 *
			 *	Note: we report 1 back so the caller will
			 *	not feed the frame direct to the physical device
			 *	We don't want that to happen. (It won't be upset
			 *	as we have pulled the frame from the queue by
			 *	freeing it).
			 *
			 *	NB: TCP modifies buffers that are still
			 *	on a device queue, thus we use skb_copy()
			 *      instead of using skb_clone() unless this
			 *	gets fixed.
			 */

			ax25_address src_c;
			ax25_address dst_c;

			if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
				kfree_skb(skb);
				goto put;
			}

			if (skb->sk != NULL)
				skb_set_owner_w(ourskb, skb->sk);

			kfree_skb(skb);
			/* dl9sau: bugfix
			 * after kfree_skb(), dst and src which were pointer
			 * to bp which is part of skb->data would not be valid
			 * anymore hope that after skb_pull(ourskb, ..) our
			 * dsc_c and src_c will not become invalid
			 */
			bp  = ourskb->data;
			dst_c = *(ax25_address *)(bp + 1);
			src_c = *(ax25_address *)(bp + 8);

			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
173
			skb_reset_network_header(ourskb);
L
Linus Torvalds 已提交
174 175

			ax25=ax25_send_frame(
176 177
			    ourskb,
			    ax25_dev->values[AX25_VALUES_PACLEN],
L
Linus Torvalds 已提交
178
			    &src_c,
179
			    &dst_c, digipeat, dev);
L
Linus Torvalds 已提交
180 181 182 183 184 185 186
			if (ax25) {
				ax25_cb_put(ax25);
			}
			goto put;
		}
	}

187 188 189
	bp[7]  &= ~AX25_CBIT;
	bp[7]  &= ~AX25_EBIT;
	bp[7]  |= AX25_SSSID_SPARE;
L
Linus Torvalds 已提交
190

191 192 193
	bp[14] &= ~AX25_CBIT;
	bp[14] |= AX25_EBIT;
	bp[14] |= AX25_SSSID_SPARE;
L
Linus Torvalds 已提交
194 195 196

	skb_pull(skb, AX25_KISS_HEADER_LEN);

197
	if (digipeat != NULL) {
L
Linus Torvalds 已提交
198 199 200 201 202 203 204 205
		if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
			kfree_skb(skb);
			goto put;
		}

		skb = ourskb;
	}

206
	ax25_queue_xmit(skb, dev);
L
Linus Torvalds 已提交
207 208

put:
209 210
	if (route)
		ax25_put_route(route);
L
Linus Torvalds 已提交
211

212
	return NETDEV_TX_OK;
213 214
}

L
Linus Torvalds 已提交
215 216
#else	/* INET */

217 218 219
static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
			    unsigned short type, const void *daddr,
			    const void *saddr, unsigned int len)
L
Linus Torvalds 已提交
220 221 222 223
{
	return -AX25_HEADER_LEN;
}

224
netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
225
{
226 227
	kfree_skb(skb);
	return NETDEV_TX_OK;
228
}
L
Linus Torvalds 已提交
229 230
#endif

231 232 233 234 235 236 237 238 239 240 241 242 243 244
static bool ax25_validate_header(const char *header, unsigned int len)
{
	ax25_digi digi;

	if (!len)
		return false;

	if (header[0])
		return true;

	return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
			       NULL);
}

245 246
const struct header_ops ax25_header_ops = {
	.create = ax25_hard_header,
247
	.validate = ax25_validate_header,
248 249 250
};

EXPORT_SYMBOL(ax25_header_ops);
251
EXPORT_SYMBOL(ax25_ip_xmit);
252