Blame view
net/batman-adv/icmp_socket.c
9.06 KB
0b8739314 batman-adv: updat... |
1 |
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors: |
c6c8fea29 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 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 net: Add batman-a... |
25 26 27 |
#include "hash.h" #include "originator.h" #include "hard-interface.h" |
56303d34a batman-adv: Prefi... |
28 |
static struct batadv_socket_client *batadv_socket_client_hash[256]; |
c6c8fea29 net: Add batman-a... |
29 |
|
56303d34a batman-adv: Prefi... |
30 |
static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, |
964126901 batman-adv: Prefi... |
31 |
struct batadv_icmp_packet_rr *icmp_packet, |
af4447f62 batman-adv: Prefi... |
32 |
size_t icmp_len); |
c6c8fea29 net: Add batman-a... |
33 |
|
9039dc7e8 batman-adv: Prefi... |
34 |
void batadv_socket_init(void) |
c6c8fea29 net: Add batman-a... |
35 |
{ |
af4447f62 batman-adv: Prefi... |
36 |
memset(batadv_socket_client_hash, 0, sizeof(batadv_socket_client_hash)); |
c6c8fea29 net: Add batman-a... |
37 |
} |
af4447f62 batman-adv: Prefi... |
38 |
static int batadv_socket_open(struct inode *inode, struct file *file) |
c6c8fea29 net: Add batman-a... |
39 40 |
{ unsigned int i; |
56303d34a batman-adv: Prefi... |
41 |
struct batadv_socket_client *socket_client; |
c6c8fea29 net: Add batman-a... |
42 |
|
bd5b80d51 batman-adv: Check... |
43 44 |
if (!try_module_get(THIS_MODULE)) return -EBUSY; |
c6c8fea29 net: Add batman-a... |
45 |
nonseekable_open(inode, file); |
704509b8d batman-adv: Calcu... |
46 |
socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL); |
bd5b80d51 batman-adv: Check... |
47 48 |
if (!socket_client) { module_put(THIS_MODULE); |
c6c8fea29 net: Add batman-a... |
49 |
return -ENOMEM; |
bd5b80d51 batman-adv: Check... |
50 |
} |
c6c8fea29 net: Add batman-a... |
51 |
|
af4447f62 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 net: Add batman-a... |
55 56 57 |
break; } } |
af4447f62 batman-adv: Prefi... |
58 |
if (i == ARRAY_SIZE(batadv_socket_client_hash)) { |
86ceb3605 batman-adv: Ignor... |
59 60 |
pr_err("Error - can't add another packet client: maximum number of clients reached "); |
c6c8fea29 net: Add batman-a... |
61 |
kfree(socket_client); |
bd5b80d51 batman-adv: Check... |
62 |
module_put(THIS_MODULE); |
c6c8fea29 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 net: Add batman-a... |
74 75 |
return 0; } |
af4447f62 batman-adv: Prefi... |
76 |
static int batadv_socket_release(struct inode *inode, struct file *file) |
c6c8fea29 net: Add batman-a... |
77 |
{ |
56303d34a batman-adv: Prefi... |
78 79 |
struct batadv_socket_client *socket_client = file->private_data; struct batadv_socket_packet *socket_packet; |
c6c8fea29 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 batman-adv: Prefi... |
87 |
struct batadv_socket_packet, list); |
c6c8fea29 net: Add batman-a... |
88 89 90 91 |
list_del(list_pos); kfree(socket_packet); } |
af4447f62 batman-adv: Prefi... |
92 |
batadv_socket_client_hash[socket_client->index] = NULL; |
c6c8fea29 net: Add batman-a... |
93 94 95 |
spin_unlock_bh(&socket_client->lock); kfree(socket_client); |
bd5b80d51 batman-adv: Check... |
96 |
module_put(THIS_MODULE); |
c6c8fea29 net: Add batman-a... |
97 98 99 |
return 0; } |
af4447f62 batman-adv: Prefi... |
100 101 |
static ssize_t batadv_socket_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
c6c8fea29 net: Add batman-a... |
102 |
{ |
56303d34a batman-adv: Prefi... |
103 104 |
struct batadv_socket_client *socket_client = file->private_data; struct batadv_socket_packet *socket_packet; |
c6c8fea29 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 batman-adv: Prefi... |
110 |
if ((!buf) || (count < sizeof(struct batadv_icmp_packet))) |
c6c8fea29 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 batman-adv: Prefi... |
125 |
struct batadv_socket_packet, list); |
c6c8fea29 net: Add batman-a... |
126 127 128 129 |
list_del(&socket_packet->list); socket_client->queue_len--; spin_unlock_bh(&socket_client->lock); |
b5a1eeef0 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 net: Add batman-a... |
132 |
|
c6c8fea29 net: Add batman-a... |
133 134 135 136 137 138 139 |
kfree(socket_packet); if (error) return -EFAULT; return packet_len; } |
af4447f62 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 net: Add batman-a... |
142 |
{ |
56303d34a 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 net: Add batman-a... |
146 |
struct sk_buff *skb; |
964126901 batman-adv: Prefi... |
147 |
struct batadv_icmp_packet_rr *icmp_packet; |
c6c8fea29 net: Add batman-a... |
148 |
|
56303d34a batman-adv: Prefi... |
149 150 |
struct batadv_orig_node *orig_node = NULL; struct batadv_neigh_node *neigh_node = NULL; |
964126901 batman-adv: Prefi... |
151 |
size_t packet_len = sizeof(struct batadv_icmp_packet); |
c6c8fea29 net: Add batman-a... |
152 |
|
964126901 batman-adv: Prefi... |
153 |
if (len < sizeof(struct batadv_icmp_packet)) { |
39c75a51e batman-adv: Prefi... |
154 |
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1eda58bfc batman-adv: Prefi... |
155 156 |
"Error - can't send packet from char device: invalid packet size "); |
c6c8fea29 net: Add batman-a... |
157 158 |
return -EINVAL; } |
e5d89254b batman-adv: Prefi... |
159 |
primary_if = batadv_primary_if_get_selected(bat_priv); |
32ae9b221 batman-adv: Make ... |
160 161 162 163 164 |
if (!primary_if) { len = -EFAULT; goto out; } |
c6c8fea29 net: Add batman-a... |
165 |
|
964126901 batman-adv: Prefi... |
166 167 |
if (len >= sizeof(struct batadv_icmp_packet_rr)) packet_len = sizeof(struct batadv_icmp_packet_rr); |
c6c8fea29 net: Add batman-a... |
168 |
|
41ab6c489 batman-adv: don't... |
169 |
skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN); |
32ae9b221 batman-adv: Make ... |
170 171 172 173 |
if (!skb) { len = -ENOMEM; goto out; } |
c6c8fea29 net: Add batman-a... |
174 |
|
41ab6c489 batman-adv: don't... |
175 |
skb_reserve(skb, ETH_HLEN); |
964126901 batman-adv: Prefi... |
176 |
icmp_packet = (struct batadv_icmp_packet_rr *)skb_put(skb, packet_len); |
c6c8fea29 net: Add batman-a... |
177 |
|
d18eb4533 batman-adv: Direc... |
178 |
if (copy_from_user(icmp_packet, buff, packet_len)) { |
c6c8fea29 net: Add batman-a... |
179 180 181 |
len = -EFAULT; goto free_skb; } |
acd34afa8 batman-adv: Prefi... |
182 |
if (icmp_packet->header.packet_type != BATADV_ICMP) { |
39c75a51e batman-adv: Prefi... |
183 |
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1eda58bfc batman-adv: Prefi... |
184 185 |
"Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP) "); |
c6c8fea29 net: Add batman-a... |
186 187 188 |
len = -EINVAL; goto free_skb; } |
acd34afa8 batman-adv: Prefi... |
189 |
if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { |
39c75a51e batman-adv: Prefi... |
190 |
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1eda58bfc batman-adv: Prefi... |
191 192 |
"Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST) "); |
c6c8fea29 net: Add batman-a... |
193 194 195 196 197 |
len = -EINVAL; goto free_skb; } icmp_packet->uid = socket_client->index; |
7e071c79a batman-adv: Prefi... |
198 |
if (icmp_packet->header.version != BATADV_COMPAT_VERSION) { |
acd34afa8 batman-adv: Prefi... |
199 |
icmp_packet->msg_type = BATADV_PARAMETER_PROBLEM; |
7e071c79a batman-adv: Prefi... |
200 |
icmp_packet->header.version = BATADV_COMPAT_VERSION; |
af4447f62 batman-adv: Prefi... |
201 202 |
batadv_socket_add_packet(socket_client, icmp_packet, packet_len); |
c6c8fea29 net: Add batman-a... |
203 204 |
goto free_skb; } |
39c75a51e batman-adv: Prefi... |
205 |
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
c6c8fea29 net: Add batman-a... |
206 |
goto dst_unreach; |
da641193d batman-adv: Prefi... |
207 |
orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst); |
c6c8fea29 net: Add batman-a... |
208 |
if (!orig_node) |
e1a5382f9 batman-adv: Make ... |
209 |
goto dst_unreach; |
44524fcdf batman-adv: Corre... |
210 |
|
7d211efc5 batman-adv: Prefi... |
211 |
neigh_node = batadv_orig_node_get_router(orig_node); |
44524fcdf batman-adv: Corre... |
212 |
if (!neigh_node) |
e1a5382f9 batman-adv: Make ... |
213 |
goto dst_unreach; |
c6c8fea29 net: Add batman-a... |
214 |
|
d0072609b batman-adv: remov... |
215 |
if (!neigh_node->if_incoming) |
c6c8fea29 net: Add batman-a... |
216 |
goto dst_unreach; |
e9a4f295e batman-adv: Prefi... |
217 |
if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) |
c6c8fea29 net: Add batman-a... |
218 219 220 |
goto dst_unreach; memcpy(icmp_packet->orig, |
32ae9b221 batman-adv: Make ... |
221 |
primary_if->net_dev->dev_addr, ETH_ALEN); |
c6c8fea29 net: Add batman-a... |
222 |
|
964126901 batman-adv: Prefi... |
223 |
if (packet_len == sizeof(struct batadv_icmp_packet_rr)) |
44524fcdf batman-adv: Corre... |
224 |
memcpy(icmp_packet->rr, |
d0072609b batman-adv: remov... |
225 |
neigh_node->if_incoming->net_dev->dev_addr, ETH_ALEN); |
c6c8fea29 net: Add batman-a... |
226 |
|
9455e34cb batman-adv: Prefi... |
227 |
batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); |
c6c8fea29 net: Add batman-a... |
228 |
goto out; |
c6c8fea29 net: Add batman-a... |
229 |
dst_unreach: |
acd34afa8 batman-adv: Prefi... |
230 |
icmp_packet->msg_type = BATADV_DESTINATION_UNREACHABLE; |
af4447f62 batman-adv: Prefi... |
231 |
batadv_socket_add_packet(socket_client, icmp_packet, packet_len); |
c6c8fea29 net: Add batman-a... |
232 233 234 |
free_skb: kfree_skb(skb); out: |
32ae9b221 batman-adv: Make ... |
235 |
if (primary_if) |
e5d89254b batman-adv: Prefi... |
236 |
batadv_hardif_free_ref(primary_if); |
44524fcdf batman-adv: Corre... |
237 |
if (neigh_node) |
7d211efc5 batman-adv: Prefi... |
238 |
batadv_neigh_node_free_ref(neigh_node); |
44524fcdf batman-adv: Corre... |
239 |
if (orig_node) |
7d211efc5 batman-adv: Prefi... |
240 |
batadv_orig_node_free_ref(orig_node); |
c6c8fea29 net: Add batman-a... |
241 242 |
return len; } |
af4447f62 batman-adv: Prefi... |
243 |
static unsigned int batadv_socket_poll(struct file *file, poll_table *wait) |
c6c8fea29 net: Add batman-a... |
244 |
{ |
56303d34a batman-adv: Prefi... |
245 |
struct batadv_socket_client *socket_client = file->private_data; |
c6c8fea29 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 batman-adv: Prefi... |
254 |
static const struct file_operations batadv_fops = { |
c6c8fea29 net: Add batman-a... |
255 |
.owner = THIS_MODULE, |
af4447f62 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 net: Add batman-a... |
261 262 |
.llseek = no_llseek, }; |
56303d34a batman-adv: Prefi... |
263 |
int batadv_socket_setup(struct batadv_priv *bat_priv) |
c6c8fea29 net: Add batman-a... |
264 265 266 267 268 |
{ struct dentry *d; if (!bat_priv->debug_dir) goto err; |
64346643e batman-adv: Prefi... |
269 |
d = debugfs_create_file(BATADV_ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, |
af4447f62 batman-adv: Prefi... |
270 |
bat_priv->debug_dir, bat_priv, &batadv_fops); |
5346c35eb batman-adv: Retur... |
271 |
if (!d) |
c6c8fea29 net: Add batman-a... |
272 273 274 275 276 |
goto err; return 0; err: |
5346c35eb batman-adv: Retur... |
277 |
return -ENOMEM; |
c6c8fea29 net: Add batman-a... |
278 |
} |
56303d34a batman-adv: Prefi... |
279 |
static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, |
964126901 batman-adv: Prefi... |
280 |
struct batadv_icmp_packet_rr *icmp_packet, |
af4447f62 batman-adv: Prefi... |
281 |
size_t icmp_len) |
c6c8fea29 net: Add batman-a... |
282 |
{ |
56303d34a batman-adv: Prefi... |
283 |
struct batadv_socket_packet *socket_packet; |
c6c8fea29 net: Add batman-a... |
284 |
|
704509b8d batman-adv: Calcu... |
285 |
socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC); |
c6c8fea29 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 batman-adv: Refor... |
297 298 |
* deleted */ |
af4447f62 batman-adv: Prefi... |
299 |
if (!batadv_socket_client_hash[icmp_packet->uid]) { |
c6c8fea29 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 batman-adv: Prefi... |
310 311 |
struct batadv_socket_packet, list); |
c6c8fea29 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 batman-adv: Prefi... |
322 |
void batadv_socket_receive_packet(struct batadv_icmp_packet_rr *icmp_packet, |
9039dc7e8 batman-adv: Prefi... |
323 |
size_t icmp_len) |
c6c8fea29 net: Add batman-a... |
324 |
{ |
56303d34a batman-adv: Prefi... |
325 |
struct batadv_socket_client *hash; |
c6c8fea29 net: Add batman-a... |
326 |
|
af4447f62 batman-adv: Prefi... |
327 |
hash = batadv_socket_client_hash[icmp_packet->uid]; |
c6c8fea29 net: Add batman-a... |
328 |
if (hash) |
af4447f62 batman-adv: Prefi... |
329 |
batadv_socket_add_packet(hash, icmp_packet, icmp_len); |
c6c8fea29 net: Add batman-a... |
330 |
} |