summaryrefslogtreecommitdiffstats
path: root/net/ax25/ax25_ctl.c
blob: da4cd49c88b1709373c603d59a79391035a2080b (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
/*
 * ax25_ctl.c:  Implements ioctl()s on persisting VC sockets (NEW-AX.25)
 *
 * Authors:     Jens David (DG1KJD), Matthias Welwarsky (DG2FEF), Joerg (DL1BKE)
 *
 * Comment:
 *
 * Changelog:
 *
 * License:     This module 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.
 */

#include <asm/uaccess.h>
#include <linux/ax25.h>
#include <net/ax25.h>

#include "af_ax25.h"
#include "ax25_in.h"
#include "ax25_subr.h"
#include "ax25_timer.h"

/*
 * dl1bke 960311: set parameters for existing AX.25 connections,
 *		  includes a KILL command to abort any connection.
 *		  VERY useful for debugging ;-)
 */
int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
{
	struct ax25_ctl_struct ax25_ctl;
	struct net_device *dev;
	ax25_cb *ax25;
	ax25_addr_t addr;
	int err;

	if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_ctl))) != 0)
		return err;

	if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
		return -EFAULT;;

	if ((dev = ax25rtr_get_dev(&ax25_ctl.port_addr)) == NULL)
		return -ENODEV;

	addr.src    = ax25_ctl.source_addr;
	addr.dest   = ax25_ctl.dest_addr;
	addr.dcount = 0;

	if ((ax25 = ax25_find_cb(&addr, dev)) == NULL)
		return -ENOTCONN;

	switch (ax25_ctl.cmd) {
		case AX25_KILL:
			ax25_tx_command(ax25, AX25_DISC, AX25_POLLON);
			ax25_set_cond(ax25, AX25_COND_STATE_CHANGE);
			ax25_disconnect(ax25, ENETRESET);
			if (ax25->sk)
				ax25_close_socket(ax25->sk, ENETRESET);
			break;

		case AX25_WINDOW:
			if (ax25->seqmask == AX25_SEQMASK) {
				if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
					return -EINVAL;
			} else {
				if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
					return -EINVAL;
			}
			ax25->window = ax25_ctl.arg;
			break;

		case AX25_T1:
			if (ax25_ctl.arg < 1)
				return -EINVAL;
			ax25->rtt = (ax25_ctl.arg * AX25_TICS) / 4;
			ax25->t1  = ax25_ctl.arg;
			write_lock(&ax25->timer_lock);
			if (ax25->wrt_timer > ax25->t1)
				ax25->wrt_timer = ax25->t1;
			write_unlock(&ax25->timer_lock);
			break;

		case AX25_T2:
			if (ax25_ctl.arg < 0)
				return -EINVAL;
			ax25->t2 = ax25_ctl.arg;
			write_lock(&ax25->timer_lock);
			if (ax25->ack_timer > ax25->t2)
				ax25->ack_timer = ax25->t2;
			write_unlock(&ax25->timer_lock);
			break;

		case AX25_N2:
			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
				return -EINVAL;
			ax25->n2count = 0;
			ax25->n2 = ax25_ctl.arg;
			break;

		case AX25_T3:
			if (ax25_ctl.arg < 0)
				return -EINVAL;
			ax25->t3 = ax25_ctl.arg * AX25_SLOWHZ;
			write_lock(&ax25->timer_lock);
			if (ax25->wrt_timer != 0)
				ax25->wrt_timer = ax25->t3;
			write_unlock(&ax25->timer_lock);
			break;

		case AX25_IDLE:
			if (ax25_ctl.arg < 0)
				return -EINVAL;
			ax25->idle = ax25_ctl.arg * AX25_SLOWHZ;
			write_lock(&ax25->timer_lock);
			if (ax25->idletimer != 0)
				ax25->idletimer = ax25->idle;
			write_unlock(&ax25->timer_lock);
			break;

		case AX25_PACLEN:
			if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
				return -EINVAL;
			ax25->paclen = ax25_ctl.arg;
			break;

		default:
			return -EINVAL;
	  }

	  return 0;
}