summaryrefslogtreecommitdiffstats
path: root/ax25ipd/process.c
blob: 098efc804fef42f87c16f005e10f96f4e6f04c54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/* process.c     Handle processing and routing of AX25 frames
 *
 * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
 * This software may be freely used, distributed, or modified, providing
 * this header is not removed.
 *
 * This is the only module that knows about the internal structure of
 * AX25 frames.
 */

/*
 * Dual port additions by M.Durrant VE3PNX and D.J.Dionne Feb 4, 1995
 */

#include <stdio.h>
#include <string.h>
#include <syslog.h>

#include "ax25ipd.h"

/* if dual port the upper nibble will have a value of 1 (not 0) */
#define FROM_PORT2(p)   (((*(p+1))&0x10)!=0)
#define FOR_PORT2(p)    (addrmatch(p,mycallsign2) || addrmatch(p,myalias2))
/* ve3djf and ve3pnx addition above                             */
#define IS_LAST(p)      (((*(p+6))&0x01)!=0)
#define NOT_LAST(p)     (((*(p+6))&0x01)==0)
#define REPEATED(p)     (((*(p+6))&0x80)!=0)
#define NOTREPEATED(p)  (((*(p+6))&0x80)==0)
#define IS_ME(p)        (addrmatch(p,mycallsign) || addrmatch(p,myalias) || addrmatch(p,mycallsign2) || addrmatch(p,myalias2) )
#define NOT_ME(p)       (!(addrmatch(p,mycallsign) || addrmatch(p,myalias) || addrmatch(p,mycallsign2) || addrmatch(p,myalias2) ) )
#define ARE_DIGIS(f)    (((*(f+13))&0x01)==0)
#define NO_DIGIS(f)     (((*(f+13))&0x01)!=0)
#define SETREPEATED(p)  (*(p+6))|=0x80
#define SETLAST(p)      (*(p+6))|=0x01

static unsigned char bcbuf[256];	/* Must be larger than bc_text!!! */
static int bclen;			/* The size of bcbuf */

/*
 * Initialize the process variables
 */

void process_init(void)
{
	bclen = -1;		/* flag that we need to rebuild the bctext */
}

/*
 * handle a frame given us by the kiss routines.  The buf variable is
 * a pointer to an AX25 frame.  Note that the AX25 frame from kiss does
 * not include the CRC bytes.  These are computed by this routine, and
 * it is expected that the buffer we have has room for the CRC bytes.
 * We will either dump this frame, or send it via the IP interface.
 *
 * If we are in digi mode, we validate in several ways:
 *   a) we must be the next digi in line to pick up the packet
 *   b) the next site to get the packet (the next listed digi, or
 *      the destination if we are the last digi) must be known to
 *      us via the route table.
 * If we pass validation, we then set the digipeated bit for our entry
 * in the packet, compute the CRC, and send the packet to the IP
 * interface.
 *
 * If we are in tnc mode, we have less work to do.
 *   a) the next site to get the packet (the next listed digi, or
 *      the destination) must be known to us via the route table.
 * If we pass validation, we compute the CRC, and send the packet to
 * the IP interface.
 */

void from_kiss(unsigned char *buf, int l)
{
	unsigned char *a, *ipaddr;

	if (l < 15) {
		LOGL2("from_kiss: dumped - length wrong!\n");
		stats.kiss_tooshort++;
		return;
	}

	if (loglevel > 2)
		dump_ax25frame("from_kiss: ", buf, l);

	if (digi) {		/* if we are in digi mode */
		a = next_addr(buf);
		if (NOT_ME(a)) {
			stats.kiss_not_for_me++;
			LOGL4("from_kiss: (digi) dumped - not for me\n");
			return;
		}
		if (a == buf) {	/* must be a digi */
			stats.kiss_i_am_dest++;
			LOGL2
			    ("from_kiss: (digi) dumped - I am destination!\n");
			return;
		}
		SETREPEATED(a);
		a = next_addr(buf);	/* find who gets it after us */
	} else {		/* must be tnc mode */
		a = next_addr(buf);
#ifdef TNC_FILTER
		if (IS_ME(a)) {
			LOGL2
			    ("from_kiss: (tnc) dumped - addressed to self!\n");
			return;
		}
#endif
	}			/* end of tnc mode */

	/* Lookup the IP address for this route */
	ipaddr = call_to_ip(a);

	if (ipaddr == NULL) {
		if (is_call_bcast(a)) {
			/* Warning - assuming buffer has room for 2 bytes */
			add_crc(buf, l);
			l += 2;
			send_broadcast(buf, l);
		} else {
			stats.kiss_no_ip_addr++;
			LOGL2
			    ("from_kiss: dumped - cannot figure out where to send this!\n");
		}
		return;
	} else {
		/* Warning - assuming buffer has room for 2 bytes */
		add_crc(buf, l);
		l += 2;
		send_ip(buf, l, ipaddr);
		if (is_call_bcast(a)) {
			send_broadcast(buf, l);
		}
	}
}

/*
 * handle a frame given us by the IP routines.  The buf variable is
 * a pointer to an AX25 frame.
 * Note that the frame includes the CRC bytes, which we dump ASAP.
 * We will either dump this frame, or send it via the KISS interface.
 *
 * If we are in digi mode, we only validate that:
 *   a) we must be the next digi in line to pick up the packet
 * If we pass validation, we then set the digipeated bit for our entry
 * in the packet, and send the packet to the KISS send routine.
 *
 * If we are in tnc mode, we validate pretty well nothing, just like a
 * real TNC...  #define FILTER_TNC will change this.
 * We simply send the packet to the KISS send routine.
 */

void from_ip(unsigned char *buf, int l)
{
	int port = 0;
	unsigned char *a;

	if (!ok_crc(buf, l)) {
		stats.ip_failed_crc++;
		LOGL2("from_ip: dumped - CRC incorrect!\n");
		return;
	}
	l = l - 2;		/* dump the blasted CRC */

	if (l < 15) {
		stats.ip_tooshort++;
		LOGL2("from_ip: dumped - length wrong!\n");
		return;
	}

	if (loglevel > 2)
		dump_ax25frame("from_ip: ", buf, l);

	if (digi) {		/* if we are in digi mode */
		a = next_addr(buf);
		if (NOT_ME(a)) {
			stats.ip_not_for_me++;
			LOGL2("from_ip: (digi) dumped - not for me!\n");
			return;
		}
		if (a == buf) {	/* must be a digi */
			stats.ip_i_am_dest++;
			LOGL2
			    ("from_ip: (digi) dumped - I am destination!\n");
			return;
		}
		if (dual_port == 1 && FOR_PORT2(a)) {
			port = 0x10;
		}
		SETREPEATED(a);
	} else {		/* must be tnc mode */
		a = next_addr(buf);
#ifdef TNC_FILTER
		if (NOT_ME(a)) {
			LOGL2
			    ("from_ip: (tnc) dumped - I am not destination!\n");
			return;
		}
#endif
	}			/* end of tnc mode */
	if (!ttyfd_bpq)
		send_kiss(port, buf, l);
	else {
		send_bpq(buf, l);
	}
}

/*
 * Send an ID frame out the KISS port.
 */

void do_beacon(void)
{
	int i;
	unsigned char *p;

	if (bclen == 0)
		return;		/* nothing to do! */

	if (bclen < 0) {	/* build the id string */
		p = bcbuf;
		*p++ = ('I' << 1);
		*p++ = ('D' << 1);
		*p++ = (' ' << 1);
		*p++ = (' ' << 1);
		*p++ = (' ' << 1);
		*p++ = (' ' << 1);
		*p++ = '\0' | 0x60;	/* SSID, set reserved bits */

		for (i = 0; i < 6; i++)
			*p++ = mycallsign[i];
		*p++ = mycallsign[6] | 0x60;	/* ensure reserved bits are set */
		SETLAST(bcbuf + 7);	/* Set the E bit -- last address */

		*p++ = 0x03;	/* Control field -- UI frame */

		*p++ = 0xf0;	/* Protocol ID -- 0xf0 is no protocol */

		strcpy((char *)p, bc_text);	/* add the text field */

		bclen = 16 + strlen(bc_text);	/* adjust the length nicely */
	}

	if (loglevel > 2)
		dump_ax25frame("do_beacon: ", bcbuf, bclen);
	stats.kiss_beacon_outs++;
	if (!ttyfd_bpq)
		send_kiss(0, bcbuf, bclen);
	else {
		send_bpq(bcbuf, bclen);
	}
}

/*
 * return true if the addresses supplied match
 * modified for wildcarding by vk5xxx
 */
int addrmatch(unsigned char *a, unsigned char *b)
{
	if ((*a == '\0') || (*b == '\0'))
		return 0;

	if ((*a++ ^ *b++) & 0xfe)
		return 0;	/* "K" */
	if ((*a++ ^ *b++) & 0xfe)
		return 0;	/* "A" */
	if ((*a++ ^ *b++) & 0xfe)
		return 0;	/* "9" */
	if ((*a++ ^ *b++) & 0xfe)
		return 0;	/* "W" */
	if ((*a++ ^ *b++) & 0xfe)
		return 0;	/* "S" */
	if ((*a++ ^ *b++) & 0xfe)
		return 0;	/* "B" */
	if (((*b) & 0x1e) == 0)
		return 1;	/* ssid 0 matches all ssid's */
	if ((*a++ ^ *b) & 0x1e)
		return 0;	/* ssid */
/*	if ((*a++^*b++)&0x1e)return 0;      ssid (how it was ...) */
	return 1;
}

/*
 * return pointer to the next station to get this packet
 */
unsigned char *next_addr(unsigned char *f)
{
	unsigned char *a;

/* If no digis, return the destination address */
	if (NO_DIGIS(f))
		return f;

/* check each digi field.  The first one that hasn't seen it is the one */
	a = f + 7;
	do {
		a += 7;
		if (NOTREPEATED(a))
			return a;
	}
	while (NOT_LAST(a));

/* all the digis have seen it.  return the destination address */
	return f;
}

/*
 * tack on the CRC for the frame.  Note we assume the buffer is long
 * enough to have the two bytes tacked on.
 */
void add_crc(unsigned char *buf, int l)
{
	unsigned short int u;

	u = compute_crc(buf, l);
	buf[l] = u & 0xff;	/* lsb first */
	buf[l + 1] = (u >> 8) & 0xff;	/* msb next */
}

/*
 * Dump AX25 frame.
 */
void dump_ax25frame(char *t, unsigned char *buf, int l)
{
#ifdef DEBUG
	int i;
#endif
	unsigned char *a;

	printf("%s AX25: (l=%3d)   ", t, l);

	if (l < 15) {
		printf("Bogus size...\n");
		return;
	}

	printf("%s -> ", call_to_a(buf + 7));
	printf("%s", call_to_a(buf));

	if (ARE_DIGIS(buf)) {
		printf(" v");
		a = buf + 7;
		do {
			a += 7;
			printf(" %s", call_to_a(a));
			if (REPEATED(a))
				printf("*");
		}
		while (NOT_LAST(a));
	}

	printf("\n");

#ifdef DEBUG
	for (i = 0; i < l; i++)
		printf("%02x ", buf[i]);
	printf("\n");
#endif

	fflush(stdout);
}