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 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
#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/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/system.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
int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
		     unsigned short type, const void *daddr,
		     const void *saddr, unsigned 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 103 104 105 106

	return -AX25_HEADER_LEN;	/* Unfinished header */
}

int ax25_rebuild_header(struct sk_buff *skb)
{
	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 132
	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
		goto put;
L
Linus Torvalds 已提交
133 134 135
	}

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

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

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

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

	skb_pull(skb, AX25_KISS_HEADER_LEN);

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

		skb = ourskb;
	}

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

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

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

#else	/* INET */

220 221 222
int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
		     unsigned short type, const void *daddr,
		     const void *saddr, unsigned len)
L
Linus Torvalds 已提交
223 224 225 226 227 228 229 230 231 232 233
{
	return -AX25_HEADER_LEN;
}

int ax25_rebuild_header(struct sk_buff *skb)
{
	return 1;
}

#endif

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

239 240
EXPORT_SYMBOL(ax25_hard_header);
EXPORT_SYMBOL(ax25_rebuild_header);
241 242
EXPORT_SYMBOL(ax25_header_ops);