1//
2//Copyright (C) 2001  Ben Greear
3//
4//This program is free software; you can redistribute it and/or
5//modify it under the terms of the GNU Library General Public License
6//as published by the Free Software Foundation; either version 2
7//of the License, or (at your option) any later version.
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.  See the
12//GNU General Public License for more details.
13//
14//You should have received a copy of the GNU Library General Public License
15//along with this program; if not, write to the Free Software
16//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17//
18// To contact the Author, Ben Greear:  greearb@candelatech.com
19//
20
21
22#include <errno.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <strings.h>
28#include <sys/ioctl.h>
29#include <linux/if_vlan.h>
30#include <linux/sockios.h>
31#include <string.h>
32#include <sys/socket.h>
33#include <sys/types.h>
34
35
36#define MAX_HOSTNAME 256
37
38
39static char* usage = \
40"Usage: add             [interface-name] [vlan_id]\n"
41"       rem             [vlan-name]\n"
42"       set_flag        [interface-name] [flag-num]       [0 | 1]\n"
43"       set_egress_map  [vlan-name]      [skb_priority]   [vlan_qos]\n"
44"       set_ingress_map [vlan-name]      [skb_priority]   [vlan_qos]\n"
45"       set_name_type   [name-type]\n"
46"\n"
47"* The [interface-name] is the name of the ethernet card that hosts\n"
48"  the VLAN you are talking about.\n"
49"* The vlan_id is the identifier (0-4095) of the VLAN you are operating on.\n"
50"* skb_priority is the priority in the socket buffer (sk_buff).\n"
51"* vlan_qos is the 3 bit priority in the VLAN header\n"
52"* name-type:  VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5),\n"
53"              DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5)\n"
54"* bind-type:  PER_DEVICE  # Allows vlan 5 on eth0 and eth1 to be unique.\n"
55"              PER_KERNEL  # Forces vlan 5 to be unique across all devices.\n"
56"* FLAGS:  1 REORDER_HDR  When this is set, the VLAN device will move the\n"
57"            ethernet header around to make it look exactly like a real\n"
58"            ethernet device.  This may help programs such as DHCPd which\n"
59"            read the raw ethernet packet and make assumptions about the\n"
60"            location of bytes.  If you don't need it, don't turn it on, because\n"
61"            there will be at least a small performance degradation.  Default\n"
62"            is OFF.\n";
63
64void show_usage() {
65   fprintf(stdout,usage);
66}
67
68int hex_to_bytes(char* bytes, int bytes_length, char* hex_str) {
69   int hlen;
70   int i;
71
72   int j = 0;
73   char hex[3];
74   char* stop; /* not used for any real purpose */
75
76   hlen = strlen(hex_str);
77
78   hex[2] = 0;
79
80   for (i = 0; i<hlen; i++) {
81
82      hex[0] = hex_str[i];
83      i++;
84      if (i >= hlen) {
85         return j; /* done */
86      }
87
88      hex[1] = hex_str[i];
89      bytes[j++] = (char)strtoul(hex, &stop, 16);
90   }
91   return j;
92}
93
94
95int main(int argc, char** argv) {
96   int fd;
97   struct vlan_ioctl_args if_request;
98
99   char* cmd = NULL;
100   char* if_name = NULL;
101   unsigned int vid = 0;
102   unsigned int skb_priority;
103   unsigned short vlan_qos;
104   unsigned int nm_type = VLAN_NAME_TYPE_PLUS_VID;
105
106   char* conf_file_name = "/proc/net/vlan/config";
107
108   memset(&if_request, 0, sizeof(struct vlan_ioctl_args));
109
110   if ((argc < 3) || (argc > 5)) {
111      fprintf(stdout,"Expecting argc to be 3-5, inclusive.  Was: %d\n",argc);
112
113      show_usage();
114      exit(1);
115   }
116   else {
117      cmd = argv[1];
118
119      if (strcasecmp(cmd, "set_name_type") == 0) {
120         if (strcasecmp(argv[2], "VLAN_PLUS_VID") == 0) {
121            nm_type = VLAN_NAME_TYPE_PLUS_VID;
122         }
123         else if (strcasecmp(argv[2], "VLAN_PLUS_VID_NO_PAD") == 0) {
124            nm_type = VLAN_NAME_TYPE_PLUS_VID_NO_PAD;
125         }
126         else if (strcasecmp(argv[2], "DEV_PLUS_VID") == 0) {
127            nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID;
128         }
129         else if (strcasecmp(argv[2], "DEV_PLUS_VID_NO_PAD") == 0) {
130            nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
131         }
132         else {
133            // MATHIEU
134                    //cerr << "Invalid name type.\n";
135            fprintf(stderr,"Invalid name type.\n");
136
137            show_usage();
138            exit(1);
139         }
140         if_request.u.name_type = nm_type;
141      }
142      else {
143         if_name = argv[2];
144         if (strlen(if_name) > 15) {
145            // MATHIEU
146                //cerr << "ERROR:  if_name must be 15 characters or less." << endl;
147            fprintf(stderr,"ERROR:  if_name must be 15 characters or less.\n");
148
149                        exit(1);
150         }
151         strcpy(if_request.device1, if_name);
152      }
153
154      if (argc == 4) {
155         vid = atoi(argv[3]);
156         if_request.u.VID = vid;
157      }
158
159      if (argc == 5) {
160         skb_priority = atoi(argv[3]);
161         vlan_qos = atoi(argv[4]);
162         if_request.u.skb_priority = skb_priority;
163         if_request.vlan_qos = vlan_qos;
164      }
165   }
166
167   // Open up the /proc/vlan/config
168   if ((fd = open(conf_file_name, O_RDONLY)) < 0) {
169      // MATHIEU
170      //cerr << "ERROR:  Could not open /proc/vlan/config.\n";
171      fprintf(stderr,"WARNING:  Could not open /proc/net/vlan/config.  Maybe you need to load the 8021q module, or maybe you are not using PROCFS??\n");
172
173   }
174   else {
175      close(fd);
176   }
177
178   /* We use sockets now, instead of the file descriptor */
179   if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
180      fprintf(stderr, "FATAL:  Couldn't open a socket..go figure!\n");
181      exit(2);
182   }
183
184   /* add */
185   if (strcasecmp(cmd, "add") == 0) {
186      if_request.cmd = ADD_VLAN_CMD;
187      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
188         fprintf(stderr,"ERROR: trying to add VLAN #%u to IF -:%s:-  error: %s\n",
189                    vid, if_name, strerror(errno));
190      }
191   }//if
192   else if (strcasecmp(cmd, "rem") == 0) {
193      if_request.cmd = DEL_VLAN_CMD;
194      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
195         fprintf(stderr,"ERROR: trying to remove VLAN -:%s:- error: %s\n",
196                 if_name, strerror(errno));
197      }
198   }//if
199   else if (strcasecmp(cmd, "set_egress_map") == 0) {
200      if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
201      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
202         fprintf(stderr,"ERROR: trying to set egress map on device -:%s:- error: %s\n",
203                 if_name, strerror(errno));
204      }
205   }
206   else if (strcasecmp(cmd, "set_ingress_map") == 0) {
207      if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
208      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
209         fprintf(stderr,"ERROR: trying to set ingress map on device -:%s:- error: %s\n",
210                 if_name, strerror(errno));
211      }
212   }
213   else if (strcasecmp(cmd, "set_flag") == 0) {
214      if_request.cmd = SET_VLAN_FLAG_CMD;
215      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
216         fprintf(stderr,"ERROR: trying to set flag on device -:%s:- error: %s\n",
217                 if_name, strerror(errno));
218      }
219   }
220   else if (strcasecmp(cmd, "set_name_type") == 0) {
221      if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
222      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
223         fprintf(stderr,"ERROR: trying to set name type for VLAN subsystem, error: %s\n",
224                 strerror(errno));
225      }
226   }
227   else {
228      fprintf(stderr, "Unknown command -:%s:-\n", cmd);
229
230      show_usage();
231      exit(5);
232   }
233
234   return 0;
235}/* main */
236