PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src-rt/emf/igs/igs_linux.c

https://gitlab.com/envieidoc/tomato
C | 563 lines | 389 code | 99 blank | 75 comment | 57 complexity | 78a6734d765e6d7c8650cef6eca2b8dc MD5 | raw file
  1. /*
  2. * IGMP Snooping layer linux specific code
  3. *
  4. * Copyright (C) 2009, Broadcom Corporation
  5. * All Rights Reserved.
  6. *
  7. * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
  8. * the contents of this file may not be disclosed to third parties, copied
  9. * or duplicated in any form, in whole or in part, without the prior
  10. * written permission of Broadcom Corporation.
  11. *
  12. * $Id: igs_linux.c,v 1.7 2009/04/28 00:08:23 Exp $
  13. */
  14. #include <linux/module.h>
  15. #include <linux/netdevice.h>
  16. #include <linux/proc_fs.h>
  17. #include <linux/netlink.h>
  18. #include <net/sock.h>
  19. #include <linux/if.h>
  20. #include <proto/ethernet.h>
  21. #include <bcmnvram.h>
  22. #include <bcmutils.h>
  23. #include <osl.h>
  24. #include <emf/igs/osl_linux.h>
  25. #include <emf/igs/igs_cfg.h>
  26. #include <emf/igs/igsc_export.h>
  27. #include "igs_linux.h"
  28. MODULE_LICENSE("Proprietary");
  29. static igs_struct_t igs;
  30. /*
  31. * Description: This function is called by IGS Common code when it wants
  32. * to send a packet on to all the LAN ports. It allocates
  33. * the native OS packet buffer, adds mac header and forwards
  34. * a copy of frame on to LAN ports.
  35. *
  36. * Input: igs_info - IGS instance information.
  37. * ip - Pointer to the buffer containing the frame to
  38. * send.
  39. * length - Length of the buffer.
  40. * mgrp_ip - Multicast destination address.
  41. *
  42. * Return: SUCCESS or FAILURE
  43. */
  44. int32
  45. igs_broadcast(igs_info_t *igs_info, uint8 *ip, uint32 length, uint32 mgrp_ip)
  46. {
  47. struct sk_buff *skb;
  48. struct net_device *br_dev;
  49. struct ether_header *eh;
  50. br_dev = igs_info->br_dev;
  51. ASSERT(br_dev);
  52. if ((br_dev->flags & IFF_UP) == 0)
  53. {
  54. IGS_ERROR("Bridge interface %s is down\n", br_dev->name);
  55. return (FAILURE);
  56. }
  57. skb = dev_alloc_skb(length + ETHER_HDR_LEN);
  58. if (skb == NULL)
  59. {
  60. IGS_ERROR("Out of memory allocating IGMP Query packet\n");
  61. return (FAILURE);
  62. }
  63. IGS_DEBUG("Allocated pkt buffer for IGMP Query\n");
  64. skb_pull(skb, ETHER_HDR_LEN);
  65. memcpy(skb->data, ip, length);
  66. skb_put(skb, length);
  67. /* Add the ethernet header */
  68. eh = (struct ether_header *)skb_push(skb, ETH_HLEN);
  69. eh->ether_type = __constant_htons(ETH_P_IP);
  70. eh->ether_dhost[0] = 0x01;
  71. eh->ether_dhost[1] = 0x00;
  72. eh->ether_dhost[2] = 0x5e;
  73. eh->ether_dhost[5] = mgrp_ip & 0xff; mgrp_ip >>= 8;
  74. eh->ether_dhost[4] = mgrp_ip & 0xff; mgrp_ip >>= 8;
  75. eh->ether_dhost[3] = mgrp_ip & 0x7f;
  76. /* Send the frame on to the bridge device */
  77. memcpy(eh->ether_shost, br_dev->dev_addr, br_dev->addr_len);
  78. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
  79. skb_reset_mac_header(skb);
  80. #else
  81. skb->mac.raw = skb->data;
  82. #endif
  83. skb->dev = br_dev;
  84. dev_queue_xmit(skb);
  85. IGS_DEBUG("IGMP Query sent on %s\n", br_dev->name);
  86. return (SUCCESS);
  87. }
  88. #ifdef CONFIG_PROC_FS
  89. /*
  90. * IGSL Packet Counters/Statistics Function
  91. */
  92. static int32
  93. igs_stats_get(char *buf, char **start, off_t offset, int32 size,
  94. int32 *eof, void *data)
  95. {
  96. igs_info_t *igs_info;
  97. igs_cfg_request_t cfg;
  98. igs_stats_t *stats;
  99. struct bcmstrbuf b;
  100. igs_info = (igs_info_t *)data;
  101. strcpy(cfg.inst_id, igs_info->inst_id);
  102. cfg.command_id = IGSCFG_CMD_IGS_STATS;
  103. cfg.oper_type = IGSCFG_OPER_TYPE_GET;
  104. cfg.size = sizeof(cfg.arg);
  105. stats = (igs_stats_t *)cfg.arg;
  106. igsc_cfg_request_process(igs_info->igsc_info, &cfg);
  107. if (cfg.status != IGSCFG_STATUS_SUCCESS)
  108. {
  109. IGS_ERROR("Unable to get the IGS stats\n");
  110. return (FAILURE);
  111. }
  112. bcm_binit(&b, buf, size);
  113. bcm_bprintf(&b, "IgmpPkts IgmpQueries "
  114. "IgmpReports IgmpV2Reports IgmpLeaves\n");
  115. bcm_bprintf(&b, "%-15d %-15d %-15d %-15d %d\n",
  116. stats->igmp_packets, stats->igmp_queries,
  117. stats->igmp_reports, stats->igmp_v2reports,
  118. stats->igmp_leaves);
  119. bcm_bprintf(&b, "IgmpNotHandled McastGroups "
  120. "McastMembers MemTimeouts\n");
  121. bcm_bprintf(&b, "%-15d %-15d %-15d %d\n",
  122. stats->igmp_not_handled, stats->igmp_mcast_groups,
  123. stats->igmp_mcast_members, stats->igmp_mem_timeouts);
  124. if (b.size == 0)
  125. {
  126. IGS_ERROR("Input buffer overflow\n");
  127. return (FAILURE);
  128. }
  129. return (b.buf - b.origbuf);
  130. }
  131. static int32
  132. igs_sdb_list(char *buf, char **start, off_t offset, int32 size,
  133. int32 *eof, void *data)
  134. {
  135. igs_info_t *igs_info;
  136. igs_cfg_request_t cfg;
  137. igs_cfg_sdb_list_t *list;
  138. int32 i;
  139. struct bcmstrbuf b;
  140. igs_info = (igs_info_t *)data;
  141. strcpy(cfg.inst_id, igs_info->inst_id);
  142. cfg.command_id = IGSCFG_CMD_IGSDB_LIST;
  143. cfg.oper_type = IGSCFG_OPER_TYPE_GET;
  144. cfg.size = sizeof(cfg.arg);
  145. list = (igs_cfg_sdb_list_t *)cfg.arg;
  146. igsc_cfg_request_process(igs_info->igsc_info, &cfg);
  147. if (cfg.status != IGSCFG_STATUS_SUCCESS)
  148. {
  149. IGS_ERROR("Unable to get the IGSDB list\n");
  150. return (FAILURE);
  151. }
  152. bcm_binit(&b, buf, size);
  153. bcm_bprintf(&b, "Group Members Interface\n");
  154. for (i = 0; i < list->num_entries; i++)
  155. {
  156. bcm_bprintf(&b, "%08x ", list->sdb_entry[i].mgrp_ip);
  157. bcm_bprintf(&b, "%08x ", list->sdb_entry[i].mh_ip);
  158. bcm_bprintf(&b, "%s\n", list->sdb_entry[i].if_name);
  159. }
  160. if (b.size == 0)
  161. {
  162. IGS_ERROR("Input buffer overflow\n");
  163. return (FAILURE);
  164. }
  165. return (b.buf - b.origbuf);
  166. }
  167. #endif /* CONFIG_PROC_FS */
  168. /*
  169. * Description: This function is called when user application enables snooping
  170. * on a bridge interface. It primarily allocates memory for IGS
  171. * instance data and calls common code initialization function.
  172. */
  173. static igs_info_t *
  174. igs_instance_add(int8 *inst_id, struct net_device *br_ptr)
  175. {
  176. igs_info_t *igs_info;
  177. osl_t *osh;
  178. uint8 proc_name[64];
  179. igsc_wrapper_t igsl;
  180. if (igs.inst_count > IGS_MAX_INST)
  181. {
  182. IGS_ERROR("Max instance limit %d exceeded\n", IGS_MAX_INST);
  183. return (NULL);
  184. }
  185. igs.inst_count++;
  186. IGS_INFO("Creating IGS instance for %s\n", inst_id);
  187. osh = osl_attach(NULL, PCI_BUS, FALSE);
  188. ASSERT(osh);
  189. /* Allocate os specfic IGS info object */
  190. igs_info = MALLOC(osh, sizeof(igs_info_t));
  191. if (igs_info == NULL)
  192. {
  193. IGS_ERROR("Out of memory allocating igs_info\n");
  194. osl_detach(osh);
  195. return (NULL);
  196. }
  197. igs_info->osh = osh;
  198. /* Save the IGS instance identifier */
  199. strncpy(igs_info->inst_id, inst_id, IFNAMSIZ);
  200. igs_info->inst_id[IFNAMSIZ - 1] = 0;
  201. /* Save the device pointer */
  202. igs_info->br_dev = br_ptr;
  203. /* Fill in linux specific wrapper functions*/
  204. igsl.igs_broadcast = (igs_broadcast_fn_ptr)igs_broadcast;
  205. /* Initialize IGSC layer */
  206. if ((igs_info->igsc_info = igsc_init(inst_id, (void *)igs_info, osh, &igsl)) == NULL)
  207. {
  208. IGS_ERROR("IGSC init failed\n");
  209. MFREE(osh, igs_info, sizeof(igs_info_t));
  210. osl_detach(osh);
  211. return (NULL);
  212. }
  213. #ifdef CONFIG_PROC_FS
  214. sprintf(proc_name, "net/igs_stats_%s", inst_id);
  215. create_proc_read_entry(proc_name, 0, 0, igs_stats_get, igs_info);
  216. sprintf(proc_name, "net/igsdb_%s", inst_id);
  217. create_proc_read_entry(proc_name, 0, 0, igs_sdb_list, igs_info);
  218. #endif /* CONFIG_PROC_FS */
  219. IGS_INFO("Created IGSC instance for %s\n", inst_id);
  220. /* Add to global IGS instance list */
  221. OSL_LOCK(igs.lock);
  222. igs_info->next = igs.list_head;
  223. igs.list_head = igs_info;
  224. OSL_UNLOCK(igs.lock);
  225. return (igs_info);
  226. }
  227. static int32
  228. igs_instance_del(igs_info_t *igs_info)
  229. {
  230. bool found = FALSE;
  231. osl_t *osh;
  232. igs_info_t *ptr, *prev;
  233. uint8 proc_name[64];
  234. OSL_LOCK(igs.lock);
  235. /* Delete the IGS instance */
  236. prev = NULL;
  237. for (ptr = igs.list_head; ptr != NULL; prev = ptr, ptr = ptr->next)
  238. {
  239. if (ptr == igs_info)
  240. {
  241. found = TRUE;
  242. if (prev != NULL)
  243. prev->next = ptr->next;
  244. else
  245. igs.list_head = NULL;
  246. break;
  247. }
  248. }
  249. OSL_UNLOCK(igs.lock);
  250. if (!found)
  251. {
  252. IGS_ERROR("IGS instance not found\n");
  253. return (FAILURE);
  254. }
  255. /* Free the IGS instance */
  256. igsc_exit(igs_info->igsc_info);
  257. #ifdef CONFIG_PROC_FS
  258. sprintf(proc_name, "net/igs_stats_%s", igs_info->inst_id);
  259. remove_proc_entry(proc_name, 0);
  260. sprintf(proc_name, "net/igsdb_%s", igs_info->inst_id);
  261. remove_proc_entry(proc_name, 0);
  262. #endif /* CONFIG_PROC_FS */
  263. osh = igs_info->osh;
  264. MFREE(igs_info->osh, igs_info, sizeof(igs_info_t));
  265. osl_detach(osh);
  266. return (SUCCESS);
  267. }
  268. static void
  269. igs_instances_clear(void)
  270. {
  271. igs_info_t *ptr, *tmp;
  272. OSL_LOCK(igs.lock);
  273. ptr = igs.list_head;
  274. while (ptr != NULL)
  275. {
  276. tmp = ptr->next;
  277. igs_instance_del(ptr);
  278. ptr = tmp;
  279. }
  280. OSL_UNLOCK(igs.lock);
  281. return;
  282. }
  283. static igs_info_t *
  284. igs_instance_find(int8 *inst_id)
  285. {
  286. igs_info_t *igs_info;
  287. ASSERT(inst_id != NULL);
  288. OSL_LOCK(igs.lock);
  289. for (igs_info = igs.list_head; igs_info != NULL; igs_info = igs_info->next)
  290. {
  291. if (strcmp(igs_info->inst_id, inst_id) == 0)
  292. {
  293. OSL_UNLOCK(igs.lock);
  294. return (igs_info);
  295. }
  296. }
  297. OSL_UNLOCK(igs.lock);
  298. return (NULL);
  299. }
  300. static void *
  301. igs_if_name_validate(uint8 *if_name)
  302. {
  303. struct net_device *dev;
  304. /* Get the interface pointer */
  305. dev = dev_get_by_name(if_name);
  306. if (dev == NULL)
  307. {
  308. IGS_ERROR("Interface %s doesn't exist\n", if_name);
  309. return (NULL);
  310. }
  311. dev_put(dev);
  312. return (dev);
  313. }
  314. /*
  315. * Description: This function handles the OS specific processing
  316. * required for configuration commands.
  317. *
  318. * Input: data - Configuration command parameters
  319. */
  320. void
  321. igs_cfg_request_process(igs_cfg_request_t *cfg)
  322. {
  323. igs_info_t *igs_info;
  324. struct net_device *br_ptr;
  325. if (cfg == NULL)
  326. {
  327. cfg->status = IGSCFG_STATUS_FAILURE;
  328. cfg->size = sprintf(cfg->arg, "Invalid input buffer passed\n");
  329. return;
  330. }
  331. /* Validate the instance identifier */
  332. br_ptr = igs_if_name_validate(cfg->inst_id);
  333. if (br_ptr == NULL)
  334. {
  335. cfg->status = IGSCFG_STATUS_FAILURE;
  336. cfg->size = sprintf(cfg->arg, "Unknown instance identifier %s\n",
  337. cfg->inst_id);
  338. return;
  339. }
  340. /* Locate the IGS instance */
  341. igs_info = igs_instance_find(cfg->inst_id);
  342. if ((igs_info == NULL) && (cfg->command_id != IGSCFG_CMD_BR_ADD))
  343. {
  344. cfg->status = IGSCFG_STATUS_FAILURE;
  345. cfg->size = sprintf(cfg->arg, "Invalid instance identifier %s\n",
  346. cfg->inst_id);
  347. return;
  348. }
  349. /* Convert the interface name in arguments to interface pointer */
  350. switch (cfg->command_id)
  351. {
  352. case IGSCFG_CMD_BR_ADD:
  353. if (igs_info != NULL)
  354. {
  355. cfg->status = IGSCFG_STATUS_FAILURE;
  356. cfg->size = sprintf(cfg->arg,
  357. "IGMP Snooping already enabled on %s\n",
  358. cfg->inst_id);
  359. return;
  360. }
  361. /* Create a new IGS instance corresponding to the bridge
  362. * interface.
  363. */
  364. igs_info = igs_instance_add(cfg->inst_id, br_ptr);
  365. if (igs_info == NULL)
  366. {
  367. cfg->status = IGSCFG_STATUS_FAILURE;
  368. cfg->size = sprintf(cfg->arg,
  369. "IGMP Snooping enable on %s failed\n",
  370. cfg->inst_id);
  371. return;
  372. }
  373. cfg->status = IGSCFG_STATUS_SUCCESS;
  374. break;
  375. case IGSCFG_CMD_BR_DEL:
  376. /* Delete and free the IGS instance */
  377. if (igs_instance_del(igs_info) != SUCCESS)
  378. {
  379. cfg->status = IGSCFG_STATUS_FAILURE;
  380. cfg->size = sprintf(cfg->arg,
  381. "IGMP Snooping disable failed\n");
  382. return;
  383. }
  384. cfg->status = IGSCFG_STATUS_SUCCESS;
  385. break;
  386. case IGSCFG_CMD_BR_LIST:
  387. break;
  388. default:
  389. igsc_cfg_request_process(igs_info->igsc_info, cfg);
  390. break;
  391. }
  392. return;
  393. }
  394. /*
  395. * Description: This function is called by Linux kernel when user
  396. * applications sends a message on netlink socket. It
  397. * dequeues the message, calls the functions to process
  398. * the commands and sends the result back to user.
  399. *
  400. * Input: skb - Kernel socket structure
  401. */
  402. static void
  403. igs_netlink_sock_cb(struct sk_buff *skb)
  404. {
  405. struct nlmsghdr *nlh;
  406. nlh = nlmsg_hdr(skb);
  407. IGS_DEBUG("Length of the command buffer %d\n", nlh->nlmsg_len);
  408. /* Check the buffer for min size */
  409. if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
  410. nlh->nlmsg_len < NLMSG_LENGTH(sizeof(igs_cfg_request_t)))
  411. {
  412. IGS_ERROR("Configuration request size not > %d\n",
  413. sizeof(igs_cfg_request_t));
  414. return;
  415. }
  416. skb = skb_clone(skb, GFP_KERNEL);
  417. if (skb == NULL)
  418. return;
  419. nlh = nlmsg_hdr(skb);
  420. /* Process the message */
  421. igs_cfg_request_process((igs_cfg_request_t *)NLMSG_DATA(nlh));
  422. /* Send the result to user process */
  423. NETLINK_CB(skb).pid = nlh->nlmsg_pid;
  424. NETLINK_CB(skb).dst_group = 0;
  425. netlink_unicast(igs.nl_sk, skb, nlh->nlmsg_pid, MSG_DONTWAIT);
  426. }
  427. /*
  428. * Description: This function is called during module load time. It
  429. * primarily allocates memory for IGS OS specific instance
  430. * data and calls the common code initialization function.
  431. */
  432. static int32 __init
  433. igs_module_init(void)
  434. {
  435. #define NETLINK_IGSC 18
  436. igs.nl_sk = netlink_kernel_create(NETLINK_IGSC, 0, igs_netlink_sock_cb,
  437. NULL, THIS_MODULE);
  438. if (igs.nl_sk == NULL)
  439. {
  440. IGS_ERROR("Netlink kernel socket create failed\n");
  441. return (FAILURE);
  442. }
  443. igs.lock = OSL_LOCK_CREATE("IGS Instance List");
  444. if (igs.lock == NULL)
  445. {
  446. IGS_ERROR("IGS instance list lock create failed\n");
  447. return (FAILURE);
  448. }
  449. return (SUCCESS);
  450. }
  451. static void __exit
  452. igs_module_exit(void)
  453. {
  454. sock_release(igs.nl_sk->sk_socket);
  455. igs_instances_clear();
  456. OSL_LOCK_DESTROY(igs.lock);
  457. return;
  458. }
  459. module_init(igs_module_init);
  460. module_exit(igs_module_exit);
  461. EXPORT_SYMBOL(igsc_init);
  462. EXPORT_SYMBOL(igsc_exit);
  463. EXPORT_SYMBOL(igsc_sdb_interface_del);
  464. EXPORT_SYMBOL(igsc_interface_rtport_del);