vconfig.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * vconfig implementation for busybox
  4. *
  5. * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. */
  22. /* BB_AUDIT SUSv3 N/A */
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26. #include <sys/ioctl.h>
  27. #include <net/if.h>
  28. #include <string.h>
  29. #include <limits.h>
  30. #include "busybox.h"
  31. /* Stuff from linux/if_vlan.h, kernel version 2.4.23 */
  32. enum vlan_ioctl_cmds {
  33. ADD_VLAN_CMD,
  34. DEL_VLAN_CMD,
  35. SET_VLAN_INGRESS_PRIORITY_CMD,
  36. SET_VLAN_EGRESS_PRIORITY_CMD,
  37. GET_VLAN_INGRESS_PRIORITY_CMD,
  38. GET_VLAN_EGRESS_PRIORITY_CMD,
  39. SET_VLAN_NAME_TYPE_CMD,
  40. SET_VLAN_FLAG_CMD
  41. };
  42. enum vlan_name_types {
  43. VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */
  44. VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */
  45. VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */
  46. VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */
  47. VLAN_NAME_TYPE_HIGHEST
  48. };
  49. struct vlan_ioctl_args {
  50. int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
  51. char device1[24];
  52. union {
  53. char device2[24];
  54. int VID;
  55. unsigned int skb_priority;
  56. unsigned int name_type;
  57. unsigned int bind_type;
  58. unsigned int flag; /* Matches vlan_dev_info flags */
  59. } u;
  60. short vlan_qos;
  61. };
  62. #define VLAN_GROUP_ARRAY_LEN 4096
  63. #define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */
  64. /* On entry, table points to the length of the current string plus
  65. * nul terminator plus data length for the subsequent entry. The
  66. * return value is the last data entry for the matching string. */
  67. static const char *xfind_str(const char *table, const char *str)
  68. {
  69. while (strcasecmp(str, table+1) != 0) {
  70. if (!*(table += table[0])) {
  71. bb_show_usage();
  72. }
  73. }
  74. return table - 1;
  75. }
  76. static const char cmds[] = {
  77. 4, ADD_VLAN_CMD, 7,
  78. 'a', 'd', 'd', 0,
  79. 3, DEL_VLAN_CMD, 7,
  80. 'r', 'e', 'm', 0,
  81. 3, SET_VLAN_NAME_TYPE_CMD, 17,
  82. 's', 'e', 't', '_',
  83. 'n', 'a', 'm', 'e', '_',
  84. 't', 'y', 'p', 'e', 0,
  85. 4, SET_VLAN_FLAG_CMD, 12,
  86. 's', 'e', 't', '_',
  87. 'f', 'l', 'a', 'g', 0,
  88. 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18,
  89. 's', 'e', 't', '_',
  90. 'e', 'g', 'r', 'e', 's', 's', '_',
  91. 'm', 'a', 'p', 0,
  92. 5, SET_VLAN_INGRESS_PRIORITY_CMD, 16,
  93. 's', 'e', 't', '_',
  94. 'i', 'n', 'g', 'r', 'e', 's', 's', '_',
  95. 'm', 'a', 'p', 0,
  96. };
  97. static const char name_types[] = {
  98. VLAN_NAME_TYPE_PLUS_VID, 16,
  99. 'V', 'L', 'A', 'N',
  100. '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
  101. 0,
  102. VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22,
  103. 'V', 'L', 'A', 'N',
  104. '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
  105. '_', 'N', 'O', '_', 'P', 'A', 'D', 0,
  106. VLAN_NAME_TYPE_RAW_PLUS_VID, 15,
  107. 'D', 'E', 'V',
  108. '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
  109. 0,
  110. VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 20,
  111. 'D', 'E', 'V',
  112. '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
  113. '_', 'N', 'O', '_', 'P', 'A', 'D', 0,
  114. };
  115. static const char conf_file_name[] = "/proc/net/vlan/config";
  116. int vconfig_main(int argc, char **argv)
  117. {
  118. struct vlan_ioctl_args ifr;
  119. const char *p;
  120. int fd;
  121. if (argc < 3) {
  122. bb_show_usage();
  123. }
  124. /* Don't bother closing the filedes. It will be closed on cleanup. */
  125. if (open(conf_file_name, O_RDONLY) < 0) { /* Is 802.1q is present? */
  126. bb_perror_msg_and_die("open %s", conf_file_name);
  127. }
  128. memset(&ifr, 0, sizeof(struct vlan_ioctl_args));
  129. ++argv;
  130. p = xfind_str(cmds+2, *argv);
  131. ifr.cmd = *p;
  132. if (argc != p[-1]) {
  133. bb_show_usage();
  134. }
  135. if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */
  136. ifr.u.name_type = *xfind_str(name_types+1, argv[1]);
  137. } else {
  138. if (strlen(argv[1]) >= IF_NAMESIZE) {
  139. bb_error_msg_and_die("if_name >= %d chars\n", IF_NAMESIZE);
  140. }
  141. strcpy(ifr.device1, argv[1]);
  142. p = argv[2];
  143. /* I suppose one could try to combine some of the function calls below,
  144. * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized
  145. * (unsigned) int members of a unions. But because of the range checking,
  146. * doing so wouldn't save that much space and would also make maintainence
  147. * more of a pain. */
  148. if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */
  149. ifr.u.flag = bb_xgetularg10_bnd(p, 0, 1);
  150. } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */
  151. ifr.u.VID = bb_xgetularg10_bnd(p, 0, VLAN_GROUP_ARRAY_LEN-1);
  152. } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */
  153. ifr.u.skb_priority = bb_xgetularg10_bnd(p, 0, ULONG_MAX);
  154. ifr.vlan_qos = bb_xgetularg10_bnd(argv[3], 0, 7);
  155. }
  156. }
  157. if (((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  158. || (ioctl(fd, SIOCSIFVLAN, &ifr) < 0)
  159. ) {
  160. bb_perror_msg_and_die("socket or ioctl error for %s", *argv);
  161. }
  162. return 0;
  163. }