ax25_ip.c 5.1 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
int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
L
Linus Torvalds 已提交
50 51 52 53 54 55 56
{
	unsigned char *buff;

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

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

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

64 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
	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 已提交
94 95

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

	return -AX25_HEADER_LEN;	/* Unfinished header */
}

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

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

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

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

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

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

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

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

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

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

	skb_pull(skb, AX25_KISS_HEADER_LEN);

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

		skb = ourskb;
	}

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

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

213
	return 1;
L
Linus Torvalds 已提交
214 215 216 217
}

#else	/* INET */

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

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

#endif

230 231
EXPORT_SYMBOL(ax25_hard_header);
EXPORT_SYMBOL(ax25_rebuild_header);