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#define uint32 unsigned long
35#define uint16 unsigned short
36#define uint unsigned int
37#define uint8 unsigned char
38#define uint64 unsigned long long
39#include <swapi.h>
40#include <nvports.h>
41
42
43#define MAX_HOSTNAME 256
44
45
46static char* usage =
47      "
48Usage: add             [interface-name] [vlan_id]
49       rem             [vlan-name]
50       set_flag        [interface-name] [flag-num]       [0 | 1]
51       set_egress_map  [vlan-name]      [skb_priority]   [vlan_qos]
52       set_ingress_map [vlan-name]      [skb_priority]   [vlan_qos]
53       set_name_type   [name-type]
54
55* The [interface-name] is the name of the ethernet card that hosts
56  the VLAN you are talking about.
57* The vlan_id is the identifier (0-4095) of the VLAN you are operating on.
58* skb_priority is the priority in the socket buffer (sk_buff).
59* vlan_qos is the 3 bit priority in the VLAN header
60* name-type:  VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5),
61              DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5)
62* bind-type:  PER_DEVICE  # Allows vlan 5 on eth0 and eth1 to be unique.
63              PER_KERNEL  # Forces vlan 5 to be unique across all devices.
64* FLAGS:  1 REORDER_HDR  When this is set, the VLAN device will move the
65            ethernet header around to make it look exactly like a real
66            ethernet device.  This may help programs such as DHCPd which
67            read the raw ethernet packet and make assumptions about the
68            location of bytes.  If you don't need it, don't turn it on, because
69            there will be at least a small performance degradation.  Default
70            is OFF.
71";
72
73void show_usage() {
74   fprintf(stdout,usage);
75}
76
77int hex_to_bytes(char* bytes, int bytes_length, char* hex_str) {
78   int hlen;
79   int i;
80
81   int j = 0;
82   char hex[3];
83   char* stop; /* not used for any real purpose */
84
85   hlen = strlen(hex_str);
86
87   hex[2] = 0;
88
89   for (i = 0; i<hlen; i++) {
90
91      hex[0] = hex_str[i];
92      i++;
93      if (i >= hlen) {
94         return j; /* done */
95      }
96
97      hex[1] = hex_str[i];
98      bytes[j++] = (char)strtoul(hex, &stop, 16);
99   }
100   return j;
101}
102
103
104int main(int argc, char** argv) {
105   int fd;
106   struct vlan_ioctl_args if_request;
107
108   char* cmd = NULL;
109   char* if_name = NULL;
110   unsigned int vid = 0;
111   unsigned int skb_priority;
112   unsigned short vlan_qos;
113   unsigned int nm_type = VLAN_NAME_TYPE_PLUS_VID;
114
115   char* conf_file_name = "/proc/net/vlan/config";
116   unsigned int  port = 0;
117   int retVal, port_enb, port_untag, ports_enable;
118   char *curptr = NULL;
119
120   memset(&if_request, 0, sizeof(struct vlan_ioctl_args));
121
122   if ((argc < 3) || (argc > 5)) {
123      fprintf(stdout,"Expecting argc to be 3-5, inclusive.  Was: %d\n",argc);
124
125      show_usage();
126      exit(1);
127   }
128   else {
129      cmd = argv[1];
130
131      if (strcasecmp(cmd, "set_name_type") == 0) {
132         if (strcasecmp(argv[2], "VLAN_PLUS_VID") == 0) {
133            nm_type = VLAN_NAME_TYPE_PLUS_VID;
134         }
135         else if (strcasecmp(argv[2], "VLAN_PLUS_VID_NO_PAD") == 0) {
136            nm_type = VLAN_NAME_TYPE_PLUS_VID_NO_PAD;
137         }
138         else if (strcasecmp(argv[2], "DEV_PLUS_VID") == 0) {
139            nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID;
140         }
141         else if (strcasecmp(argv[2], "DEV_PLUS_VID_NO_PAD") == 0) {
142            nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
143         }
144         else {
145            // MATHIEU
146                    //cerr << "Invalid name type.\n";
147            fprintf(stderr,"Invalid name type.\n");
148
149            show_usage();
150            exit(1);
151         }
152         if_request.u.name_type = nm_type;
153      }
154      else {
155         if_name = argv[2];
156         if (strlen(if_name) > 15) {
157            // MATHIEU
158                //cerr << "ERROR:  if_name must be 15 characters or less." << endl;
159            fprintf(stderr,"ERROR:  if_name must be 15 characters or less.\n");
160
161                        exit(1);
162         }
163         strcpy(if_request.device1, if_name);
164      }
165
166      if (argc == 4) {
167         vid = atoi(argv[3]);
168         if_request.u.VID = vid;
169      }
170
171      if (argc == 5) {
172         skb_priority = atoi(argv[3]);
173         vlan_qos = atoi(argv[4]);
174         if_request.u.skb_priority = skb_priority;
175         if_request.vlan_qos = vlan_qos;
176      }
177   }
178
179   // Open up the /proc/vlan/config
180   if ((fd = open(conf_file_name, O_RDONLY)) < 0) {
181      // MATHIEU
182      //cerr << "ERROR:  Could not open /proc/vlan/config.\n";
183      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");
184
185   }
186   else {
187      close(fd);
188   }
189
190   /* We use sockets now, instead of the file descriptor */
191   if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
192      fprintf(stderr, "FATAL:  Couldn't open a socket..go figure!\n");
193      exit(2);
194   }
195
196   /* add */
197   if (strcasecmp(cmd, "add") == 0) {
198      if_request.cmd = ADD_VLAN_CMD;
199      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
200         fprintf(stderr,"ERROR: trying to add VLAN #%u to IF -:%s:-  error: %s\n",
201                    vid, if_name, strerror(errno));
202      }
203      else {
204
205         if ((bcm_api_init())<0) {
206             fprintf(stderr,"No Robo device found\n");
207         }
208         else
209         {
210             if (BCM_RET_SUCCESS != (retVal = bcm_vlan_create(0,vid)))
211             {
212                 fprintf(stderr,"ERROR: trying to create VLAN #%u for switch\n", vid);
213             }
214             else
215             {
216         	fprintf(stdout,"Added VLAN with VID == %u to IF -:%s:-\n",
217                 	vid, if_name);
218         	if (vid == 1) {
219            		fprintf(stdout, "WARNING:  VLAN 1 does not work with many switches,\nconsider another number if you have problems.\n");
220         	}
221             }
222             bcm_api_deinit();
223         }
224
225      }
226   }//if
227   else if (strcasecmp(cmd, "rem") == 0) {
228      if_request.cmd = DEL_VLAN_CMD;
229      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
230         fprintf(stderr,"ERROR: trying to remove VLAN -:%s:- error: %s\n",
231                 if_name, strerror(errno));
232      }
233      else {
234         if ((bcm_api_init())<0) {
235             fprintf(stderr,"No Robo device found\n");
236         }
237         else
238         {
239             /* get vid from interface name */
240             if ((curptr = strrchr(if_name,'.'))) {
241               if (!sscanf(++curptr,"%d",&vid))
242                 vid = 0;
243             } else
244                vid = 0;
245             if (BCM_RET_SUCCESS != (retVal = bcm_vlan_create(0,vid)))
246             {
247                 fprintf(stderr,"ERROR: trying to remove VLAN #%u for switch\n", vid);
248             }
249             else
250             {
251         		fprintf(stdout,"Removed VLAN -:%s:-\n", if_name);
252             }
253             bcm_api_deinit();
254         }
255      }
256   }//if
257   else if (strcasecmp(cmd, "set_egress_map") == 0) {
258      if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
259      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
260         fprintf(stderr,"ERROR: trying to set egress map on device -:%s:- error: %s\n",
261                 if_name, strerror(errno));
262      }
263      else {
264         fprintf(stdout,"Set egress mapping on device -:%s:- "
265                 "Should be visible in /proc/net/vlan/%s\n",
266                 if_name, if_name);
267      }
268   }
269   else if (strcasecmp(cmd, "set_ingress_map") == 0) {
270      if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
271      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
272         fprintf(stderr,"ERROR: trying to set ingress map on device -:%s:- error: %s\n",
273                 if_name, strerror(errno));
274      }
275      else {
276         fprintf(stdout,"Set ingress mapping on device -:%s:- "
277                 "Should be visible in /proc/net/vlan/%s\n",
278                 if_name, if_name);
279      }
280   }
281   else if (strcasecmp(cmd, "set_flag") == 0) {
282      if_request.cmd = SET_VLAN_FLAG_CMD;
283      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
284         fprintf(stderr,"ERROR: trying to set flag on device -:%s:- error: %s\n",
285                 if_name, strerror(errno));
286      }
287      else {
288         fprintf(stdout,"Set flag on device -:%s:- "
289                 "Should be visible in /proc/net/vlan/%s\n",
290                 if_name, if_name);
291      }
292   }
293   else if (strcasecmp(cmd, "set_name_type") == 0) {
294      if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
295      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
296         fprintf(stderr,"ERROR: trying to set name type for VLAN subsystem, error: %s\n",
297                 strerror(errno));
298      }
299      else {
300         fprintf(stdout,"Set name-type for VLAN subsystem."
301                 " Should be visible in /proc/net/vlan/config\n");
302      }
303   }
304   else if (strcasecmp(cmd, "add_port") == 0 || strcasecmp(cmd, "add_port_nountag") == 0
305        || strcasecmp(cmd, "add_port_nountag_nodeftag") == 0) {
306      /* enable port for this vlan id */
307      vid = atoi(argv[2]);
308      port = atoi(argv[3]);
309      port_enb = PBMP_PORT((port-1));
310      /* if add_port_nountag don't untag */
311      if (strcasecmp(cmd, "add_port_nountag") == 0
312	|| nvExistsPortAttrib("native",port)
313        || strcasecmp(cmd, "add_port_nountag_nodeftag") == 0)
314         port_untag = 0;
315      else
316         port_untag = PBMP_PORT((port-1));
317      if (port < BCM_MIN_PORT || port > BCM_MAX_PORT)
318      {
319         fprintf(stderr,"ERROR: invalid port number, must be between %d and %d\n",
320                 BCM_MIN_PORT,BCM_MAX_PORT);
321      }
322      if ((bcm_api_init())<0) {
323          fprintf(stderr,"No Robo device found\n");
324      }
325      else
326      {
327        if (strcasecmp(cmd, "add_port_nountag_nodeftag") == 0)
328        {
329            if (BCM_RET_SUCCESS != (retVal = bcm_vlan_port_add(0,vid,port_enb,port_untag,0))){
330              fprintf(stderr,"Error trying to add port\n");
331            }
332        }
333        else
334        {
335            if (BCM_RET_SUCCESS != (retVal = bcm_vlan_port_add(0,vid,port_enb,port_untag,1))){
336              fprintf(stderr,"Error trying to add port\n");
337            }
338        }
339        bcm_api_deinit();
340      }
341   }//if
342   else if (strcasecmp(cmd, "ports_enable") == 0) {
343      /* activate vlans in switch */
344      ports_enable = atoi(argv[2]);
345      if (ports_enable > 1 || ports_enable < 0)
346      {
347         fprintf(stderr,"ERROR: invalid port enable, must be 0 or 1\n");
348      }
349      if ((bcm_api_init())<0) {
350          fprintf(stderr,"No Robo device found\n");
351      }
352      else
353      {
354        if (BCM_RET_SUCCESS != (retVal =bcm_vlan_enable(0,ports_enable))){
355          fprintf(stderr,"Error trying to enable ports\n");
356        }
357        bcm_api_deinit();
358      }
359   }
360   else {
361      fprintf(stderr, "Unknown command -:%s:-\n", cmd);
362
363      show_usage();
364      exit(5);
365   }
366
367   return 0;
368}/* main */
369