blob: 3bbe51b9c455da18a8d4c137d0ca2e088f916c75 [file] [log] [blame]
Ravinder Konka94266eb2015-10-15 19:55:24 +05301/*************************************************************************
2 * -----------------------------------------------------------------------
3 * Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
4
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 * -----------------------------------------------------------------------
14
15 * DESCRIPTION
16 * Main file for eMBMs Tunneling Module in kernel.
17 *************************************************************************
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/fs.h>
23#include <net/ip.h>
24#include <linux/uaccess.h>
25#include <linux/types.h>
26#include <linux/version.h>
27#include <linux/etherdevice.h>
28
29#include <linux/inetdevice.h>
30#include <linux/netfilter.h>
31#include <net/arp.h>
32#include <net/neighbour.h>
33
34#include <linux/skbuff.h>
35#include <linux/list.h>
36#include <linux/in.h>
37#include <net/netfilter/nf_conntrack.h>
38#include <linux/miscdevice.h>
39#include "embms_kernel.h"
40
41struct embms_info_internal embms_conf;
42
43/* Global structures used for tunneling. These include
44 * iphdr and udphdr which are appended to skbs for
45 * tunneling, net_device and tunnleing related
46 * structs and params
47 */
48
49unsigned char hdr_buff[sizeof(struct iphdr) + sizeof(struct udphdr)];
50struct iphdr *iph_global;
51struct udphdr *udph_global;
52struct net_device *dev_global;
53
54static struct tmgi_to_clnt_info tmgi_to_clnt_map_tbl;
55
56/* handle_multicast_stream - packet forwarding
57 * function for multicast stream
58 * Main use case is for EMBMS Over Softap feature
59 */
60
61static int handle_multicast_stream(struct sk_buff *skb)
62{
63 struct iphdr *iph;
64 struct udphdr *udph;
Ravinder Konka94266eb2015-10-15 19:55:24 +053065 unsigned char *tmp_ptr = NULL;
66 struct sk_buff *skb_new = NULL;
67 struct sk_buff *skb_cpy = NULL;
68 struct clnt_info *temp_client = NULL;
69 struct tmgi_to_clnt_info *temp_tmgi = NULL;
70 struct list_head *tmgi_entry_ptr, *prev_tmgi_entry_ptr;
71 struct list_head *clnt_ptr, *prev_clnt_ptr;
72 int hdr_size = sizeof(*udph) + sizeof(*iph) + ETH_HLEN;
73
74 /* only IP packets */
75 if (htons(ETH_P_IP) != skb->protocol) {
76 embms_error("Not an IP packet\n");
77 return 0;
78 }
79
80 if (embms_conf.embms_tunneling_status == TUNNELING_OFF) {
81 embms_debug("Tunneling Disabled. Can't process packets\n");
82 return 0;
83 }
84
85 if (unlikely(memcmp(skb->dev->name, embms_conf.embms_iface,
86 strlen(embms_conf.embms_iface)) != 0)) {
87 embms_error("Packet received on %s iface. NOT an EMBMS Iface\n",
88 skb->dev->name);
89 return 0;
90 }
91
92 /* Check if dst ip of packet is same as multicast ip of any tmgi*/
93
94 iph = (struct iphdr *)skb->data;
95 udph = (struct udphdr *)(skb->data + sizeof(struct iphdr));
96
97 spin_lock_bh(&embms_conf.lock);
98
99 list_for_each_safe(tmgi_entry_ptr, prev_tmgi_entry_ptr,
100 &tmgi_to_clnt_map_tbl.tmgi_list_ptr) {
101 temp_tmgi = list_entry(tmgi_entry_ptr,
102 struct tmgi_to_clnt_info,
103 tmgi_list_ptr);
104
105 if ((temp_tmgi->tmgi_multicast_addr == iph->daddr) &&
106 (temp_tmgi->tmgi_port == udph->dest))
107 break;
108 }
109
110 if (tmgi_entry_ptr == &tmgi_to_clnt_map_tbl.tmgi_list_ptr) {
111 embms_error("handle_multicast_stream:");
112 embms_error("could not find matchin tmgi entry\n");
113 spin_unlock_bh(&embms_conf.lock);
114 return 0;
115 }
116
117 /* Found a matching tmgi entry. Realloc headroom to
118 * accommodate new Ethernet, IP and UDP header
119 */
120
121 skb_new = skb_realloc_headroom(skb, hdr_size);
122 if (unlikely(!skb_new)) {
123 embms_error("Can't allocate headroom\n");
124 spin_unlock_bh(&embms_conf.lock);
125 return 0;
126 }
127
128 /* push skb->data and copy IP and UDP headers*/
129
130 tmp_ptr = skb_push(skb_new,
131 sizeof(struct udphdr) + sizeof(struct iphdr));
132
133 iph = (struct iphdr *)tmp_ptr;
134 udph = (struct udphdr *)(tmp_ptr + sizeof(struct iphdr));
135
136 memcpy(tmp_ptr, hdr_buff, hdr_size - ETH_HLEN);
137 udph->len = htons(skb_new->len - sizeof(struct iphdr));
138 iph->tot_len = htons(skb_new->len);
139
140 list_for_each_safe(clnt_ptr, prev_clnt_ptr,
141 &temp_tmgi->client_list_head) {
142 temp_client = list_entry(clnt_ptr,
143 struct clnt_info,
144 client_list_ptr);
145
146 /* Make a copy of skb_new with new IP and UDP header.
147 * We can't use skb_new or its clone here since we need to
148 * constantly change dst ip and dst port which is not possible
149 * for shared memory as is the case with skb_new.
150 */
151
152 skb_cpy = skb_copy(skb_new, GFP_ATOMIC);
153 if (unlikely(!skb_cpy)) {
154 embms_error("Can't copy skb\n");
155 kfree_skb(skb_new);
156 return 0;
157 }
158
159 iph = (struct iphdr *)skb_cpy->data;
160 udph = (struct udphdr *)(skb_cpy->data + sizeof(struct iphdr));
161
162 iph->id = htons(atomic_inc_return(&embms_conf.ip_ident));
163
164 /* Calculate checksum for new IP and UDP header*/
165
166 udph->dest = temp_client->port;
167 skb_cpy->csum = csum_partial((char *)udph,
168 ntohs(udph->len),
169 skb_cpy->csum);
170
171 iph->daddr = temp_client->addr;
172 ip_send_check(iph);
173
174 udph->check = 0;
175 udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
176 ntohs(udph->len),
177 IPPROTO_UDP,
178 skb_cpy->csum);
179
180 if (udph->check == 0)
181 udph->check = CSUM_MANGLED_0;
182
183 if (unlikely(!dev_global)) {
184 embms_error("Global device NULL\n");
185 kfree_skb(skb_cpy);
186 kfree_skb(skb_new);
187 return 0;
188 }
189
190 /* update device info and add MAC header*/
191
192 skb_cpy->dev = dev_global;
193
194 skb_cpy->dev->header_ops->create(skb_cpy, skb_cpy->dev,
195 ETH_P_IP, temp_client->dmac,
196 NULL, skb_cpy->len);
197 dev_queue_xmit(skb_cpy);
198 }
199
200 spin_unlock_bh(&embms_conf.lock);
201 kfree_skb(skb_new);
202 return 1;
203}
204
205static int check_embms_device(atomic_t *use_count)
206{
207 int ret;
208
209 if (atomic_inc_return(use_count) == 1) {
210 ret = 0;
211 } else {
212 atomic_dec(use_count);
213 ret = -EBUSY;
214 }
215 return ret;
216}
217
218static int embms_device_open(struct inode *inode, struct file *file)
219{
220 /*Check if the device is busy*/
221 if (check_embms_device(&embms_conf.device_under_use)) {
222 embms_error("embms_tm_open : EMBMS device busy\n");
223 return -EBUSY;
224 }
225
226 try_module_get(THIS_MODULE);
227 return SUCCESS;
228}
229
230static int embms_device_release(struct inode *inode, struct file *file)
231{
232 /* Reduce device use count before leaving*/
233 embms_debug("Releasing EMBMS device..\n");
234 atomic_dec(&embms_conf.device_under_use);
235 embms_conf.embms_tunneling_status = TUNNELING_OFF;
236 module_put(THIS_MODULE);
237 return SUCCESS;
238}
239
240static struct tmgi_to_clnt_info *check_for_tmgi_entry(u32 addr,
241 u16 port)
242{
243 struct list_head *tmgi_ptr, *prev_tmgi_ptr;
244 struct tmgi_to_clnt_info *temp_tmgi = NULL;
245
246 embms_debug("check_for_tmgi_entry: mcast addr :%pI4, port %u\n",
247 &addr, ntohs(port));
248
249 list_for_each_safe(tmgi_ptr,
250 prev_tmgi_ptr,
251 &tmgi_to_clnt_map_tbl.tmgi_list_ptr) {
252 temp_tmgi = list_entry(tmgi_ptr,
253 struct tmgi_to_clnt_info,
254 tmgi_list_ptr);
255
256 if ((temp_tmgi->tmgi_multicast_addr == addr) &&
257 (temp_tmgi->tmgi_port == port)) {
258 embms_debug("check_for_tmgi_entry:TMGI entry found\n");
259 return temp_tmgi;
260 }
261 }
262 return NULL;
263}
264
265static struct clnt_info *chk_clnt_entry(struct tmgi_to_clnt_info *tmgi,
266 struct tmgi_to_clnt_info_update *clnt)
267{
268 struct list_head *clnt_ptr, *prev_clnt_ptr;
269 struct clnt_info *temp_client = NULL;
270
271 embms_debug("check_for_client_entry: clnt addr :%pI4, port %u\n",
272 &clnt->client_addr, ntohs(clnt->client_port));
273
274 list_for_each_safe(clnt_ptr,
275 prev_clnt_ptr,
276 &tmgi->client_list_head) {
277 temp_client = list_entry(clnt_ptr,
278 struct clnt_info,
279 client_list_ptr);
280 if ((temp_client->addr == clnt->client_addr) &&
281 (temp_client->port == clnt->client_port)) {
282 embms_debug("Clnt entry present\n");
283 return temp_client;
284 }
285 }
286 return NULL;
287}
288
289static int add_new_tmgi_entry(struct tmgi_to_clnt_info_update *info_update,
290 struct clnt_info *clnt)
291{
292 struct tmgi_to_clnt_info *new_tmgi = NULL;
293
294 embms_debug("add_new_tmgi_entry:Enter\n");
295
296 new_tmgi = kzalloc(sizeof(*new_tmgi),
297 GFP_ATOMIC);
298 if (!new_tmgi) {
299 embms_error("add_new_tmgi_entry: mem alloc failed\n");
300 return -ENOMEM;
301 }
302
303 memset(new_tmgi, 0, sizeof(struct tmgi_to_clnt_info));
304
305 new_tmgi->tmgi_multicast_addr = info_update->multicast_addr;
306 new_tmgi->tmgi_port = info_update->multicast_port;
307
308 embms_debug("add_new_tmgi_entry:");
309 embms_debug("New tmgi multicast addr :%pI4 , port %u\n",
310 &info_update->multicast_addr,
311 ntohs(info_update->multicast_port));
312
313 embms_debug("add_new_tmgi_entry:Adding client entry\n");
314
315 spin_lock_bh(&embms_conf.lock);
316
317 INIT_LIST_HEAD(&new_tmgi->client_list_head);
318 list_add(&clnt->client_list_ptr,
319 &new_tmgi->client_list_head);
320 new_tmgi->no_of_clients++;
321
322 /* Once above steps are done successfully,
323 * we add tmgi entry to our local table
324 */
325
326 list_add(&new_tmgi->tmgi_list_ptr,
327 &tmgi_to_clnt_map_tbl.tmgi_list_ptr);
328 embms_conf.no_of_tmgi_sessions++;
329
330 spin_unlock_bh(&embms_conf.lock);
331
332 return SUCCESS;
333}
334
335static void print_tmgi_to_client_table(void)
336{
337 int i, j;
338 struct clnt_info *temp_client = NULL;
339 struct tmgi_to_clnt_info *temp_tmgi = NULL;
340 struct list_head *tmgi_entry_ptr, *prev_tmgi_entry_ptr;
341 struct list_head *clnt_ptr, *prev_clnt_ptr;
342
343 embms_debug("====================================================\n");
344 embms_debug("Printing TMGI to Client Table :\n");
345 embms_debug("No of Active TMGIs : %d\n",
346 embms_conf.no_of_tmgi_sessions);
347 embms_debug("====================================================\n\n");
348
349 if (embms_conf.no_of_tmgi_sessions > 0) {
350 i = 1;
351 list_for_each_safe(tmgi_entry_ptr, prev_tmgi_entry_ptr,
352 &tmgi_to_clnt_map_tbl.tmgi_list_ptr) {
353 temp_tmgi = list_entry(tmgi_entry_ptr,
354 struct tmgi_to_clnt_info,
355 tmgi_list_ptr);
356
357 embms_debug("TMGI entry %d :\n", i);
358 embms_debug("TMGI multicast addr : %pI4 , port %u\n\n",
359 &temp_tmgi->tmgi_multicast_addr,
360 ntohs(temp_tmgi->tmgi_port));
361 embms_debug("No of clients : %d\n",
362 temp_tmgi->no_of_clients);
363 j = 1;
364
365 list_for_each_safe(clnt_ptr, prev_clnt_ptr,
366 &temp_tmgi->client_list_head) {
367 temp_client = list_entry(clnt_ptr,
368 struct clnt_info,
369 client_list_ptr);
370 embms_debug("Client entry %d :\n", j);
371 embms_debug("client addr : %pI4 , port %u\n\n",
372 &temp_client->addr,
373 ntohs(temp_client->port));
374 j++;
375 }
376 i++;
377 embms_debug("===========================================\n\n");
378 }
379 } else {
380 embms_debug("No TMGI entries to Display\n");
381 }
382 embms_debug("==================================================================\n\n");
383}
384
385/**
386 * delete_tmgi_entry_from_table() - deletes tmgi from global tmgi-client table
387 * @buffer: Buffer containing TMGI info for deletion.
388 *
389 * This function completely removes the TMGI from
390 * global TMGI-client table, along with the client list
391 * so that no packets for this TMGI are processed
392 *
393 * Return: Success on deleting TMGI entry, error otherwise.
394 */
395
396int delete_tmgi_entry_from_table(char *buffer)
397{
Ravinder Konka94266eb2015-10-15 19:55:24 +0530398 struct tmgi_to_clnt_info_update *info_update;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530399 struct clnt_info *temp_client = NULL;
400 struct tmgi_to_clnt_info *temp_tmgi = NULL;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530401 struct list_head *clnt_ptr, *prev_clnt_ptr;
402
403 embms_debug("delete_tmgi_entry_from_table: Enter\n");
404
405 info_update = (struct tmgi_to_clnt_info_update *)buffer;
406
407 if (!info_update) {
408 embms_error("delete_tmgi_entry_from_table:");
409 embms_error("NULL arguments passed\n");
410 return -EBADPARAM;
411 }
412
413 /* This function is used to delete a specific TMGI entry
414 * when that particular TMGI goes down
415 * Search for the TMGI entry in our local table
416 */
417 if (embms_conf.no_of_tmgi_sessions == 0) {
418 embms_error("TMGI count 0. Nothing to delete\n");
419 return SUCCESS;
420 }
421
422 temp_tmgi = check_for_tmgi_entry(info_update->multicast_addr,
423 info_update->multicast_port);
424
425 if (!temp_tmgi) {
426 /* TMGI entry was not found in our local table*/
427 embms_error("delete_client_entry_from_table :");
428 embms_error("Desired TMGI entry not found\n");
429 return -EBADPARAM;
430 }
431
432 spin_lock_bh(&embms_conf.lock);
433
434 /* We need to free memory allocated to client entries
435 * for a particular TMGI entry
436 */
437
438 list_for_each_safe(clnt_ptr, prev_clnt_ptr,
439 &temp_tmgi->client_list_head) {
440 temp_client = list_entry(clnt_ptr,
441 struct clnt_info,
442 client_list_ptr);
443 embms_debug("delete_tmgi_entry_from_table :");
444 embms_debug("Client addr to delete :%pI4 , port %u\n",
445 &temp_client->addr, ntohs(temp_client->port));
446 list_del(&temp_client->client_list_ptr);
447 temp_tmgi->no_of_clients--;
448 kfree(temp_client);
449 }
450
451 /* Free memory allocated to tmgi entry*/
452
453 list_del(&temp_tmgi->tmgi_list_ptr);
454 kfree(temp_tmgi);
455 embms_conf.no_of_tmgi_sessions--;
456
457 spin_unlock_bh(&embms_conf.lock);
458
459 embms_debug("delete_tmgi_entry_from_table : TMGI Entry deleted.\n");
460
461 return SUCCESS;
462}
463
464/**
465 * delete_client_entry_from_all_tmgi() - deletes client from all tmgi lists
466 * @buffer: Buffer containing client info for deletion.
467 *
468 * This function completely removes a client from
469 * all TMGIs in global TMGI-client table. Also delets TMGI
470 * entries if no more clients are there
471 *
472 * Return: Success on deleting client entry, error otherwise.
473 */
474int delete_client_entry_from_all_tmgi(char *buffer)
475{
Ravinder Konka94266eb2015-10-15 19:55:24 +0530476 struct tmgi_to_clnt_info_update *info_update;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530477 struct clnt_info *temp_client = NULL;
478 struct tmgi_to_clnt_info *tmgi = NULL;
479 struct list_head *tmgi_entry_ptr, *prev_tmgi_entry_ptr;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530480
481 /* We use this function when we want to delete any
482 * client entry from all TMGI entries. This scenario
483 * happens when any client disconnects and hence
484 * we need to clean all realted client entries
485 * in our mapping table
486 */
487
488 embms_debug("del_clnt_from_all_tmgi: Enter\n");
489
490 info_update = (struct tmgi_to_clnt_info_update *)buffer;
491
492 if (!info_update) {
493 embms_error("del_clnt_from_all_tmgi:");
494 embms_error("NULL arguments passed\n");
495 return -EBADPARAM;
496 }
497
498 /* We start checking from first TMGI entry and if client
499 * entry is found in client entries of any TMGI, we clean
500 * up that client entry from that TMGI entry
501 */
502 if (embms_conf.no_of_tmgi_sessions == 0)
503 return SUCCESS;
504
505 list_for_each_safe(tmgi_entry_ptr, prev_tmgi_entry_ptr,
506 &tmgi_to_clnt_map_tbl.tmgi_list_ptr) {
507 tmgi = list_entry(tmgi_entry_ptr,
508 struct tmgi_to_clnt_info,
509 tmgi_list_ptr);
510
511 temp_client = chk_clnt_entry(tmgi, info_update);
512 if (!temp_client)
513 continue;
514
515 spin_lock_bh(&embms_conf.lock);
516
517 list_del(&temp_client->client_list_ptr);
518 tmgi->no_of_clients--;
519 kfree(temp_client);
520
521 spin_unlock_bh(&embms_conf.lock);
522
523 temp_client = NULL;
524
525 if (tmgi->no_of_clients == 0) {
526 /* Deleted clnt was the only clnt for
527 * that TMGI we need to delete TMGI
528 * entry from table
529 */
530 embms_debug("del_clnt_from_all_tmgi:");
531 embms_debug("Deleted client was ");
532 embms_debug("last client for tmgi\n");
533 embms_debug("del_clnt_from_all_tmgi:");
534 embms_debug("Delting tmgi as it has ");
535 embms_debug("zero clients.TMGI IP ");
536 embms_debug(":%pI4 , port %u\n",
537 &tmgi->tmgi_multicast_addr,
538 ntohs(tmgi->tmgi_port));
539
540 spin_lock_bh(&embms_conf.lock);
541
542 list_del(&tmgi->tmgi_list_ptr);
543 embms_conf.no_of_tmgi_sessions--;
544 kfree(tmgi);
545
546 spin_unlock_bh(&embms_conf.lock);
547
548 embms_debug("del_clnt_from_all_tmgi:");
549 embms_debug("TMGI entry deleted\n");
550 }
551 }
552
553 embms_debug("del_clnt_from_all_tmgi Successful\n");
554 return SUCCESS;
555}
556
557/**
558 * add_client_entry_to_table() - add client entry to specified TMGI
559 * @buffer: Buffer containing client info for addition.
560 *
561 * This function adds a client to the specified TMGI in
562 * the global TMGI-client table. If TMGI entry is not
563 * present, it adds a new TMGI entry and adds client
564 * entry to it.
565 *
566 * Return: Success on adding client entry, error otherwise.
567 */
568int add_client_entry_to_table(char *buffer)
569{
Mohammed Javidc1dc1652017-11-14 10:11:12 +0530570 int ret;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530571 struct tmgi_to_clnt_info_update *info_update;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530572 struct clnt_info *new_client = NULL;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530573 struct tmgi_to_clnt_info *tmgi = NULL;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530574 struct neighbour *neigh_entry;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530575
576 embms_debug("add_client_entry_to_table: Enter\n");
577
578 info_update = (struct tmgi_to_clnt_info_update *)buffer;
579
580 if (!info_update) {
581 embms_error("add_client_entry_to_table:");
582 embms_error("NULL arguments passed\n");
583 return -EBADPARAM;
584 }
585
586 new_client = kzalloc(sizeof(*new_client), GFP_ATOMIC);
587 if (!new_client) {
588 embms_error("add_client_entry_to_table:");
589 embms_error("Cannot allocate memory\n");
590 return -ENOMEM;
591 }
592
593 new_client->addr = info_update->client_addr;
594 new_client->port = info_update->client_port;
595
596 neigh_entry = __ipv4_neigh_lookup(dev_global,
597 (u32)(new_client->addr));
598 if (!neigh_entry) {
599 embms_error("add_client_entry_to_table :");
600 embms_error("Can't find neighbour entry\n");
601 kfree(new_client);
602 return -EBADPARAM;
603 }
604
605 ether_addr_copy(new_client->dmac, neigh_entry->ha);
606
607 embms_debug("DMAC of client : %pM\n", new_client->dmac);
608
609 embms_debug("add_client_entry_to_table:");
610 embms_debug("New client addr :%pI4 , port %u\n",
611 &info_update->client_addr,
612 ntohs(info_update->client_port));
613
614 if (embms_conf.no_of_tmgi_sessions == 0) {
615 /* TMGI Client mapping table is empty.
616 * First client entry is being added
617 */
618
619 embms_debug("tmgi_to_clnt_map_tbl is empty\n");
620
621 ret = add_new_tmgi_entry(info_update, new_client);
622 if (ret != SUCCESS) {
623 kfree(new_client);
624 new_client = NULL;
625 }
626
627 goto exit_add;
628 }
629
630 /* In this case, table already has some entries
631 * and we need to search for the specific tmgi entry
632 * for which client entry is to be added
633 */
634
635 tmgi = check_for_tmgi_entry(info_update->multicast_addr,
636 info_update->multicast_port);
637 if (tmgi) {
638 if (chk_clnt_entry(tmgi, info_update)) {
639 kfree(new_client);
640 return -ENOEFFECT;
641 }
642
643 /* Adding client to the client list
644 * for the specified TMGI
645 */
646
647 spin_lock_bh(&embms_conf.lock);
648
649 list_add(&new_client->client_list_ptr,
650 &tmgi->client_list_head);
651 tmgi->no_of_clients++;
652
653 spin_unlock_bh(&embms_conf.lock);
654
655 ret = SUCCESS;
656 } else {
657 /* TMGI specified in the message was not found in
658 * mapping table.Hence, we need to add a new entry
659 * for this TMGI and add the specified client to the client
660 * list
661 */
662
663 embms_debug("TMGI entry not present. Adding tmgi entry\n");
664
665 ret = add_new_tmgi_entry(info_update, new_client);
666 if (ret != SUCCESS) {
667 kfree(new_client);
668 new_client = NULL;
669 }
670 }
671
672exit_add:
673 return ret;
674}
675
676/**
677 * delete_client_entry_from_table() - delete client entry from specified TMGI
678 * @buffer: Buffer containing client info for deletion.
679 *
680 * This function deletes a client from the specified TMGI in
681 * the global TMGI-client table. If this was the last client
682 * entry, it also deletes the TMGI entry.
683 *
684 * Return: Success on deleting client entry, error otherwise.
685 */
686int delete_client_entry_from_table(char *buffer)
687{
Ravinder Konka94266eb2015-10-15 19:55:24 +0530688 struct tmgi_to_clnt_info_update *info_update;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530689 struct clnt_info *temp_client = NULL;
690 struct tmgi_to_clnt_info *temp_tmgi = NULL;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530691
692 embms_debug("delete_client_entry_from_table: Enter\n");
693
694 info_update = (struct tmgi_to_clnt_info_update *)buffer;
695
696 if (!info_update) {
697 embms_error("delete_client_entry_from_table:");
698 embms_error("NULL arguments passed\n");
699 return -EBADPARAM;
700 }
701
702 /* Search for the TMGI entry*/
703 if (embms_conf.no_of_tmgi_sessions == 0)
704 return SUCCESS;
705
706 temp_tmgi = check_for_tmgi_entry(info_update->multicast_addr,
707 info_update->multicast_port);
708
709 if (!temp_tmgi) {
710 embms_error("delete_client_entry_from_table:TMGI not found\n");
711 return -EBADPARAM;
712 }
713 /* Delete client entry for a specific tmgi*/
714
715 embms_debug("delete_client_entry_from_table:clnt addr :%pI4,port %u\n",
716 &info_update->client_addr,
717 ntohs(info_update->client_port));
718
719 temp_client = chk_clnt_entry(temp_tmgi, info_update);
720
721 if (!temp_client) {
722 /* Specified client entry was not found in client list
723 * of specified TMGI
724 */
725 embms_error("delete_client_entry_from_table:Clnt not found\n");
726 return -EBADPARAM;
727 }
728
729 spin_lock_bh(&embms_conf.lock);
730
731 list_del(&temp_client->client_list_ptr);
732 temp_tmgi->no_of_clients--;
733
734 spin_unlock_bh(&embms_conf.lock);
735
736 kfree(temp_client);
737 temp_client = NULL;
738
739 embms_debug("delete_client_entry_from_table:Client entry deleted\n");
740
741 if (temp_tmgi->no_of_clients == 0) {
742 /* If deleted client was the only client for that TMGI
743 * we need to delete TMGI entry from table
744 */
745 embms_debug("delete_client_entry_from_table:");
746 embms_debug("Deleted client was the last client for tmgi\n");
747 embms_debug("delete_client_entry_from_table:");
748 embms_debug("Deleting tmgi since it has zero clients\n");
749
750 spin_lock_bh(&embms_conf.lock);
751
752 list_del(&temp_tmgi->tmgi_list_ptr);
753 embms_conf.no_of_tmgi_sessions--;
754 kfree(temp_tmgi);
755
756 spin_unlock_bh(&embms_conf.lock);
757
758 embms_debug("delete_client_entry_from_table: TMGI deleted\n");
759 }
760
761 if (embms_conf.no_of_tmgi_sessions == 0)
762 embms_conf.embms_tunneling_status = TUNNELING_OFF;
763
764 return SUCCESS;
765}
766
767/**
768 * embms_device_ioctl() - handle IOCTL calls to device
769 * @file: File descriptor of file opened from userspace process
770 * @ioctl_num: IOCTL to use
771 * @ioctl_param: IOCTL parameters/arguments
772 *
773 * This function is called whenever a process tries to do
774 * an ioctl on our device file. As per the IOCTL number,
775 * it calls various functions to manipulate global
776 * TMGI-client table
777 *
778 * Return: Success if functoin call returns SUCCESS, error otherwise.
779 */
780
Mohammed Javidc1dc1652017-11-14 10:11:12 +0530781long embms_device_ioctl(struct file *file, unsigned int ioctl_num,
782 unsigned long ioctl_param)
Ravinder Konka94266eb2015-10-15 19:55:24 +0530783{
Mohammed Javidc1dc1652017-11-14 10:11:12 +0530784 int ret;
Ravinder Konka94266eb2015-10-15 19:55:24 +0530785 char buffer[BUF_LEN];
786 struct in_device *iface_dev;
787 struct in_ifaddr *iface_info;
788 struct tmgi_to_clnt_info_update *info_update;
789 char __user *argp = (char __user *)ioctl_param;
790
791 memset(buffer, 0, BUF_LEN);
792
793 /* Switch according to the ioctl called*/
794 switch (ioctl_num) {
795 case ADD_EMBMS_TUNNEL:
796 if (copy_from_user(buffer, argp,
797 sizeof(struct tmgi_to_clnt_info_update)))
798 return -EFAULT;
799
800 ret = add_client_entry_to_table(buffer);
801 print_tmgi_to_client_table();
802 break;
803
804 case DEL_EMBMS_TUNNEL:
805 if (copy_from_user(buffer, argp,
806 sizeof(struct tmgi_to_clnt_info_update)))
807 return -EFAULT;
808
809 ret = delete_client_entry_from_table(buffer);
810 print_tmgi_to_client_table();
811 break;
812
813 case TMGI_DEACTIVATE:
814 if (copy_from_user(buffer, argp,
815 sizeof(struct tmgi_to_clnt_info_update)))
816 return -EFAULT;
817
818 ret = delete_tmgi_entry_from_table(buffer);
819 print_tmgi_to_client_table();
820 break;
821
822 case CLIENT_DEACTIVATE:
823 if (copy_from_user(buffer, argp,
824 sizeof(struct tmgi_to_clnt_info_update)))
825 return -EFAULT;
826
827 ret = delete_client_entry_from_all_tmgi(buffer);
828 print_tmgi_to_client_table();
829 break;
830
831 case GET_EMBMS_TUNNELING_STATUS:
832 /* This ioctl is both input (ioctl_param) and
833 * output (the return value of this function)
834 */
835 embms_debug("Sending tunneling status : %d\n",
836 embms_conf.embms_tunneling_status);
837 ret = embms_conf.embms_tunneling_status;
838 break;
839
840 case START_EMBMS_TUNNEL:
841
842 if (copy_from_user(buffer, argp,
843 sizeof(struct tmgi_to_clnt_info_update)))
844 return -EFAULT;
845
846 info_update = (struct tmgi_to_clnt_info_update *)buffer;
847 embms_conf.embms_data_port = info_update->data_port;
848 udph_global->source = embms_conf.embms_data_port;
849
850 memset(embms_conf.embms_iface, 0, EMBMS_MAX_IFACE_NAME);
851 memcpy(embms_conf.embms_iface, info_update->iface_name,
852 EMBMS_MAX_IFACE_NAME);
853
854 embms_conf.embms_tunneling_status = TUNNELING_ON;
855 embms_debug("Starting Tunneling. Embms_data_port = %d\n",
856 ntohs(embms_conf.embms_data_port));
857 embms_debug("Embms Data Iface = %s\n", embms_conf.embms_iface);
858 ret = SUCCESS;
859
860 /*Initialise dev_global to bridge device*/
861 dev_global = __dev_get_by_name(&init_net, BRIDGE_IFACE);
862 if (!dev_global) {
863 embms_error("Error in getting device info\n");
864 ret = FAILURE;
865 } else {
866 iface_dev = (struct in_device *)dev_global->ip_ptr;
867 iface_info = iface_dev->ifa_list;
868 while (iface_info) {
869 if (memcmp(iface_info->ifa_label,
870 BRIDGE_IFACE,
871 strlen(BRIDGE_IFACE)) == 0)
872 break;
873
874 iface_info = iface_info->ifa_next;
875 }
876 if (iface_info) {
877 embms_debug("IP address of %s iface is %pI4\n",
878 BRIDGE_IFACE,
879 &iface_info->ifa_address);
880 /*Populate source addr for header*/
881 iph_global->saddr = iface_info->ifa_address;
882 ret = SUCCESS;
883 } else {
884 embms_debug("Could not find iface address\n");
885 ret = FAILURE;
886 }
887 }
888
889 break;
890
891 case STOP_EMBMS_TUNNEL:
892
893 embms_conf.embms_tunneling_status = TUNNELING_OFF;
894 embms_debug("Stopped Tunneling..\n");
895 ret = SUCCESS;
896 break;
897 }
898
899 return ret;
900}
901
902/* Module Declarations
903 * This structure will hold the functions to be called
904 * when a process does something to the device we
905 * created. Since a pointer to this structure is kept in
906 * the devices table, it can't be local to
907 * init_module. NULL is for unimplemented functions.
908 */
909static const struct file_operations embms_device_fops = {
910 .owner = THIS_MODULE,
911 .open = embms_device_open,
912 .release = embms_device_release,
913 .read = NULL,
914 .write = NULL,
915 .unlocked_ioctl = embms_device_ioctl,
916};
917
918static int embms_ioctl_init(void)
919{
920 int ret;
921 struct device *dev;
922
923 ret = alloc_chrdev_region(&device, 0, dev_num, EMBMS_DEVICE_NAME);
924 if (ret) {
925 embms_error("device_alloc err\n");
926 goto dev_alloc_err;
927 }
928
929 embms_class = class_create(THIS_MODULE, EMBMS_DEVICE_NAME);
930 if (IS_ERR(embms_class)) {
931 embms_error("class_create err\n");
932 goto class_err;
933 }
934
935 dev = device_create(embms_class, NULL, device,
936 &embms_conf, EMBMS_DEVICE_NAME);
937 if (IS_ERR(dev)) {
938 embms_error("device_create err\n");
939 goto device_err;
940 }
941
942 cdev_init(&embms_device, &embms_device_fops);
943 ret = cdev_add(&embms_device, device, dev_num);
944 if (ret) {
945 embms_error("cdev_add err\n");
946 goto cdev_add_err;
947 }
948
949 embms_debug("ioctl init OK!!\n");
950 return 0;
951
952cdev_add_err:
953 device_destroy(embms_class, device);
954device_err:
955 class_destroy(embms_class);
956class_err:
957 unregister_chrdev_region(device, dev_num);
958dev_alloc_err:
959 return -ENODEV;
960}
961
962static void embms_ioctl_deinit(void)
963{
964 cdev_del(&embms_device);
965 device_destroy(embms_class, device);
966 class_destroy(embms_class);
967 unregister_chrdev_region(device, dev_num);
968}
969
970/*Initialize the module - Register the misc device*/
971static int __init start_embms(void)
972{
973 int ret = 0;
974
975 iph_global = (struct iphdr *)hdr_buff;
976 udph_global = (struct udphdr *)(hdr_buff + sizeof(struct iphdr));
977
978 embms_conf.embms_tunneling_status = TUNNELING_OFF;
979 embms_conf.no_of_tmgi_sessions = 0;
980 embms_conf.embms_data_port = 0;
981 atomic_set(&embms_conf.device_under_use, 0);
982 atomic_set(&embms_conf.ip_ident, 0);
983 spin_lock_init(&embms_conf.lock);
984
985 embms_debug("Registering embms device\n");
986
987 ret = embms_ioctl_init();
988 if (ret) {
989 embms_error("embms device failed to register");
990 goto fail_init;
991 }
992
993 INIT_LIST_HEAD(&tmgi_to_clnt_map_tbl.tmgi_list_ptr);
994
995 memset(hdr_buff, 0, sizeof(struct udphdr) + sizeof(struct iphdr));
996 udph_global->check = UDP_CHECKSUM;
997 iph_global->version = IP_VERSION;
998 iph_global->ihl = IP_IHL;
999 iph_global->tos = IP_TOS;
1000 iph_global->frag_off = IP_FRAG_OFFSET;
1001 iph_global->ttl = IP_TTL;
1002 iph_global->protocol = IPPROTO_UDP;
1003
1004 dev_global = NULL;
1005
1006 if (!embms_tm_multicast_recv)
1007 RCU_INIT_POINTER(embms_tm_multicast_recv,
1008 handle_multicast_stream);
1009
1010 return ret;
1011
1012fail_init:
1013 embms_ioctl_deinit();
1014 return ret;
1015}
1016
1017/*Cleanup - unregister the appropriate file from proc*/
1018
1019static void __exit stop_embms(void)
1020{
1021 embms_ioctl_deinit();
1022
1023 if (rcu_dereference(embms_tm_multicast_recv))
1024 RCU_INIT_POINTER(embms_tm_multicast_recv, NULL);
1025
1026 embms_debug("unregister_chrdev done\n");
1027}
1028
1029module_init(start_embms);
1030module_exit(stop_embms);
1031MODULE_LICENSE("GPL v2");