Blame view

net/batman-adv/icmp_socket.c 9.06 KB
0b8739314   Antonio Quartulli   batman-adv: updat...
1
  /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   *
   * Marek Lindner
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
c6c8fea29   Sven Eckelmann   net: Add batman-a...
18
19
20
21
22
23
24
   */
  
  #include "main.h"
  #include <linux/debugfs.h>
  #include <linux/slab.h>
  #include "icmp_socket.h"
  #include "send.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
25
26
27
  #include "hash.h"
  #include "originator.h"
  #include "hard-interface.h"
56303d34a   Sven Eckelmann   batman-adv: Prefi...
28
  static struct batadv_socket_client *batadv_socket_client_hash[256];
c6c8fea29   Sven Eckelmann   net: Add batman-a...
29

56303d34a   Sven Eckelmann   batman-adv: Prefi...
30
  static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
964126901   Sven Eckelmann   batman-adv: Prefi...
31
  				     struct batadv_icmp_packet_rr *icmp_packet,
af4447f62   Sven Eckelmann   batman-adv: Prefi...
32
  				     size_t icmp_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
33

9039dc7e8   Sven Eckelmann   batman-adv: Prefi...
34
  void batadv_socket_init(void)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
35
  {
af4447f62   Sven Eckelmann   batman-adv: Prefi...
36
  	memset(batadv_socket_client_hash, 0, sizeof(batadv_socket_client_hash));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
37
  }
af4447f62   Sven Eckelmann   batman-adv: Prefi...
38
  static int batadv_socket_open(struct inode *inode, struct file *file)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
39
40
  {
  	unsigned int i;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
41
  	struct batadv_socket_client *socket_client;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
42

bd5b80d51   Sven Eckelmann   batman-adv: Check...
43
44
  	if (!try_module_get(THIS_MODULE))
  		return -EBUSY;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
45
  	nonseekable_open(inode, file);
704509b8d   Sven Eckelmann   batman-adv: Calcu...
46
  	socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL);
bd5b80d51   Sven Eckelmann   batman-adv: Check...
47
48
  	if (!socket_client) {
  		module_put(THIS_MODULE);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
49
  		return -ENOMEM;
bd5b80d51   Sven Eckelmann   batman-adv: Check...
50
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
51

af4447f62   Sven Eckelmann   batman-adv: Prefi...
52
53
54
  	for (i = 0; i < ARRAY_SIZE(batadv_socket_client_hash); i++) {
  		if (!batadv_socket_client_hash[i]) {
  			batadv_socket_client_hash[i] = socket_client;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
55
56
57
  			break;
  		}
  	}
af4447f62   Sven Eckelmann   batman-adv: Prefi...
58
  	if (i == ARRAY_SIZE(batadv_socket_client_hash)) {
86ceb3605   Sven Eckelmann   batman-adv: Ignor...
59
60
  		pr_err("Error - can't add another packet client: maximum number of clients reached
  ");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
61
  		kfree(socket_client);
bd5b80d51   Sven Eckelmann   batman-adv: Check...
62
  		module_put(THIS_MODULE);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
63
64
65
66
67
68
69
70
71
72
73
  		return -EXFULL;
  	}
  
  	INIT_LIST_HEAD(&socket_client->queue_list);
  	socket_client->queue_len = 0;
  	socket_client->index = i;
  	socket_client->bat_priv = inode->i_private;
  	spin_lock_init(&socket_client->lock);
  	init_waitqueue_head(&socket_client->queue_wait);
  
  	file->private_data = socket_client;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
74
75
  	return 0;
  }
af4447f62   Sven Eckelmann   batman-adv: Prefi...
76
  static int batadv_socket_release(struct inode *inode, struct file *file)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
77
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
78
79
  	struct batadv_socket_client *socket_client = file->private_data;
  	struct batadv_socket_packet *socket_packet;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
80
81
82
83
84
85
86
  	struct list_head *list_pos, *list_pos_tmp;
  
  	spin_lock_bh(&socket_client->lock);
  
  	/* for all packets in the queue ... */
  	list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) {
  		socket_packet = list_entry(list_pos,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
87
  					   struct batadv_socket_packet, list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
88
89
90
91
  
  		list_del(list_pos);
  		kfree(socket_packet);
  	}
af4447f62   Sven Eckelmann   batman-adv: Prefi...
92
  	batadv_socket_client_hash[socket_client->index] = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
93
94
95
  	spin_unlock_bh(&socket_client->lock);
  
  	kfree(socket_client);
bd5b80d51   Sven Eckelmann   batman-adv: Check...
96
  	module_put(THIS_MODULE);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
97
98
99
  
  	return 0;
  }
af4447f62   Sven Eckelmann   batman-adv: Prefi...
100
101
  static ssize_t batadv_socket_read(struct file *file, char __user *buf,
  				  size_t count, loff_t *ppos)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
102
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
103
104
  	struct batadv_socket_client *socket_client = file->private_data;
  	struct batadv_socket_packet *socket_packet;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
105
106
107
108
109
  	size_t packet_len;
  	int error;
  
  	if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0))
  		return -EAGAIN;
964126901   Sven Eckelmann   batman-adv: Prefi...
110
  	if ((!buf) || (count < sizeof(struct batadv_icmp_packet)))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  		return -EINVAL;
  
  	if (!access_ok(VERIFY_WRITE, buf, count))
  		return -EFAULT;
  
  	error = wait_event_interruptible(socket_client->queue_wait,
  					 socket_client->queue_len);
  
  	if (error)
  		return error;
  
  	spin_lock_bh(&socket_client->lock);
  
  	socket_packet = list_first_entry(&socket_client->queue_list,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
125
  					 struct batadv_socket_packet, list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
126
127
128
129
  	list_del(&socket_packet->list);
  	socket_client->queue_len--;
  
  	spin_unlock_bh(&socket_client->lock);
b5a1eeef0   Sven Eckelmann   batman-adv: Only ...
130
131
  	packet_len = min(count, socket_packet->icmp_len);
  	error = copy_to_user(buf, &socket_packet->icmp_packet, packet_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
132

c6c8fea29   Sven Eckelmann   net: Add batman-a...
133
134
135
136
137
138
139
  	kfree(socket_packet);
  
  	if (error)
  		return -EFAULT;
  
  	return packet_len;
  }
af4447f62   Sven Eckelmann   batman-adv: Prefi...
140
141
  static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
  				   size_t len, loff_t *off)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
142
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
143
144
145
  	struct batadv_socket_client *socket_client = file->private_data;
  	struct batadv_priv *bat_priv = socket_client->bat_priv;
  	struct batadv_hard_iface *primary_if = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
146
  	struct sk_buff *skb;
964126901   Sven Eckelmann   batman-adv: Prefi...
147
  	struct batadv_icmp_packet_rr *icmp_packet;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
148

56303d34a   Sven Eckelmann   batman-adv: Prefi...
149
150
  	struct batadv_orig_node *orig_node = NULL;
  	struct batadv_neigh_node *neigh_node = NULL;
964126901   Sven Eckelmann   batman-adv: Prefi...
151
  	size_t packet_len = sizeof(struct batadv_icmp_packet);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
152

964126901   Sven Eckelmann   batman-adv: Prefi...
153
  	if (len < sizeof(struct batadv_icmp_packet)) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
154
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
155
156
  			   "Error - can't send packet from char device: invalid packet size
  ");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
157
158
  		return -EINVAL;
  	}
e5d89254b   Sven Eckelmann   batman-adv: Prefi...
159
  	primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b221   Marek Lindner   batman-adv: Make ...
160
161
162
163
164
  
  	if (!primary_if) {
  		len = -EFAULT;
  		goto out;
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
165

964126901   Sven Eckelmann   batman-adv: Prefi...
166
167
  	if (len >= sizeof(struct batadv_icmp_packet_rr))
  		packet_len = sizeof(struct batadv_icmp_packet_rr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
168

41ab6c489   Antonio Quartulli   batman-adv: don't...
169
  	skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN);
32ae9b221   Marek Lindner   batman-adv: Make ...
170
171
172
173
  	if (!skb) {
  		len = -ENOMEM;
  		goto out;
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
174

41ab6c489   Antonio Quartulli   batman-adv: don't...
175
  	skb_reserve(skb, ETH_HLEN);
964126901   Sven Eckelmann   batman-adv: Prefi...
176
  	icmp_packet = (struct batadv_icmp_packet_rr *)skb_put(skb, packet_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
177

d18eb4533   Sven Eckelmann   batman-adv: Direc...
178
  	if (copy_from_user(icmp_packet, buff, packet_len)) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
179
180
181
  		len = -EFAULT;
  		goto free_skb;
  	}
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
182
  	if (icmp_packet->header.packet_type != BATADV_ICMP) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
183
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
184
185
  			   "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)
  ");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
186
187
188
  		len = -EINVAL;
  		goto free_skb;
  	}
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
189
  	if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
190
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
191
192
  			   "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)
  ");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
193
194
195
196
197
  		len = -EINVAL;
  		goto free_skb;
  	}
  
  	icmp_packet->uid = socket_client->index;
7e071c79a   Sven Eckelmann   batman-adv: Prefi...
198
  	if (icmp_packet->header.version != BATADV_COMPAT_VERSION) {
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
199
  		icmp_packet->msg_type = BATADV_PARAMETER_PROBLEM;
7e071c79a   Sven Eckelmann   batman-adv: Prefi...
200
  		icmp_packet->header.version = BATADV_COMPAT_VERSION;
af4447f62   Sven Eckelmann   batman-adv: Prefi...
201
202
  		batadv_socket_add_packet(socket_client, icmp_packet,
  					 packet_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
203
204
  		goto free_skb;
  	}
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
205
  	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
206
  		goto dst_unreach;
da641193d   Sven Eckelmann   batman-adv: Prefi...
207
  	orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
208
  	if (!orig_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
209
  		goto dst_unreach;
44524fcdf   Marek Lindner   batman-adv: Corre...
210

7d211efc5   Sven Eckelmann   batman-adv: Prefi...
211
  	neigh_node = batadv_orig_node_get_router(orig_node);
44524fcdf   Marek Lindner   batman-adv: Corre...
212
  	if (!neigh_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
213
  		goto dst_unreach;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
214

d0072609b   Marek Lindner   batman-adv: remov...
215
  	if (!neigh_node->if_incoming)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
216
  		goto dst_unreach;
e9a4f295e   Sven Eckelmann   batman-adv: Prefi...
217
  	if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
218
219
220
  		goto dst_unreach;
  
  	memcpy(icmp_packet->orig,
32ae9b221   Marek Lindner   batman-adv: Make ...
221
  	       primary_if->net_dev->dev_addr, ETH_ALEN);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
222

964126901   Sven Eckelmann   batman-adv: Prefi...
223
  	if (packet_len == sizeof(struct batadv_icmp_packet_rr))
44524fcdf   Marek Lindner   batman-adv: Corre...
224
  		memcpy(icmp_packet->rr,
d0072609b   Marek Lindner   batman-adv: remov...
225
  		       neigh_node->if_incoming->net_dev->dev_addr, ETH_ALEN);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
226

9455e34cb   Sven Eckelmann   batman-adv: Prefi...
227
  	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
228
  	goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
229
  dst_unreach:
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
230
  	icmp_packet->msg_type = BATADV_DESTINATION_UNREACHABLE;
af4447f62   Sven Eckelmann   batman-adv: Prefi...
231
  	batadv_socket_add_packet(socket_client, icmp_packet, packet_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
232
233
234
  free_skb:
  	kfree_skb(skb);
  out:
32ae9b221   Marek Lindner   batman-adv: Make ...
235
  	if (primary_if)
e5d89254b   Sven Eckelmann   batman-adv: Prefi...
236
  		batadv_hardif_free_ref(primary_if);
44524fcdf   Marek Lindner   batman-adv: Corre...
237
  	if (neigh_node)
7d211efc5   Sven Eckelmann   batman-adv: Prefi...
238
  		batadv_neigh_node_free_ref(neigh_node);
44524fcdf   Marek Lindner   batman-adv: Corre...
239
  	if (orig_node)
7d211efc5   Sven Eckelmann   batman-adv: Prefi...
240
  		batadv_orig_node_free_ref(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
241
242
  	return len;
  }
af4447f62   Sven Eckelmann   batman-adv: Prefi...
243
  static unsigned int batadv_socket_poll(struct file *file, poll_table *wait)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
244
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
245
  	struct batadv_socket_client *socket_client = file->private_data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
246
247
248
249
250
251
252
253
  
  	poll_wait(file, &socket_client->queue_wait, wait);
  
  	if (socket_client->queue_len > 0)
  		return POLLIN | POLLRDNORM;
  
  	return 0;
  }
af4447f62   Sven Eckelmann   batman-adv: Prefi...
254
  static const struct file_operations batadv_fops = {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
255
  	.owner = THIS_MODULE,
af4447f62   Sven Eckelmann   batman-adv: Prefi...
256
257
258
259
260
  	.open = batadv_socket_open,
  	.release = batadv_socket_release,
  	.read = batadv_socket_read,
  	.write = batadv_socket_write,
  	.poll = batadv_socket_poll,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
261
262
  	.llseek = no_llseek,
  };
56303d34a   Sven Eckelmann   batman-adv: Prefi...
263
  int batadv_socket_setup(struct batadv_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
264
265
266
267
268
  {
  	struct dentry *d;
  
  	if (!bat_priv->debug_dir)
  		goto err;
64346643e   Sven Eckelmann   batman-adv: Prefi...
269
  	d = debugfs_create_file(BATADV_ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
af4447f62   Sven Eckelmann   batman-adv: Prefi...
270
  				bat_priv->debug_dir, bat_priv, &batadv_fops);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
271
  	if (!d)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
272
273
274
275
276
  		goto err;
  
  	return 0;
  
  err:
5346c35eb   Sven Eckelmann   batman-adv: Retur...
277
  	return -ENOMEM;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
278
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
279
  static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
964126901   Sven Eckelmann   batman-adv: Prefi...
280
  				     struct batadv_icmp_packet_rr *icmp_packet,
af4447f62   Sven Eckelmann   batman-adv: Prefi...
281
  				     size_t icmp_len)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
282
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
283
  	struct batadv_socket_packet *socket_packet;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
284

704509b8d   Sven Eckelmann   batman-adv: Calcu...
285
  	socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
286
287
288
289
290
291
292
293
294
295
296
  
  	if (!socket_packet)
  		return;
  
  	INIT_LIST_HEAD(&socket_packet->list);
  	memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len);
  	socket_packet->icmp_len = icmp_len;
  
  	spin_lock_bh(&socket_client->lock);
  
  	/* while waiting for the lock the socket_client could have been
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
297
298
  	 * deleted
  	 */
af4447f62   Sven Eckelmann   batman-adv: Prefi...
299
  	if (!batadv_socket_client_hash[icmp_packet->uid]) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
300
301
302
303
304
305
306
307
308
309
  		spin_unlock_bh(&socket_client->lock);
  		kfree(socket_packet);
  		return;
  	}
  
  	list_add_tail(&socket_packet->list, &socket_client->queue_list);
  	socket_client->queue_len++;
  
  	if (socket_client->queue_len > 100) {
  		socket_packet = list_first_entry(&socket_client->queue_list,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
310
311
  						 struct batadv_socket_packet,
  						 list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
312
313
314
315
316
317
318
319
320
321
  
  		list_del(&socket_packet->list);
  		kfree(socket_packet);
  		socket_client->queue_len--;
  	}
  
  	spin_unlock_bh(&socket_client->lock);
  
  	wake_up(&socket_client->queue_wait);
  }
964126901   Sven Eckelmann   batman-adv: Prefi...
322
  void batadv_socket_receive_packet(struct batadv_icmp_packet_rr *icmp_packet,
9039dc7e8   Sven Eckelmann   batman-adv: Prefi...
323
  				  size_t icmp_len)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
324
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
325
  	struct batadv_socket_client *hash;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
326

af4447f62   Sven Eckelmann   batman-adv: Prefi...
327
  	hash = batadv_socket_client_hash[icmp_packet->uid];
c6c8fea29   Sven Eckelmann   net: Add batman-a...
328
  	if (hash)
af4447f62   Sven Eckelmann   batman-adv: Prefi...
329
  		batadv_socket_add_packet(hash, icmp_packet, icmp_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
330
  }