tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_switch / port.c
blob94c566095bfbe6ddf1e63f91e57ca19183e7b6c5
1 /* Copyright 2005 Renzo Davoli VDE-2
2 * 2008 Luca Saiu (Marionnet project): a better hub implementation
3 * Some minor remain from uml_switch Copyright 2002 Yon Uriarte and Jeff Dike
4 * Licensed under the GPLv2
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <netinet/in.h> /*ntoh conversion*/
16 #include <sys/types.h>
17 #include <grp.h>
18 #include <pwd.h>
19 #include <ctype.h>
21 #include <config.h>
22 #include <vde.h>
23 #include <vdecommon.h>
25 #include "switch.h"
26 #include "hash.h"
27 #include "qtimer.h"
28 #include "port.h"
29 #include "fcntl.h"
30 #include "consmgmt.h"
31 #include "bitarray.h"
32 #include "fstp.h"
34 #include "packetq.h"
36 static int pflag=0;
37 static int numports;
38 #ifdef VDE_PQ2
39 static int stdqlen=128;
40 #endif
42 static struct port **portv;
44 #ifdef DEBUGOPT
45 #define DBGPORTNEW (dl)
46 #define DBGPORTDEL (dl+1)
47 #define DBGPORTDESCR (dl+2)
48 #define DBGEPNEW (dl+3)
49 #define DBGEPDEL (dl+4)
50 #define PKTFILTIN (dl+5)
51 #define PKTFILTOUT (dl+6)
52 static struct dbgcl dl[]= {
53 {"port/+","new port",D_PORT|D_PLUS},
54 {"port/-","closed port",D_PORT|D_MINUS},
55 {"port/descr","set port description",D_PORT|D_DESCR},
56 {"port/ep/+","new endpoint",D_EP|D_PLUS},
57 {"port/ep/-","closed endpoint",D_EP|D_MINUS},
58 {"packet/in",NULL,D_PACKET|D_IN},
59 {"packet/out",NULL,D_PACKET|D_OUT},
61 #endif
63 // for dedugging if needed
66 void packet_dump (struct packet *p)
68 register int i;
69 printf ("packet dump dst");
70 for (i=0;i<ETH_ALEN;i++)
71 printf(":%02x",p->header.dest[i]);
72 printf(" src");
73 for (i=0;i<ETH_ALEN;i++)
74 printf(":%02x",p->header.src[i]);
75 printf(" proto");
76 for (i=0;i<2;i++)
77 printf(":%02x",p->header.proto[i]);
78 printf("\n");
79 }*/
81 struct endpoint {
82 int port;
83 int fd_ctl;
84 int fd_data;
85 char *descr;
86 #ifdef VDE_PQ2
87 struct vdepq *vdepq;
88 int vdepq_count;
89 int vdepq_max;
90 #endif
91 struct endpoint *next;
94 #define NOTINPOOL 0x8000
96 struct port {
97 struct endpoint *ep;
98 int flag;
99 /* sender is already inside ms, but it needs one more memaccess */
100 int (*sender)(int fd_ctl, int fd_data, void *packet, int len, int port);
101 struct mod_support *ms;
102 int vlanuntag;
103 uid_t user;
104 gid_t group;
105 uid_t curuser;
106 #ifdef FSTP
107 int cost;
108 #endif
109 #ifdef PORTCOUNTERS
110 long long pktsin,pktsout,bytesin,bytesout;
111 #endif
114 /* VLAN MANAGEMENT:
115 * table the vlan table (also for inactive ports)
116 * vlan bctag is the vlan table -- only tagged forwarding ports mapping
117 * vlan bcuntag is the vlan table -- only untagged forwarding ports mapping
118 * validvlan is the table of valid vlans
121 struct {
122 bitarray table;
123 bitarray bctag;
124 bitarray bcuntag;
125 bitarray notlearning;
126 } vlant[NUMOFVLAN+1];
127 bitarray validvlan;
129 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
132 static int alloc_port(unsigned int portno)
134 int i=portno;
135 if (i==0) {
136 /* take one */
137 for (i=1;i<numports && portv[i] != NULL &&
138 (portv[i]->ep != NULL || portv[i]->flag & NOTINPOOL) ;i++)
140 } else if (i<0) /* special case MGMT client port */
141 i=0;
142 if (i >= numports)
143 return -1;
144 else {
145 if (portv[i] == NULL) {
146 struct port *port;
147 if ((port = malloc(sizeof(struct port))) == NULL){
148 printlog(LOG_WARNING,"malloc port %s",strerror(errno));
149 return -1;
150 } else
152 DBGOUT(DBGPORTNEW,"%02d", i);
153 EVENTOUT(DBGPORTNEW,i);
155 portv[i]=port;
156 port->ep=NULL;
157 port->user=port->group=port->curuser=-1;
158 #ifdef FSTP
159 port->cost=DEFAULT_COST;
160 #endif
161 #ifdef PORTCOUNTERS
162 port->pktsin=0;
163 port->pktsout=0;
164 port->bytesin=0;
165 port->bytesout=0;
166 #endif
167 port->flag=0;
168 port->sender=NULL;
169 port->vlanuntag=0;
170 ba_set(vlant[0].table,i);
173 return i;
177 static void free_port(unsigned int portno)
179 if (portno < numports) {
180 struct port *port=portv[portno];
181 if (port != NULL && port->ep==NULL) {
182 portv[portno]=NULL;
183 register int i;
184 /* delete completely the port. all vlan defs zapped */
185 bac_FORALL(validvlan,NUMOFVLAN,ba_clr(vlant[i].table,portno),i);
186 free(port);
191 /* 1 if user belongs to the group, 0 otherwise) */
192 static int user_belongs_to_group(uid_t uid, gid_t gid)
194 struct passwd *pw=getpwuid(uid);
195 if (pw == NULL)
196 return 0;
197 else {
198 if (gid==pw->pw_gid)
199 return 1;
200 else {
201 struct group *grp;
202 setgrent();
203 while ((grp = getgrent())) {
204 if (grp->gr_gid == gid) {
205 int i;
206 for (i = 0; grp->gr_mem[i]; i++) {
207 if (strcmp(grp->gr_mem[i], pw->pw_name)==0) {
208 endgrent();
209 return 1;
214 endgrent();
215 return 0;
221 /* Access Control check:
222 returns 0->OK -1->Permission Denied */
223 static int checkport_ac(struct port *port, uid_t user)
225 /*unrestricted*/
226 if (port->user == -1 && port->group == -1)
227 return 0;
228 /*root or restricted to a specific user*/
229 else if (user==0 || (port->user != -1 && port->user==user))
230 return 0;
231 /*restricted to a group*/
232 else if (port->group != -1 && user_belongs_to_group(user,port->group))
233 return 0;
234 else {
235 errno=EPERM;
236 return -1;
240 /* initialize a new endpoint */
241 struct endpoint *setup_ep(int portno, int fd_ctl, int fd_data, uid_t user,
242 struct mod_support *modfun)
244 struct port *port;
245 struct endpoint *ep;
247 if ((portno = alloc_port(portno)) >= 0) {
248 port=portv[portno];
249 if (port->ep == NULL && checkport_ac(port,user)==0)
250 port->curuser=user;
251 if (port->curuser == user &&
252 (ep=malloc(sizeof(struct endpoint))) != NULL) {
253 DBGOUT(DBGEPNEW,"Port %02d FD %2d", portno,fd_ctl);
254 EVENTOUT(DBGEPNEW,portno,fd_ctl);
255 port->ms=modfun;
256 port->sender=modfun->sender;
257 ep->port=portno;
258 ep->fd_ctl=fd_ctl;
259 ep->fd_data=fd_data;
260 ep->descr=NULL;
261 #ifdef VDE_PQ2
262 ep->vdepq=NULL;
263 ep->vdepq_count=0;
264 ep->vdepq_max=stdqlen;
265 #endif
266 if(port->ep == NULL) {/* WAS INACTIVE */
267 register int i;
268 /* copy all the vlan defs to the active vlan defs */
269 ep->next=port->ep;
270 port->ep=ep;
271 bac_FORALL(validvlan,NUMOFVLAN,
272 ({if (ba_check(vlant[i].table,portno)) {
273 ba_set(vlant[i].bctag,portno);
274 #ifdef FSTP
275 fstaddport(i,portno,(i!=port->vlanuntag));
276 #endif
278 }),i);
279 if (port->vlanuntag != NOVLAN) {
280 ba_set(vlant[port->vlanuntag].bcuntag,portno);
281 ba_clr(vlant[port->vlanuntag].bctag,portno);
283 ba_clr(vlant[port->vlanuntag].notlearning,portno);
284 } else {
285 ep->next=port->ep;
286 port->ep=ep;
288 return ep;
290 else {
291 if (port->curuser != user)
292 errno=EADDRINUSE;
293 else
294 errno=ENOMEM;
295 return NULL;
298 else {
299 errno=ENOMEM;
300 return NULL;
304 int ep_get_port(struct endpoint *ep)
306 return ep->port;
309 void setup_description(struct endpoint *ep, char *descr)
311 DBGOUT(DBGPORTDESCR,"Port %02d FD %2d -> \"%s\"",ep->port,ep->fd_ctl,descr);
312 EVENTOUT(DBGPORTDESCR,ep->port,ep->fd_ctl,descr);
313 ep->descr=descr;
316 static int rec_close_ep(struct endpoint **pep, int fd_ctl)
318 struct endpoint *this=*pep;
319 if (this != NULL) {
320 if (this->fd_ctl==fd_ctl) {
321 DBGOUT(DBGEPDEL,"Port %02d FD %2d",this->port,fd_ctl);
322 EVENTOUT(DBGEPDEL,this->port,fd_ctl);
323 *pep=this->next;
324 #ifdef VDE_PQ2
325 vdepq_del(&(this->vdepq));
326 #endif
327 if (portv[this->port]->ms->delep)
328 portv[this->port]->ms->delep(this->fd_ctl,this->fd_data,this->descr);
329 free(this);
330 return 0;
331 } else
332 return rec_close_ep(&(this->next),fd_ctl);
333 } else
334 return ENXIO;
337 static int close_ep_port_fd(int portno, int fd_ctl)
339 if (portno >=0 && portno < numports) {
340 struct port *port=portv[portno];
341 if (port != NULL) {
342 int rv=rec_close_ep(&(port->ep),fd_ctl);
343 if (port->ep == NULL) {
344 DBGOUT(DBGPORTDEL,"%02d",portno);
345 EVENTOUT(DBGPORTDEL,portno);
346 hash_delete_port(portno);
347 port->ms=NULL;
348 port->sender=NULL;
349 port->curuser=-1;
350 register int i;
351 /* inactivate port: all active vlan defs cleared */
352 bac_FORALL(validvlan,NUMOFVLAN,({
353 ba_clr(vlant[i].bctag,portno);
354 #ifdef FSTP
355 fstdelport(i,portno);
356 #endif
357 }),i);
358 if (port->vlanuntag < NOVLAN) ba_clr(vlant[port->vlanuntag].bcuntag,portno);
360 return rv;
361 } else
362 return ENXIO;
363 } else
364 return EINVAL;
367 int close_ep(struct endpoint *ep)
369 return close_ep_port_fd(ep->port, ep->fd_ctl);
372 #ifdef VDE_PQ2
373 static int rec_setqlen_ep(struct endpoint *ep, int fd_ctl, int len)
375 struct endpoint *this=ep;
376 if (this != NULL) {
377 if (this->fd_ctl==fd_ctl) {
378 ep->vdepq_max = len;
379 return 0;
380 } else
381 return rec_setqlen_ep(this->next, fd_ctl, len);
382 } else
383 return ENXIO;
386 static int setqlen_ep_port_fd(int portno, int fd_ctl, int len)
388 if (portno >=0 && portno < numports) {
389 struct port *port=portv[portno];
390 if (port != NULL) {
391 return rec_setqlen_ep(port->ep, fd_ctl, len);
393 else
394 return ENXIO;
395 } else
396 return EINVAL;
398 #endif
400 int portflag(int op,int f)
402 int oldflag=pflag;
403 switch(op) {
404 case P_GETFLAG: oldflag = pflag & f; break;
405 case P_SETFLAG: pflag=f; break;
406 case P_ADDFLAG: pflag |= f; break;
407 case P_CLRFLAG: pflag &= ~f; break;
409 return oldflag;
413 /*********************** sending macro used by Core ******************/
415 /* VDBG counter: count[port].spacket++; count[port].sbytes+=len */
416 #ifdef PORTCOUNTERS
417 #define SEND_COUNTER_UPD(Port,LEN) ({Port->pktsout++; Port->bytesout +=len;})
418 #else
419 #define SEND_COUNTER_UPD(Port,LEN)
420 #endif
422 #ifndef VDE_PQ2
423 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
425 struct port *Port=(PORT); \
426 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
427 struct endpoint *ep; \
428 SEND_COUNTER_UPD(Port,LEN); \
429 for (ep=Port->ep; ep != NULL; ep=ep->next) \
430 Port->ms->sender(ep->fd_ctl, ep->fd_data, (PACKET), (LEN), ep->port); \
433 #else
434 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN,TMPBUF) \
436 struct port *Port=(PORT); \
437 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
438 struct endpoint *ep; \
439 SEND_COUNTER_UPD(Port,LEN); \
440 for (ep=Port->ep; ep != NULL; ep=ep->next) \
441 if (ep->vdepq_count || \
442 Port->ms->sender(ep->fd_ctl, ep->fd_data, (PACKET), (LEN), ep->port) == -EWOULDBLOCK) {\
443 if (ep->vdepq_count < ep->vdepq_max) \
444 ep->vdepq_count += vdepq_add(&(ep->vdepq), (PACKET), (LEN), TMPBUF); \
445 if (ep->vdepq_count == 1) mainloop_pollmask_add(ep->fd_data, POLLOUT);\
449 #endif
451 #ifdef FSTP
453 /* functions for FSTP */
454 void port_send_packet(int portno, void *packet, int len)
456 #ifndef VDE_PQ2
457 SEND_PACKET_PORT(portv[portno],portno,packet,len);
458 #else
459 void *tmpbuf=NULL;
460 SEND_PACKET_PORT(portv[portno],portno,packet,len,&tmpbuf);
461 #endif
464 void portset_send_packet(bitarray portset, void *packet, int len)
466 register int i;
467 #ifndef VDE_PQ2
468 ba_FORALL(portset,numports,
469 SEND_PACKET_PORT(portv[i],i,packet,len), i);
470 #else
471 void *tmpbuf=NULL;
472 ba_FORALL(portset,numports,
473 SEND_PACKET_PORT(portv[i],i,packet,len,&tmpbuf), i);
474 #endif
478 void port_set_status(int portno, int vlan, int status)
480 if (ba_check(vlant[vlan].table,portno)) {
481 if (status==DISCARDING) {
482 ba_set(vlant[vlan].notlearning,portno);
483 ba_clr(vlant[vlan].bctag,portno);
484 ba_clr(vlant[vlan].bcuntag,portno);
485 } else if (status==LEARNING) {
486 ba_clr(vlant[vlan].notlearning,portno);
487 ba_clr(vlant[vlan].bctag,portno);
488 ba_clr(vlant[vlan].bcuntag,portno);
489 } else { /*forwarding*/
490 ba_clr(vlant[vlan].notlearning,portno);
491 if (portv[portno]->vlanuntag == vlan)
492 ba_set(vlant[vlan].bcuntag,portno);
493 else
494 ba_set(vlant[vlan].bctag,portno);
499 int port_get_status(int portno, int vlan)
501 if (ba_check(vlant[vlan].notlearning,portno))
502 return DISCARDING;
503 else {
504 if (ba_check(vlant[vlan].bctag,portno) ||
505 ba_check(vlant[vlan].bcuntag,portno))
506 return FORWARDING;
507 else
508 return LEARNING;
512 int port_getcost(int port)
514 return portv[port]->cost;
516 #endif
518 /************************************ CORE PACKET MGMT *****************************/
520 /* TAG2UNTAG packet:
521 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
522 * | Destination | Source |81 00|pvlan| L/T | data
523 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
525 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
526 * | Destination | Source | L/T | data
527 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
529 * Destination/Source: 4 byte right shift
530 * Length -4 bytes
531 * Pointer to the packet: +4 bytes
532 * */
534 #define TAG2UNTAG(P,LEN) \
535 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
536 (struct packet *)((char *)(P)+4); })
538 /* TAG2UNTAG packet:
539 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
540 * | Destination | Source | L/T | data
541 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
543 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
544 * | Destination | Source |81 00|pvlan| L/T | data
545 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
546 * Destination/Source: 4 byte left shift
547 * Length -4 bytes
548 * Pointer to the packet: +4 bytes
549 * The space has been allocated in advance (just in case); all the modules
550 * read data into a bipacket.
553 #define UNTAG2TAG(P,VLAN,LEN) \
554 ({ memmove((char *)(P)-4,(P),2*ETH_ALEN); LEN += 4 ; \
555 (P)->header.src[2]=0x81; (P)->header.src[3]=0x00;\
556 (P)->header.src[4]=(VLAN >> 8); (P)->header.src[5]=(VLAN);\
557 (struct packet *)((char *)(P)-4); })
560 #ifdef VDE_PQ2
561 static int trysendfun(struct endpoint *ep, void *packet, int len)
563 int port=ep->port;
564 return portv[port]->ms->sender(ep->fd_ctl, ep->fd_data, packet, len, port);
567 void handle_out_packet(struct endpoint *ep)
569 //printf("handle_out_packet %d\n",ep->vdepq_count);
570 ep->vdepq_count -= vdepq_try(&(ep->vdepq),ep,trysendfun);
571 if (ep->vdepq_count == 0)
572 mainloop_pollmask_del(ep->fd_data, POLLOUT);
574 #endif
576 void handle_in_packet(struct endpoint *ep, struct packet *packet, int len)
578 int tarport;
579 int vlan,tagged;
580 int port=ep->port;
582 if(PACKETFILTER(PKTFILTIN,port,packet,len)) {
584 #ifdef PORTCOUNTERS
585 portv[port]->pktsin++;
586 portv[port]->bytesin+=len;
587 #endif
588 if (pflag & HUB_TAG) { /* this is a HUB */
589 register int i;
590 #ifndef VDE_PQ2
591 for(i = 1; i < numports; i++)
592 if((i != port) && (portv[i] != NULL))
593 SEND_PACKET_PORT(portv[i],i,packet,len);
594 #else
595 void *tmpbuf=NULL;
596 for(i = 1; i < numports; i++)
597 if((i != port) && (portv[i] != NULL))
598 SEND_PACKET_PORT(portv[i],i,packet,len,&tmpbuf);
599 #endif
600 } else { /* This is a switch, not a HUB! */
601 if (packet->header.proto[0] == 0x81 && packet->header.proto[1] == 0x00) {
602 tagged=1;
603 vlan=((packet->data[0] << 8) + packet->data[1]) & 0xfff;
604 if (! ba_check(vlant[vlan].table,port))
605 return; /*discard unwanted packets*/
606 } else {
607 tagged=0;
608 if ((vlan=portv[port]->vlanuntag) == NOVLAN)
609 return; /*discard unwanted packets*/
612 #ifdef FSTP
613 /* when it works as a HUB or FSTP is off, MST packet must be forwarded */
614 if (ISBPDU(packet) && fstflag(P_GETFLAG, FSTP_TAG)) {
615 fst_in_bpdu(port,packet,len,vlan,tagged);
616 return; /* BPDU packets are not forwarded */
618 #endif
619 /* The port is in blocked status, no packet received */
620 if (ba_check(vlant[vlan].notlearning,port)) return;
622 /* We don't like broadcast source addresses */
623 if(! (IS_BROADCAST(packet->header.src))) {
625 int last = find_in_hash_update(packet->header.src,vlan,port);
626 /* old value differs from actual input port */
627 if(last >=0 && (port != last)){
628 printlog(LOG_INFO,"MAC %02x:%02x:%02x:%02x:%02x:%02x moved from port %d to port %d",packet->header.src[0],packet->header.src[1],packet->header.src[2],packet->header.src[3],packet->header.src[4],packet->header.src[5],last,port);
631 /* static void send_dst(int port,struct packet *packet, int len) */
632 if(IS_BROADCAST(packet->header.dest) ||
633 (tarport = find_in_hash(packet->header.dest,vlan)) < 0 ){
634 /* FST HERE! broadcast only on active ports*/
635 /* no cache or broadcast/multicast == all ports *except* the source port! */
636 /* BROADCAST: tag/untag. Broadcast the packet untouched on the ports
637 * of the same tag-ness, then transform it to the other tag-ness for the others*/
638 if (tagged) {
639 register int i;
640 #ifndef VDE_PQ2
641 ba_FORALL(vlant[vlan].bctag,numports,
642 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len);}),i);
643 packet=TAG2UNTAG(packet,len);
644 ba_FORALL(vlant[vlan].bcuntag,numports,
645 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len);}),i);
646 #else
647 void *tmpbuft=NULL;
648 void *tmpbufu=NULL;
649 ba_FORALL(vlant[vlan].bctag,numports,
650 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len,&tmpbuft);}),i);
651 packet=TAG2UNTAG(packet,len);
652 ba_FORALL(vlant[vlan].bcuntag,numports,
653 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len,&tmpbufu);}),i);
654 #endif
655 } else { /* untagged */
656 register int i;
657 #ifndef VDE_PQ2
658 ba_FORALL(vlant[vlan].bcuntag,numports,
659 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len);}),i);
660 packet=UNTAG2TAG(packet,vlan,len);
661 ba_FORALL(vlant[vlan].bctag,numports,
662 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len);}),i);
663 #else
664 void *tmpbufu=NULL;
665 void *tmpbuft=NULL;
666 ba_FORALL(vlant[vlan].bcuntag,numports,
667 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len,&tmpbufu);}),i);
668 packet=UNTAG2TAG(packet,vlan,len);
669 ba_FORALL(vlant[vlan].bctag,numports,
670 ({if (i != port) SEND_PACKET_PORT(portv[i],i,packet,len,&tmpbuft);}),i);
671 #endif
674 else {
675 /* the hash table should not generate tarport not in vlan
676 * any time a port is removed from a vlan, the port is flushed from the hash */
677 if (tarport==port)
678 return; /*do not loop!*/
679 #ifndef VDE_PQ2
680 if (tagged) {
681 if (portv[tarport]->vlanuntag==vlan) { /* TAG->UNTAG */
682 packet = TAG2UNTAG(packet,len);
683 SEND_PACKET_PORT(portv[tarport],tarport,packet,len);
684 } else { /* TAG->TAG */
685 SEND_PACKET_PORT(portv[tarport],tarport,packet,len);
687 } else {
688 if (portv[tarport]->vlanuntag==vlan) { /* UNTAG->UNTAG */
689 SEND_PACKET_PORT(portv[tarport],tarport,packet,len);
690 } else { /* UNTAG->TAG */
691 packet = UNTAG2TAG(packet,vlan,len);
692 SEND_PACKET_PORT(portv[tarport],tarport,packet,len);
695 #else
696 if (tagged) {
697 void *tmpbuf=NULL;
698 if (portv[tarport]->vlanuntag==vlan) { /* TAG->UNTAG */
699 packet = TAG2UNTAG(packet,len);
700 SEND_PACKET_PORT(portv[tarport],tarport,packet,len,&tmpbuf);
701 } else { /* TAG->TAG */
702 SEND_PACKET_PORT(portv[tarport],tarport,packet,len,&tmpbuf);
704 } else {
705 void *tmpbuf=NULL;
706 if (portv[tarport]->vlanuntag==vlan) { /* UNTAG->UNTAG */
707 SEND_PACKET_PORT(portv[tarport],tarport,packet,len,&tmpbuf);
708 } else { /* UNTAG->TAG */
709 packet = UNTAG2TAG(packet,vlan,len);
710 SEND_PACKET_PORT(portv[tarport],tarport,packet,len,&tmpbuf);
713 #endif
714 } /* if(BROADCAST) */
715 } /* if(HUB) */
716 } /* if(PACKETFILTER) */
719 /**************************************** COMMAND MANAGEMENT ****************************************/
721 static int showinfo(FILE *fd)
723 printoutc(fd,"Numports=%d",numports);
724 printoutc(fd,"HUB=%s",(pflag & HUB_TAG)?"true":"false");
725 #ifdef PORTCOUNTERS
726 printoutc(fd,"counters=true");
727 #else
728 printoutc(fd,"counters=false");
729 #endif
730 #ifdef VDE_PQ2
731 printoutc(fd,"default length of port packet queues: %d",stdqlen);
732 #endif
733 return 0;
736 static int portsetnumports(int val)
738 if(val > 0) {
739 /*resize structs*/
740 int i;
741 for(i=val;i<numports;i++)
742 if(portv[i] != NULL)
743 return EADDRINUSE;
744 portv=realloc(portv,val*sizeof(struct port *));
745 if (portv == NULL) {
746 printlog(LOG_ERR,"Numport resize failed portv %s",strerror(errno));
747 exit(1);
749 for (i=0;i<NUMOFVLAN;i++) {
750 if (vlant[i].table) {
751 vlant[i].table=ba_realloc(vlant[i].table,numports,val);
752 if (vlant[i].table == NULL) {
753 printlog(LOG_ERR,"Numport resize failed vlan tables vlan table %s",strerror(errno));
754 exit(1);
757 if (vlant[i].bctag) {
758 vlant[i].bctag=ba_realloc(vlant[i].bctag,numports,val);
759 if (vlant[i].bctag == NULL) {
760 printlog(LOG_ERR,"Numport resize failed vlan tables vlan bctag %s",strerror(errno));
761 exit(1);
764 if (vlant[i].bcuntag) {
765 vlant[i].bcuntag=ba_realloc(vlant[i].bcuntag,numports,val);
766 if (vlant[i].bcuntag == NULL) {
767 printlog(LOG_ERR,"Numport resize failed vlan tables vlan bctag %s",strerror(errno));
768 exit(1);
771 if (vlant[i].notlearning) {
772 vlant[i].notlearning=ba_realloc(vlant[i].notlearning,numports,val);
773 if (vlant[i].notlearning == NULL) {
774 printlog(LOG_ERR,"Numport resize failed vlan tables vlan notlearning %s",strerror(errno));
775 exit(1);
779 for (i=numports;i<val;i++)
780 portv[i]=NULL;
781 #ifdef FSTP
782 fstsetnumports(val);
783 #endif
784 numports=val;
785 return 0;
786 } else
787 return EINVAL;
790 static int portallocatable(char *arg)
792 int port,value;
793 if (sscanf(arg,"%i %i",&port,&value) != 2)
794 return EINVAL;
795 if (port < 0 || port >= numports)
796 return EINVAL;
797 if (portv[port] == NULL)
798 return ENXIO;
799 if (value)
800 portv[port]->flag &= ~NOTINPOOL;
801 else
802 portv[port]->flag |= NOTINPOOL;
803 return 0;
806 static int portsetuser(char *arg)
808 int port;
809 char *portuid=arg;
810 struct passwd *pw;
811 while (*portuid != 0 && *portuid == ' ') portuid++;
812 while (*portuid != 0 && *portuid != ' ') portuid++;
813 while (*portuid != 0 && *portuid == ' ') portuid++;
814 if (sscanf(arg,"%i",&port) != 1 || *portuid==0)
815 return EINVAL;
816 if (port < 0 || port >= numports)
817 return EINVAL;
818 if (portv[port] == NULL)
819 return ENXIO;
820 if ((pw=getpwnam(portuid)) != NULL)
821 portv[port]->user=pw->pw_uid;
822 else if (isdigit(*portuid))
823 portv[port]->user=atoi(portuid);
824 else if (strcmp(portuid,"NONE")==0 || strcmp(portuid,"ANY")==0)
825 portv[port]->user= -1;
826 else
827 return EINVAL;
828 return 0;
831 static int portsetgroup(char *arg)
833 int port;
834 char *portgid=arg;
835 struct group *gr;
836 while (*portgid != 0 && *portgid == ' ') portgid++;
837 while (*portgid != 0 && *portgid != ' ') portgid++;
838 while (*portgid != 0 && *portgid == ' ') portgid++;
839 if (sscanf(arg,"%i",&port) != 1 || *portgid==0)
840 return EINVAL;
841 if (port < 0 || port >= numports)
842 return EINVAL;
843 if (portv[port] == NULL)
844 return ENXIO;
845 if ((gr=getgrnam(portgid)) != NULL)
846 portv[port]->group=gr->gr_gid;
847 else if (isdigit(*portgid))
848 portv[port]->group=atoi(portgid);
849 else if (strcmp(portgid,"NONE")==0 || strcmp(portgid,"ANY")==0)
850 portv[port]->group= -1;
851 else
852 return EINVAL;
853 return 0;
856 static int portremove(int val)
858 if (val <0 || val>=numports)
859 return EINVAL;
860 if (portv[val] == NULL)
861 return ENXIO;
862 if (portv[val]->ep != NULL)
863 return EADDRINUSE;
864 free_port(val);
865 return 0;
868 static int portcreate(int val)
870 int port;
871 if (val <0 || val>=numports)
872 return EINVAL;
873 if (portv[val] != NULL)
874 return EEXIST;
875 port=alloc_port(val);
876 if (port < 0)
877 return ENOSPC;
878 portv[port]->flag |= NOTINPOOL;
879 return 0;
882 static int portcreateauto(FILE* fd)
884 int port = alloc_port(0);
886 if (port < 0)
887 return ENOSPC;
889 portv[port]->flag |= NOTINPOOL;
890 printoutc(fd, "Port %04d", port);
891 return 0;
894 static int epclose(char *arg)
896 int port,id;
897 if (sscanf(arg,"%i %i",&port,&id) != 2)
898 return EINVAL;
899 else
900 return close_ep_port_fd(port,id);
903 #ifdef VDE_PQ2
904 static int defqlen(int len)
906 if (len < 0)
907 return EINVAL;
908 else {
909 stdqlen=len;
910 return 0;
914 static int epqlen(char *arg)
916 int port,id,len;
917 if (sscanf(arg,"%i %i %i",&port,&id,&len) != 3 || len < 0)
918 return EINVAL;
919 else
920 return setqlen_ep_port_fd(port,id,len);
922 #endif
924 static char *port_getuser(uid_t uid)
926 static char buf[6];
927 struct passwd *pw;
928 if (uid == -1)
929 return "NONE";
930 else {
931 pw=getpwuid(uid);
932 if (pw != NULL)
933 return pw->pw_name;
934 else {
935 sprintf(buf,"%d",uid);
936 return buf;
941 static char *port_getgroup(gid_t gid)
943 static char buf[6];
944 struct group *gr;
945 if (gid == -1)
946 return "NONE";
947 else {
948 gr=getgrgid(gid);
949 if (gr != NULL)
950 return gr->gr_name;
951 else {
952 sprintf(buf,"%d",gid);
953 return buf;
958 static int print_port(FILE *fd,int i,int inclinactive)
960 struct endpoint *ep;
961 if (portv[i] != NULL && (inclinactive || portv[i]->ep!=NULL)) {
962 printoutc(fd,"Port %04d untagged_vlan=%04d %sACTIVE - %sUnnamed Allocatable",
963 i,portv[i]->vlanuntag,
964 portv[i]->ep?"":"IN",
965 (portv[i]->flag & NOTINPOOL)?"NOT ":"");
966 printoutc(fd," Current User: %s Access Control: (User: %s - Group: %s)",
967 port_getuser(portv[i]->curuser),
968 port_getuser(portv[i]->user),
969 port_getgroup(portv[i]->group));
970 #ifdef PORTCOUNTERS
971 printoutc(fd," IN: pkts %10lld bytes %20lld",portv[i]->pktsin,portv[i]->bytesin);
972 printoutc(fd," OUT: pkts %10lld bytes %20lld",portv[i]->pktsout,portv[i]->bytesout);
973 #endif
974 for (ep=portv[i]->ep; ep != NULL; ep=ep->next) {
975 printoutc(fd," -- endpoint ID %04d module %-12s: %s",ep->fd_ctl,
976 portv[i]->ms->modname,(ep->descr)?ep->descr:"no endpoint description");
977 #ifdef VDE_PQ2
978 printoutc(fd," unsent packets: %d max %d",ep->vdepq_count,ep->vdepq_max);
979 #endif
981 return 0;
982 } else
983 return ENXIO;
986 static int print_ptable(FILE *fd,char *arg)
988 register int i;
989 if (*arg != 0) {
990 i=atoi(arg);
991 if (i <0 || i>=numports)
992 return EINVAL;
993 else {
994 return print_port(fd,i,0);
996 } else {
997 for (i=0;i<numports;i++)
998 print_port(fd,i,0);
999 return 0;
1003 static int print_ptableall(FILE *fd,char *arg)
1005 register int i;
1006 if (*arg != 0) {
1007 i=atoi(arg);
1008 if (i <0 || i>=numports)
1009 return EINVAL;
1010 else {
1011 return print_port(fd,i,1);
1013 } else {
1014 for (i=0;i<numports;i++)
1015 print_port(fd,i,1);
1016 return 0;
1020 #ifdef PORTCOUNTERS
1021 static void portzerocounter(int i)
1023 if (portv[i] != NULL) {
1024 portv[i]->pktsin=0;
1025 portv[i]->pktsout=0;
1026 portv[i]->bytesin=0;
1027 portv[i]->bytesout=0;
1031 static int portresetcounters(char *arg)
1033 register int i;
1034 if (*arg != 0) {
1035 i=atoi(arg);
1036 if (i <0 || i>=numports)
1037 return EINVAL;
1038 else {
1039 portzerocounter(i);
1040 return 0;
1042 } else {
1043 for (i=0;i<numports;i++)
1044 portzerocounter(i);
1045 return 0;
1048 #endif
1050 static int portsethub(int val)
1052 if (val) {
1053 #ifdef FSTP
1054 fstpshutdown();
1055 #endif
1056 portflag(P_SETFLAG,HUB_TAG);
1057 } else
1058 portflag(P_CLRFLAG,HUB_TAG);
1059 return 0;
1062 static int portsetvlan(char *arg)
1064 int port,vlan;
1065 if (sscanf(arg,"%i %i",&port,&vlan) != 2)
1066 return EINVAL;
1067 /* port NOVLAN is okay here, it means NO untagged traffic */
1068 if (vlan <0 || vlan > NUMOFVLAN || port < 0 || port >= numports)
1069 return EINVAL;
1070 if ((vlan != NOVLAN && !bac_check(validvlan,vlan)) || portv[port] == NULL)
1071 return ENXIO;
1072 int oldvlan=portv[port]->vlanuntag;
1073 portv[port]->vlanuntag=NOVLAN;
1074 hash_delete_port(port);
1075 if (portv[port]->ep != NULL) {
1076 /*changing active port*/
1077 if (oldvlan != NOVLAN)
1078 ba_clr(vlant[oldvlan].bcuntag,port);
1079 if (vlan != NOVLAN) {
1080 ba_set(vlant[vlan].bcuntag,port);
1081 ba_clr(vlant[vlan].bctag,port);
1083 #ifdef FSTP
1084 if (oldvlan != NOVLAN) fstdelport(oldvlan,port);
1085 if (vlan != NOVLAN) fstaddport(vlan,port,0);
1086 #endif
1088 if (oldvlan != NOVLAN) ba_clr(vlant[oldvlan].table,port);
1089 if (vlan != NOVLAN) ba_set(vlant[vlan].table,port);
1090 portv[port]->vlanuntag=vlan;
1091 return 0;
1094 static int vlancreate_nocheck(int vlan)
1096 int rv=0;
1097 vlant[vlan].table=ba_alloc(numports);
1098 vlant[vlan].bctag=ba_alloc(numports);
1099 vlant[vlan].bcuntag=ba_alloc(numports);
1100 vlant[vlan].notlearning=ba_alloc(numports);
1101 if (vlant[vlan].table == NULL || vlant[vlan].bctag == NULL ||
1102 vlant[vlan].bcuntag == NULL)
1103 return ENOMEM;
1104 else {
1105 #ifdef FSTP
1106 rv=fstnewvlan(vlan);
1107 #endif
1108 if (rv == 0) {
1109 bac_set(validvlan,NUMOFVLAN,vlan);
1111 return rv;
1115 static int vlancreate(int vlan)
1117 if (vlan > 0 && vlan < NUMOFVLAN-1) { /*vlan NOVLAN (0xfff a.k.a. 4095) is reserved */
1118 if (bac_check(validvlan,vlan))
1119 return EEXIST;
1120 else
1121 return vlancreate_nocheck(vlan);
1122 } else
1123 return EINVAL;
1126 static int vlanremove(int vlan)
1128 if (vlan >= 0 && vlan < NUMOFVLAN) {
1129 if (bac_check(validvlan,vlan)) {
1130 register int i,used=0;
1131 ba_FORALL(vlant[vlan].table,numports,used++,i);
1132 if (used)
1133 return EADDRINUSE;
1134 else {
1135 bac_clr(validvlan,NUMOFVLAN,vlan);
1136 free(vlant[vlan].table);
1137 free(vlant[vlan].bctag);
1138 free(vlant[vlan].bcuntag);
1139 free(vlant[vlan].notlearning);
1140 vlant[vlan].table=NULL;
1141 vlant[vlan].bctag=NULL;
1142 vlant[vlan].bcuntag=NULL;
1143 vlant[vlan].notlearning=NULL;
1144 #ifdef FSTP
1145 fstremovevlan(vlan);
1146 #endif
1147 return 0;
1149 } else
1150 return ENXIO;
1151 } else
1152 return EINVAL;
1155 static int vlanaddport(char *arg)
1157 int port,vlan;
1158 if (sscanf(arg,"%i %i",&vlan,&port) != 2)
1159 return EINVAL;
1160 if (vlan <0 || vlan >= NUMOFVLAN-1 || port < 0 || port >= numports)
1161 return EINVAL;
1162 if (!bac_check(validvlan,vlan) || portv[port] == NULL)
1163 return ENXIO;
1164 if (portv[port]->ep != NULL && portv[port]->vlanuntag != vlan) {
1165 /* changing active port*/
1166 ba_set(vlant[vlan].bctag,port);
1167 #ifdef FSTP
1168 fstaddport(vlan,port,1);
1169 #endif
1171 ba_set(vlant[vlan].table,port);
1172 return 0;
1175 static int vlandelport(char *arg)
1177 int port,vlan;
1178 if (sscanf(arg,"%i %i",&vlan,&port) != 2)
1179 return EINVAL;
1180 if (vlan <0 || vlan >= NUMOFVLAN-1 || port < 0 || port >= numports)
1181 return EINVAL;
1182 if (!bac_check(validvlan,vlan) || portv[port] == NULL)
1183 return ENXIO;
1184 if (portv[port]->vlanuntag == vlan)
1185 return EADDRINUSE;
1186 if (portv[port]->ep != NULL) {
1187 /*changing active port*/
1188 ba_clr(vlant[vlan].bctag,port);
1189 #ifdef FSTP
1190 fstdelport(vlan,port);
1191 #endif
1193 ba_clr(vlant[vlan].table,port);
1194 hash_delete_port(port);
1195 return 0;
1198 #define STRSTATUS(PN,V) \
1199 ((ba_check(vlant[(V)].notlearning,(PN))) ? "Discarding" : \
1200 (ba_check(vlant[(V)].bctag,(PN)) || ba_check(vlant[(V)].bcuntag,(PN))) ? \
1201 "Forwarding" : "Learning")
1203 static void vlanprintactive(int vlan,FILE *fd)
1205 register int i;
1206 printoutc(fd,"VLAN %04d",vlan);
1207 #ifdef FSTP
1208 if (pflag & FSTP_TAG) {
1209 #if 0
1210 printoutc(fd," ++ FST root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n"
1211 " designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x port %d cost %d age %d",
1212 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
1213 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
1214 fsttab[vlan]->desbr[0], fsttab[vlan]->desbr[1], fsttab[vlan]->desbr[2], fsttab[vlan]->desbr[3],
1215 fsttab[vlan]->desbr[4], fsttab[vlan]->desbr[5], fsttab[vlan]->desbr[6], fsttab[vlan]->desbr[7],
1216 fsttab[vlan]->rootport,
1217 ntohl(*(u_int32_t *)(&(fsttab[vlan]->rootcost))),
1218 qtime()-fsttab[vlan]->roottimestamp);
1219 ba_FORALL(vlant[vlan].table,numports,
1220 ({ int tagged=portv[i]->vlanuntag != vlan;
1221 if (portv[i]->ep)
1222 printoutc(fd," -- Port %04d tagged=%d act=%d learn=%d forw=%d cost=%d role=%s",
1223 i, tagged, 1, !(NOTLEARNING(i,vlan)),
1224 (tagged)?(ba_check(vlant[vlan].bctag,i) != 0):(ba_check(vlant[vlan].bcuntag,i) != 0),
1225 portv[i]->cost,
1226 (fsttab[vlan]->rootport==i?"Root":
1227 ((ba_check(fsttab[vlan]->backup,i)?"Alternate/Backup":"Designated")))
1228 ); 0;
1229 }) ,i);
1230 #endif
1231 } else {
1232 #endif
1233 ba_FORALL(vlant[vlan].table,numports,
1234 ({ int tagged=portv[i]->vlanuntag != vlan;
1235 if (portv[i]->ep)
1236 printoutc(fd," -- Port %04d tagged=%d active=1 status=%s", i, tagged,
1237 STRSTATUS(i,vlan));
1238 }), i);
1239 #ifdef FSTP
1241 #endif
1244 static int vlanprint(FILE *fd,char *arg)
1246 if (*arg != 0) {
1247 register int vlan;
1248 vlan=atoi(arg);
1249 if (vlan >= 0 && vlan < NUMOFVLAN-1) {
1250 if (bac_check(validvlan,vlan))
1251 vlanprintactive(vlan,fd);
1252 else
1253 return ENXIO;
1254 } else
1255 return EINVAL;
1256 } else
1257 bac_FORALLFUN(validvlan,NUMOFVLAN,vlanprintactive,fd);
1258 return 0;
1261 static void vlanprintelem(int vlan,FILE *fd)
1263 register int i;
1264 printoutc(fd,"VLAN %04d",vlan);
1265 ba_FORALL(vlant[vlan].table,numports,
1266 printoutc(fd," -- Port %04d tagged=%d active=%d status=%s",
1267 i, portv[i]->vlanuntag != vlan, portv[i]->ep != NULL, STRSTATUS(i,vlan)),i);
1270 static int vlanprintall(FILE *fd,char *arg)
1272 if (*arg != 0) {
1273 register int vlan;
1274 vlan=atoi(arg);
1275 if (vlan > 0 && vlan < NUMOFVLAN-1) {
1276 if (bac_check(validvlan,vlan))
1277 vlanprintelem(vlan,fd);
1278 else
1279 return ENXIO;
1280 } else
1281 return EINVAL;
1282 } else
1283 bac_FORALLFUN(validvlan,NUMOFVLAN,vlanprintelem,fd);
1284 return 0;
1287 /* NOT sure about the effects of changing address on FSTP */
1289 #if 0
1290 static int setmacaddr(char *strmac)
1292 int maci[ETH_ALEN],rv;
1294 if (index(strmac,':') != NULL)
1295 rv=sscanf(strmac,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
1296 else
1297 rv=sscanf(strmac,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
1298 if (rv < 6)
1299 return EINVAL;
1300 else {
1301 register int i;
1302 for (i=0;i<ETH_ALEN;i++)
1303 switchmac[i]=maci[i];
1304 return 0;
1307 #endif
1309 uid_t port_user(int port)
1311 if (port<0 || port>=numports || portv[port]==NULL)
1312 return -1;
1313 else
1314 return portv[port]->curuser;
1317 char *port_descr(int portno, int epn) {
1318 if (portno<0 || portno>=numports)
1319 return NULL;
1320 else {
1321 struct port *port=portv[portno];
1322 if (port == NULL)
1323 return NULL;
1324 else {
1325 struct endpoint *ep;
1326 for (ep=port->ep;ep!=NULL && epn>0;ep=ep->next,epn--)
1328 if (ep)
1329 return ep->descr;
1330 else
1331 return NULL;
1336 static struct comlist cl[]={
1337 {"port","============","PORT STATUS MENU",NULL,NOARG},
1338 {"port/showinfo","","show port info",showinfo,NOARG|WITHFILE},
1339 {"port/setnumports","N","set the number of ports",portsetnumports,INTARG},
1340 /*{"port/setmacaddr","MAC","set the switch MAC address",setmacaddr,STRARG},*/
1341 {"port/sethub","0/1","1=HUB 0=switch",portsethub,INTARG},
1342 {"port/setvlan","N VLAN","set port VLAN (untagged)",portsetvlan,STRARG},
1343 {"port/createauto","","create a port with an automatically allocated id (inactive|notallocatable)",portcreateauto,NOARG|WITHFILE},
1344 {"port/create","N","create the port N (inactive|notallocatable)",portcreate,INTARG},
1345 {"port/remove","N","remove the port N",portremove,INTARG},
1346 {"port/allocatable","N 0/1","Is the port allocatable as unnamed? 1=Y 0=N",portallocatable,STRARG},
1347 {"port/setuser","N user","access control: set user",portsetuser,STRARG},
1348 {"port/setgroup","N user","access control: set group",portsetgroup,STRARG},
1349 {"port/epclose","N ID","remove the endpoint port N/id ID",epclose,STRARG},
1350 #ifdef VDE_PQ2
1351 {"port/defqlen","LEN","set the default queue length for new ports",defqlen,INTARG},
1352 {"port/epqlen","N ID LEN","set the lenth of the queue for port N/id IP",epqlen,STRARG},
1353 #endif
1354 #ifdef PORTCOUNTERS
1355 {"port/resetcounter","[N]","reset the port (N) counters",portresetcounters,STRARG},
1356 #endif
1357 {"port/print","[N]","print the port/endpoint table",print_ptable,STRARG|WITHFILE},
1358 {"port/allprint","[N]","print the port/endpoint table (including inactive port)",print_ptableall,STRARG|WITHFILE},
1359 {"vlan","============","VLAN MANAGEMENT MENU",NULL,NOARG},
1360 {"vlan/create","N","create the VLAN with tag N",vlancreate,INTARG},
1361 {"vlan/remove","N","remove the VLAN with tag N",vlanremove,INTARG},
1362 {"vlan/addport","N PORT","add port to the vlan N (tagged)",vlanaddport,STRARG},
1363 {"vlan/delport","N PORT","add port to the vlan N (tagged)",vlandelport,STRARG},
1364 {"vlan/print","[N]","print the list of defined vlan",vlanprint,STRARG|WITHFILE},
1365 {"vlan/allprint","[N]","print the list of defined vlan (including inactive port)",vlanprintall,STRARG|WITHFILE},
1368 void port_init(int initnumports)
1370 if((numports=initnumports) <= 0) {
1371 printlog(LOG_ERR,"The switch must have at least 1 port\n");
1372 exit(1);
1374 portv=calloc(numports,sizeof(struct port *));
1375 /* vlan_init */
1376 validvlan=bac_alloc(NUMOFVLAN);
1377 if (portv==NULL || validvlan == NULL) {
1378 printlog(LOG_ERR,"ALLOC port data structures");
1379 exit(1);
1381 ADDCL(cl);
1382 #ifdef DEBUGOPT
1383 ADDDBGCL(dl);
1384 #endif
1385 if (vlancreate_nocheck(0) != 0) {
1386 printlog(LOG_ERR,"ALLOC vlan port data structures");
1387 exit(1);