ax25_ip.c 5.3 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#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>
#include <asm/uaccess.h>
#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/netfilter.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

49 50 51
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 已提交
52 53 54 55 56 57 58
{
	unsigned char *buff;

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

59 60 61
	/* 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 已提交
62 63 64 65

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

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 95
	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 已提交
96 97

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

	return -AX25_HEADER_LEN;	/* Unfinished header */
}

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

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

118 119
	if (arp_find(bp + 1, skb))
		return 1;
L
Linus Torvalds 已提交
120

121 122 123 124 125
	route = ax25_get_route(dst, NULL);
	if (route) {
		digipeat = route->digipeat;
		dev = route->dev;
		ip_mode = route->ip_mode;
126
	}
L
Linus Torvalds 已提交
127 128 129 130

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

131
	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
132
		kfree_skb(skb);
133
		goto put;
L
Linus Torvalds 已提交
134 135 136
	}

	if (bp[16] == AX25_P_IP) {
137
		if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
L
Linus Torvalds 已提交
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 173 174 175 176
			/*
			 *	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 */
177
			skb_reset_network_header(ourskb);
L
Linus Torvalds 已提交
178 179

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

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

195 196 197
	bp[14] &= ~AX25_CBIT;
	bp[14] |= AX25_EBIT;
	bp[14] |= AX25_SSSID_SPARE;
L
Linus Torvalds 已提交
198 199 200

	skb_pull(skb, AX25_KISS_HEADER_LEN);

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

		skb = ourskb;
	}

210
	ax25_queue_xmit(skb, dev);
L
Linus Torvalds 已提交
211 212

put:
213 214
	if (route)
		ax25_put_route(route);
L
Linus Torvalds 已提交
215

216
	return 1;
L
Linus Torvalds 已提交
217 218 219 220
}

#else	/* INET */

221 222 223
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 已提交
224 225 226 227
{
	return -AX25_HEADER_LEN;
}

228
static int ax25_rebuild_header(struct sk_buff *skb)
L
Linus Torvalds 已提交
229 230 231 232 233 234
{
	return 1;
}

#endif

235 236 237 238 239 240 241
const struct header_ops ax25_header_ops = {
	.create = ax25_hard_header,
	.rebuild = ax25_rebuild_header,
};

EXPORT_SYMBOL(ax25_header_ops);