Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/ax25/ax25_ip.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
*
4
* Copyright (C) Jonathan Naylor G4KLX ([email protected])
5
*/
6
#include <linux/errno.h>
7
#include <linux/types.h>
8
#include <linux/socket.h>
9
#include <linux/in.h>
10
#include <linux/kernel.h>
11
#include <linux/module.h>
12
#include <linux/timer.h>
13
#include <linux/string.h>
14
#include <linux/sockios.h>
15
#include <linux/net.h>
16
#include <linux/slab.h>
17
#include <net/ax25.h>
18
#include <linux/inet.h>
19
#include <linux/netdevice.h>
20
#include <linux/if_arp.h>
21
#include <linux/skbuff.h>
22
#include <net/sock.h>
23
#include <linux/uaccess.h>
24
#include <linux/fcntl.h>
25
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
26
#include <linux/mm.h>
27
#include <linux/interrupt.h>
28
#include <linux/notifier.h>
29
#include <linux/proc_fs.h>
30
#include <linux/stat.h>
31
#include <linux/sysctl.h>
32
#include <net/ip.h>
33
#include <net/arp.h>
34
35
/*
36
* IP over AX.25 encapsulation.
37
*/
38
39
/*
40
* Shove an AX.25 UI header on an IP packet and handle ARP
41
*/
42
43
#ifdef CONFIG_INET
44
45
static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
46
unsigned short type, const void *daddr,
47
const void *saddr, unsigned int len)
48
{
49
unsigned char *buff;
50
51
/* they sometimes come back to us... */
52
if (type == ETH_P_AX25)
53
return 0;
54
55
/* header is an AX.25 UI frame from us to them */
56
buff = skb_push(skb, AX25_HEADER_LEN);
57
*buff++ = 0x00; /* KISS DATA */
58
59
if (daddr != NULL)
60
memcpy(buff, daddr, dev->addr_len); /* Address specified */
61
62
buff[6] &= ~AX25_CBIT;
63
buff[6] &= ~AX25_EBIT;
64
buff[6] |= AX25_SSSID_SPARE;
65
buff += AX25_ADDR_LEN;
66
67
if (saddr != NULL)
68
memcpy(buff, saddr, dev->addr_len);
69
else
70
memcpy(buff, dev->dev_addr, dev->addr_len);
71
72
buff[6] &= ~AX25_CBIT;
73
buff[6] |= AX25_EBIT;
74
buff[6] |= AX25_SSSID_SPARE;
75
buff += AX25_ADDR_LEN;
76
77
*buff++ = AX25_UI; /* UI */
78
79
/* Append a suitable AX.25 PID */
80
switch (type) {
81
case ETH_P_IP:
82
*buff++ = AX25_P_IP;
83
break;
84
case ETH_P_ARP:
85
*buff++ = AX25_P_ARP;
86
break;
87
default:
88
printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type);
89
*buff++ = 0;
90
break;
91
}
92
93
if (daddr != NULL)
94
return AX25_HEADER_LEN;
95
96
return -AX25_HEADER_LEN; /* Unfinished header */
97
}
98
99
netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
100
{
101
struct sk_buff *ourskb;
102
unsigned char *bp = skb->data;
103
ax25_route *route;
104
struct net_device *dev = NULL;
105
ax25_address *src, *dst;
106
ax25_digi *digipeat = NULL;
107
ax25_dev *ax25_dev;
108
ax25_cb *ax25;
109
char ip_mode = ' ';
110
111
dst = (ax25_address *)(bp + 1);
112
src = (ax25_address *)(bp + 8);
113
114
ax25_route_lock_use();
115
route = ax25_get_route(dst, NULL);
116
if (route) {
117
digipeat = route->digipeat;
118
dev = route->dev;
119
ip_mode = route->ip_mode;
120
}
121
122
if (dev == NULL)
123
dev = skb->dev;
124
125
rcu_read_lock();
126
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
127
kfree_skb(skb);
128
goto put;
129
}
130
131
if (bp[16] == AX25_P_IP) {
132
if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
133
/*
134
* We copy the buffer and release the original thereby
135
* keeping it straight
136
*
137
* Note: we report 1 back so the caller will
138
* not feed the frame direct to the physical device
139
* We don't want that to happen. (It won't be upset
140
* as we have pulled the frame from the queue by
141
* freeing it).
142
*
143
* NB: TCP modifies buffers that are still
144
* on a device queue, thus we use skb_copy()
145
* instead of using skb_clone() unless this
146
* gets fixed.
147
*/
148
149
ax25_address src_c;
150
ax25_address dst_c;
151
152
if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
153
kfree_skb(skb);
154
goto put;
155
}
156
157
if (skb->sk != NULL)
158
skb_set_owner_w(ourskb, skb->sk);
159
160
kfree_skb(skb);
161
/* dl9sau: bugfix
162
* after kfree_skb(), dst and src which were pointer
163
* to bp which is part of skb->data would not be valid
164
* anymore hope that after skb_pull(ourskb, ..) our
165
* dsc_c and src_c will not become invalid
166
*/
167
bp = ourskb->data;
168
dst_c = *(ax25_address *)(bp + 1);
169
src_c = *(ax25_address *)(bp + 8);
170
171
skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */
172
skb_reset_network_header(ourskb);
173
174
ax25=ax25_send_frame(
175
ourskb,
176
ax25_dev->values[AX25_VALUES_PACLEN],
177
&src_c,
178
&dst_c, digipeat, dev);
179
if (ax25) {
180
ax25_cb_put(ax25);
181
}
182
goto put;
183
}
184
}
185
186
bp[7] &= ~AX25_CBIT;
187
bp[7] &= ~AX25_EBIT;
188
bp[7] |= AX25_SSSID_SPARE;
189
190
bp[14] &= ~AX25_CBIT;
191
bp[14] |= AX25_EBIT;
192
bp[14] |= AX25_SSSID_SPARE;
193
194
skb_pull(skb, AX25_KISS_HEADER_LEN);
195
196
if (digipeat != NULL) {
197
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL)
198
goto put;
199
200
skb = ourskb;
201
}
202
203
ax25_queue_xmit(skb, dev);
204
205
put:
206
rcu_read_unlock();
207
ax25_route_lock_unuse();
208
return NETDEV_TX_OK;
209
}
210
211
#else /* INET */
212
213
static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
214
unsigned short type, const void *daddr,
215
const void *saddr, unsigned int len)
216
{
217
return -AX25_HEADER_LEN;
218
}
219
220
netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
221
{
222
kfree_skb(skb);
223
return NETDEV_TX_OK;
224
}
225
#endif
226
227
static bool ax25_validate_header(const char *header, unsigned int len)
228
{
229
ax25_digi digi;
230
231
if (!len)
232
return false;
233
234
if (header[0])
235
return true;
236
237
return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
238
NULL);
239
}
240
241
const struct header_ops ax25_header_ops = {
242
.create = ax25_hard_header,
243
.validate = ax25_validate_header,
244
};
245
246
EXPORT_SYMBOL(ax25_header_ops);
247
EXPORT_SYMBOL(ax25_ip_xmit);
248
249