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
13 #include <sys/socket.h>
15 #include <netinet/in.h> /*ntoh conversion*/
16 #include <sys/types.h>
23 #include <vdecommon.h>
41 static struct port
**portv
;
44 #define DBGPORTNEW (dl)
45 #define DBGPORTDEL (dl+1)
46 #define DBGPORTDESCR (dl+2)
47 #define DBGEPNEW (dl+3)
48 #define DBGEPDEL (dl+4)
49 #define PKTFILTIN (dl+5)
50 #define PKTFILTOUT (dl+6)
51 static struct dbgcl dl
[]= {
52 {"port/+","new port",D_PORT
|D_PLUS
},
53 {"port/-","closed port",D_PORT
|D_MINUS
},
54 {"port/descr","set port description",D_PORT
|D_DESCR
},
55 {"port/ep/+","new endpoint",D_EP
|D_PLUS
},
56 {"port/ep/-","closed endpoint",D_EP
|D_MINUS
},
57 {"packet/in",NULL
,D_PACKET
|D_IN
},
58 {"packet/out",NULL
,D_PACKET
|D_OUT
},
62 // for dedugging if needed
65 void packet_dump (struct packet *p)
68 printf ("packet dump dst");
69 for (i=0;i<ETH_ALEN;i++)
70 printf(":%02x",p->header.dest[i]);
72 for (i=0;i<ETH_ALEN;i++)
73 printf(":%02x",p->header.src[i]);
76 printf(":%02x",p->header.proto[i]);
85 struct endpoint
*next
;
88 #define NOTINPOOL 0x8000
94 /* sender is already inside ms, but it needs one more memaccess */
95 int (*sender
)(int fd
, int fd_ctl
, void *packet
, int len
, void *data
, int port
);
96 struct mod_support
*ms
;
105 long long pktsin
,pktsout
,bytesin
,bytesout
;
110 * table the vlan table (also for inactive ports)
111 * vlan bctag is the vlan table -- only tagged forwarding ports mapping
112 * vlan bcuntag is the vlan table -- only untagged forwarding ports mapping
113 * validvlan is the table of valid vlans
120 bitarray notlearning
;
124 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
127 static int alloc_port(unsigned int portno
)
132 for (i
=1;i
<numports
&& portv
[i
] != NULL
&&
133 (portv
[i
]->ep
!= NULL
|| portv
[i
]->flag
& NOTINPOOL
) ;i
++)
135 } else if (i
<0) /* special case MGMT client port */
140 if (portv
[i
] == NULL
) {
142 if ((port
= malloc(sizeof(struct port
))) == NULL
){
143 printlog(LOG_WARNING
,"malloc port %s",strerror(errno
));
147 DBGOUT(DBGPORTNEW
,"%02d", i
);
148 EVENTOUT(DBGPORTNEW
,i
);
153 port
->user
=port
->group
=port
->curuser
=-1;
155 port
->cost
=DEFAULT_COST
;
166 ba_set(vlant
[0].table
,i
);
173 static void free_port(unsigned int portno
)
175 if (portno
< numports
) {
176 struct port
*port
=portv
[portno
];
177 if (port
!= NULL
&& port
->ep
==NULL
) {
180 /* delete completely the port. all vlan defs zapped */
181 bac_FORALL(validvlan
,NUMOFVLAN
,ba_clr(vlant
[i
].table
,portno
),i
);
187 /* 1 if user belongs to the group, 0 otherwise) */
189 /* getgrouplist is a nonstandard call */
190 static int user_belongs_to_group(uid_t uid
, gid_t gid
)
192 struct passwd
*pw
=getpwuid(uid
);
197 gid_t
*grouplist
=NULL
;
199 grouplist
=realloc(grouplist
, gsize
*sizeof(gid_t
));
200 } while (grouplist
!= NULL
&& getgrouplist(pw
->pw_name
,pw
->pw_gid
,grouplist
,&gsize
) < 0);
201 if (grouplist
!= NULL
) {
202 for (scan
=0;scan
<gsize
&& !found
;scan
++)
203 if (grouplist
[scan
]==gid
)
211 static int user_belongs_to_group(uid_t uid
, gid_t gid
)
213 struct passwd
*pw
=getpwuid(uid
);
222 while ((grp
= getgrent())) {
223 if (grp
->gr_gid
== gid
) {
225 for (i
= 0; grp
->gr_mem
[i
]; i
++) {
226 if (strcmp(grp
->gr_mem
[i
], pw
->pw_name
)==0) {
240 /* Access Control check:
241 returns 0->OK -1->Permission Denied */
242 static int checkport_ac(struct port
*port
, uid_t user
)
245 if (port
->user
== -1 && port
->group
== -1)
247 /*root or restricted to a specific user*/
248 else if (user
==0 || (port
->user
!= -1 && port
->user
==user
))
250 /*restricted to a group*/
251 else if (port
->group
!= -1 && user_belongs_to_group(user
,port
->group
))
259 /* initialize a port structure with control=fd, given data+data_len and sender
261 * and then add it to the g_fdsdata array at index i. */
262 int setup_ep(int portno
, int fd_ctl
,
265 struct mod_support
*modfun
)
270 if ((portno
= alloc_port(portno
)) >= 0) {
272 if (port
->fd_data
< 0 && checkport_ac(port
,user
)==0) {
273 port
->fd_data
=modfun
->newport(fd_ctl
,portno
,user
);
276 if (port
->fd_data
>= 0 && port
->curuser
== user
&&
277 (ep
=malloc(sizeof(struct endpoint
))) != NULL
) {
278 DBGOUT(DBGEPNEW
,"Port %02d FD %2d", portno
,fd_ctl
);
279 EVENTOUT(DBGEPNEW
,portno
,fd_ctl
);
281 port
->sender
=modfun
->sender
;
286 if(port
->ep
== NULL
) {/* WAS INACTIVE */
288 /* copy all the vlan defs to the active vlan defs */
291 bac_FORALL(validvlan
,NUMOFVLAN
,
292 ({if (ba_check(vlant
[i
].table
,portno
)) {
293 ba_set(vlant
[i
].bctag
,portno
);
295 fstaddport(i
,portno
,(i
!=port
->vlanuntag
));
299 if (port
->vlanuntag
!= NOVLAN
) {
300 ba_set(vlant
[port
->vlanuntag
].bcuntag
,portno
);
301 ba_clr(vlant
[port
->vlanuntag
].bctag
,portno
);
303 ba_clr(vlant
[port
->vlanuntag
].notlearning
,portno
);
311 if (port
->fd_data
< 0)
313 else if (port
->curuser
!= user
)
326 void setup_description(int portno
, int fd_ctl
, char *descr
)
328 if (portno
>=0 && portno
< numports
) {
329 struct port
*port
=portv
[portno
];
332 for (ep
=port
->ep
;ep
!=NULL
;ep
=ep
->next
)
333 if (ep
->fd_ctl
== fd_ctl
) {
334 DBGOUT(DBGPORTDESCR
,"Port %02d FD %2d -> \"%s\"",portno
,fd_ctl
,descr
);
335 EVENTOUT(DBGPORTDESCR
,portno
,fd_ctl
,descr
);
342 static int rec_close_ep(struct endpoint
**pep
, int fd_ctl
)
344 struct endpoint
*this=*pep
;
346 if (this->fd_ctl
==fd_ctl
) {
347 DBGOUT(DBGEPDEL
,"Port %02d FD %2d",this->port
,fd_ctl
);
348 EVENTOUT(DBGEPDEL
,this->port
,fd_ctl
);
350 if (portv
[this->port
]->ms
->delep
)
351 portv
[this->port
]->ms
->delep(this->fd_ctl
,this->data
,this->descr
);
355 return rec_close_ep(&(this->next
),fd_ctl
);
360 int close_ep(int portno
, int fd_ctl
)
362 if (portno
>=0 && portno
< numports
) {
363 struct port
*port
=portv
[portno
];
365 int rv
=rec_close_ep(&(port
->ep
),fd_ctl
);
366 if (port
->ep
== NULL
) {
367 DBGOUT(DBGPORTDEL
,"%02d",portno
);
368 EVENTOUT(DBGPORTDEL
,portno
);
369 hash_delete_port(portno
);
371 packetq_delfd(port
->fd_data
);
373 if (portv
[portno
]->ms
->delport
)
374 portv
[portno
]->ms
->delport(port
->fd_data
,portno
);
380 /* inactivate port: all active vlan defs cleared */
381 bac_FORALL(validvlan
,NUMOFVLAN
,({
382 ba_clr(vlant
[i
].bctag
,portno
);
384 fstdelport(i
,portno
);
387 if (port
->vlanuntag
< NOVLAN
) ba_clr(vlant
[port
->vlanuntag
].bcuntag
,portno
);
396 int portflag(int op
,int f
)
400 case P_GETFLAG
: oldflag
= pflag
& f
; break;
401 case P_SETFLAG
: pflag
=f
; break;
402 case P_ADDFLAG
: pflag
|= f
; break;
403 case P_CLRFLAG
: pflag
&= ~f
; break;
409 /*********************** sending macro used by Core ******************/
411 /* VDBG counter: count[port].spacket++; count[port].sbytes+=len */
413 #define SEND_COUNTER_UPD(Port,LEN) ({Port->pktsout++; Port->bytesout +=len;})
415 #define SEND_COUNTER_UPD(Port,LEN)
419 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
421 struct port *Port=(PORT); \
422 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
423 struct endpoint *ep; \
424 SEND_COUNTER_UPD(Port,LEN); \
425 for (ep=Port->ep; ep != NULL; ep=ep->next) \
426 if (Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port)) \
427 packetq_add(Port->ms->sender,Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
431 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
433 struct port *Port=(PORT); \
434 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
435 struct endpoint *ep; \
436 SEND_COUNTER_UPD(Port,LEN); \
437 for (ep=Port->ep; ep != NULL; ep=ep->next) \
438 Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
445 /* functions for FSTP */
446 void port_send_packet(int portno
, void *packet
, int len
)
448 SEND_PACKET_PORT(portv
[portno
],portno
,packet
,len
);
451 void portset_send_packet(bitarray portset
, void *packet
, int len
)
454 ba_FORALL(portset
,numports
,
455 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
), i
);
459 void port_set_status(int portno
, int vlan
, int status
)
461 if (ba_check(vlant
[vlan
].table
,portno
)) {
462 if (status
==DISCARDING
) {
463 ba_set(vlant
[vlan
].notlearning
,portno
);
464 ba_clr(vlant
[vlan
].bctag
,portno
);
465 ba_clr(vlant
[vlan
].bcuntag
,portno
);
466 } else if (status
==LEARNING
) {
467 ba_clr(vlant
[vlan
].notlearning
,portno
);
468 ba_clr(vlant
[vlan
].bctag
,portno
);
469 ba_clr(vlant
[vlan
].bcuntag
,portno
);
470 } else { /*forwarding*/
471 ba_clr(vlant
[vlan
].notlearning
,portno
);
472 if (portv
[portno
]->vlanuntag
== vlan
)
473 ba_set(vlant
[vlan
].bcuntag
,portno
);
475 ba_set(vlant
[vlan
].bctag
,portno
);
480 int port_get_status(int portno
, int vlan
)
482 if (ba_check(vlant
[vlan
].notlearning
,portno
))
485 if (ba_check(vlant
[vlan
].bctag
,portno
) ||
486 ba_check(vlant
[vlan
].bcuntag
,portno
))
493 int port_getcost(int port
)
495 return portv
[port
]->cost
;
499 /************************************ CORE PACKET MGMT *****************************/
502 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
503 * | Destination | Source |81 00|pvlan| L/T | data
504 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
506 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
507 * | Destination | Source | L/T | data
508 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
510 * Destination/Source: 4 byte right shift
512 * Pointer to the packet: +4 bytes
515 #define TAG2UNTAG(P,LEN) \
516 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
517 (struct packet *)((char *)(P)+4); })
520 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
521 * | Destination | Source | L/T | data
522 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
524 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
525 * | Destination | Source |81 00|pvlan| L/T | data
526 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
527 * Destination/Source: 4 byte left shift
529 * Pointer to the packet: +4 bytes
530 * The space has been allocated in advance (just in case); all the modules
531 * read data into a bipacket.
534 #define UNTAG2TAG(P,VLAN,LEN) \
535 ({ memmove((char *)(P)-4,(P),2*ETH_ALEN); LEN += 4 ; \
536 (P)->header.src[2]=0x81; (P)->header.src[3]=0x00;\
537 (P)->header.src[4]=(VLAN >> 8); (P)->header.src[5]=(VLAN);\
538 (struct packet *)((char *)(P)-4); })
541 void handle_in_packet(int port
, struct packet
*packet
, int len
)
546 if(PACKETFILTER(PKTFILTIN
,port
,packet
,len
)) {
549 portv
[port
]->pktsin
++;
550 portv
[port
]->bytesin
+=len
;
552 if (pflag
& HUB_TAG
) { /* this is a HUB */
554 for(i
= 1; i
< numports
; i
++)
555 if((i
!= port
) && (portv
[i
] != NULL
))
556 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);
557 } else { /* This is a switch, not a HUB! */
558 if (packet
->header
.proto
[0] == 0x81 && packet
->header
.proto
[1] == 0x00) {
560 vlan
=((packet
->data
[0] << 8) + packet
->data
[1]) & 0xfff;
561 if (! ba_check(vlant
[vlan
].table
,port
))
562 return; /*discard unwanted packets*/
565 if ((vlan
=portv
[port
]->vlanuntag
) == NOVLAN
)
566 return; /*discard unwanted packets*/
570 /* when it works as a HUB or FSTP is off, MST packet must be forwarded */
571 if (ISBPDU(packet
) && fstflag(P_GETFLAG
, FSTP_TAG
)) {
572 fst_in_bpdu(port
,packet
,len
,vlan
,tagged
);
573 return; /* BPDU packets are not forwarded */
576 /* The port is in blocked status, no packet received */
577 if (ba_check(vlant
[vlan
].notlearning
,port
)) return;
579 /* We don't like broadcast source addresses */
580 if(! (IS_BROADCAST(packet
->header
.src
))) {
582 int last
= find_in_hash_update(packet
->header
.src
,vlan
,port
);
583 /* old value differs from actual input port */
584 if(last
>=0 && (port
!= last
)){
585 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
);
588 /* static void send_dst(int port,struct packet *packet, int len) */
589 if(IS_BROADCAST(packet
->header
.dest
) ||
590 (tarport
= find_in_hash(packet
->header
.dest
,vlan
)) < 0 ){
591 /* FST HERE! broadcast only on active ports*/
592 /* no cache or broadcast/multicast == all ports *except* the source port! */
593 /* BROADCAST: tag/untag. Broadcast the packet untouched on the ports
594 * of the same tag-ness, then transform it to the other tag-ness for the others*/
597 ba_FORALL(vlant
[vlan
].bctag
,numports
,
598 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
599 packet
=TAG2UNTAG(packet
,len
);
600 ba_FORALL(vlant
[vlan
].bcuntag
,numports
,
601 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
602 } else { /* untagged */
604 ba_FORALL(vlant
[vlan
].bcuntag
,numports
,
605 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
606 packet
=UNTAG2TAG(packet
,vlan
,len
);
607 ba_FORALL(vlant
[vlan
].bctag
,numports
,
608 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
612 /* the hash table should not generate tarport not in vlan
613 * any time a port is removed from a vlan, the port is flushed from the hash */
615 return; /*do not loop!*/
617 if (portv
[tarport
]->vlanuntag
==vlan
) /* TAG->UNTAG */
618 SEND_PACKET_PORT(portv
[tarport
],tarport
,TAG2UNTAG(packet
,len
),len
);
620 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
622 if (portv
[tarport
]->vlanuntag
==vlan
) /* UNTAG->UNTAG */
623 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
624 else /* UNTAG->TAG */
625 SEND_PACKET_PORT(portv
[tarport
],tarport
,UNTAG2TAG(packet
,vlan
,len
),len
);
627 } /* if(BROADCAST) */
629 } /* if(PACKETFILTER) */
632 /**************************************** COMMAND MANAGEMENT ****************************************/
634 static int showinfo(FILE *fd
)
636 printoutc(fd
,"Numports=%d",numports
);
637 printoutc(fd
,"HUB=%s",(pflag
& HUB_TAG
)?"true":"false");
639 printoutc(fd
,"counters=true");
641 printoutc(fd
,"counters=false");
646 static int portsetnumports(int val
)
651 for(i
=val
;i
<numports
;i
++)
654 portv
=realloc(portv
,val
*sizeof(struct port
*));
656 printlog(LOG_ERR
,"Numport resize failed portv %s",strerror(errno
));
659 for (i
=0;i
<NUMOFVLAN
;i
++) {
660 if (vlant
[i
].table
) {
661 vlant
[i
].table
=ba_realloc(vlant
[i
].table
,numports
,val
);
662 if (vlant
[i
].table
== NULL
) {
663 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan table %s",strerror(errno
));
667 if (vlant
[i
].bctag
) {
668 vlant
[i
].bctag
=ba_realloc(vlant
[i
].bctag
,numports
,val
);
669 if (vlant
[i
].bctag
== NULL
) {
670 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan bctag %s",strerror(errno
));
674 if (vlant
[i
].bcuntag
) {
675 vlant
[i
].bcuntag
=ba_realloc(vlant
[i
].bcuntag
,numports
,val
);
676 if (vlant
[i
].bcuntag
== NULL
) {
677 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan bctag %s",strerror(errno
));
681 if (vlant
[i
].notlearning
) {
682 vlant
[i
].notlearning
=ba_realloc(vlant
[i
].notlearning
,numports
,val
);
683 if (vlant
[i
].notlearning
== NULL
) {
684 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan notlearning %s",strerror(errno
));
689 for (i
=numports
;i
<val
;i
++)
700 static int portallocatable(char *arg
)
703 if (sscanf(arg
,"%i %i",&port
,&value
) != 2)
705 if (port
< 0 || port
>= numports
)
707 if (portv
[port
] == NULL
)
710 portv
[port
]->flag
&= ~NOTINPOOL
;
712 portv
[port
]->flag
|= NOTINPOOL
;
716 static int portsetuser(char *arg
)
721 while (*portuid
!= 0 && *portuid
== ' ') portuid
++;
722 while (*portuid
!= 0 && *portuid
!= ' ') portuid
++;
723 while (*portuid
!= 0 && *portuid
== ' ') portuid
++;
724 if (sscanf(arg
,"%i",&port
) != 1 || *portuid
==0)
726 if (port
< 0 || port
>= numports
)
728 if (portv
[port
] == NULL
)
730 if ((pw
=getpwnam(portuid
)) != NULL
)
731 portv
[port
]->user
=pw
->pw_uid
;
732 else if (isdigit(*portuid
))
733 portv
[port
]->user
=atoi(portuid
);
734 else if (strcmp(portuid
,"NONE")==0 || strcmp(portuid
,"ANY")==0)
735 portv
[port
]->user
= -1;
741 static int portsetgroup(char *arg
)
746 while (*portgid
!= 0 && *portgid
== ' ') portgid
++;
747 while (*portgid
!= 0 && *portgid
!= ' ') portgid
++;
748 while (*portgid
!= 0 && *portgid
== ' ') portgid
++;
749 if (sscanf(arg
,"%i",&port
) != 1 || *portgid
==0)
751 if (port
< 0 || port
>= numports
)
753 if (portv
[port
] == NULL
)
755 if ((gr
=getgrnam(portgid
)) != NULL
)
756 portv
[port
]->group
=gr
->gr_gid
;
757 else if (isdigit(*portgid
))
758 portv
[port
]->group
=atoi(portgid
);
759 else if (strcmp(portgid
,"NONE")==0 || strcmp(portgid
,"ANY")==0)
760 portv
[port
]->group
= -1;
766 static int portremove(int val
)
768 if (val
<0 || val
>=numports
)
770 if (portv
[val
] == NULL
)
772 if (portv
[val
]->ep
!= NULL
)
778 static int portcreate(int val
)
781 if (val
<0 || val
>=numports
)
783 if (portv
[val
] != NULL
)
785 port
=alloc_port(val
);
786 if (port
> 0) portv
[port
]->flag
|= NOTINPOOL
;
790 static int epclose(char *arg
)
793 if (sscanf(arg
,"%i %i",&port
,&id
) != 2)
796 return close_ep(port
,id
);
799 static char *port_getuser(uid_t uid
)
810 sprintf(buf
,"%d",uid
);
816 static char *port_getgroup(gid_t gid
)
827 sprintf(buf
,"%d",gid
);
833 static int print_port(FILE *fd
,int i
,int inclinactive
)
836 if (portv
[i
] != NULL
&& (inclinactive
|| portv
[i
]->ep
!=NULL
)) {
837 printoutc(fd
,"Port %04d untagged_vlan=%04d %sACTIVE - %sUnnamed Allocatable",
838 i
,portv
[i
]->vlanuntag
,
839 portv
[i
]->ep
?"":"IN",
840 (portv
[i
]->flag
& NOTINPOOL
)?"NOT ":"");
841 printoutc(fd
," Current User: %s Access Control: (User: %s - Group: %s)",
842 port_getuser(portv
[i
]->curuser
),
843 port_getuser(portv
[i
]->user
),
844 port_getgroup(portv
[i
]->group
));
846 printoutc(fd
," IN: pkts %10lld bytes %20lld",portv
[i
]->pktsin
,portv
[i
]->bytesin
);
847 printoutc(fd
," OUT: pkts %10lld bytes %20lld",portv
[i
]->pktsout
,portv
[i
]->bytesout
);
849 for (ep
=portv
[i
]->ep
; ep
!= NULL
; ep
=ep
->next
)
850 printoutc(fd
," -- endpoint ID %04d module %-12s: %s",ep
->fd_ctl
,
851 portv
[i
]->ms
->modname
,(ep
->descr
)?ep
->descr
:"no endpoint description");
857 static int print_ptable(FILE *fd
,char *arg
)
862 if (i
<0 || i
>=numports
)
865 return print_port(fd
,i
,0);
868 for (i
=0;i
<numports
;i
++)
874 static int print_ptableall(FILE *fd
,char *arg
)
879 if (i
<0 || i
>=numports
)
882 return print_port(fd
,i
,1);
885 for (i
=0;i
<numports
;i
++)
892 static void portzerocounter(int i
)
894 if (portv
[i
] != NULL
) {
898 portv
[i
]->bytesout
=0;
902 static int portresetcounters(char *arg
)
907 if (i
<0 || i
>=numports
)
914 for (i
=0;i
<numports
;i
++)
921 static int portsethub(int val
)
927 portflag(P_SETFLAG
,HUB_TAG
);
929 portflag(P_CLRFLAG
,HUB_TAG
);
933 static int portsetvlan(char *arg
)
936 if (sscanf(arg
,"%i %i",&port
,&vlan
) != 2)
938 /* port NOVLAN is okay here, it means NO untagged traffic */
939 if (vlan
<0 || vlan
> NUMOFVLAN
|| port
< 0 || port
>= numports
)
941 if ((vlan
!= NOVLAN
&& !bac_check(validvlan
,vlan
)) || portv
[port
] == NULL
)
943 int oldvlan
=portv
[port
]->vlanuntag
;
944 portv
[port
]->vlanuntag
=NOVLAN
;
945 hash_delete_port(port
);
946 if (portv
[port
]->ep
!= NULL
) {
947 /*changing active port*/
948 if (oldvlan
!= NOVLAN
)
949 ba_clr(vlant
[oldvlan
].bcuntag
,port
);
950 if (vlan
!= NOVLAN
) {
951 ba_set(vlant
[vlan
].bcuntag
,port
);
952 ba_clr(vlant
[vlan
].bctag
,port
);
955 if (oldvlan
!= NOVLAN
) fstdelport(oldvlan
,port
);
956 if (vlan
!= NOVLAN
) fstaddport(vlan
,port
,0);
959 if (oldvlan
!= NOVLAN
) ba_clr(vlant
[oldvlan
].table
,port
);
960 if (vlan
!= NOVLAN
) ba_set(vlant
[vlan
].table
,port
);
961 portv
[port
]->vlanuntag
=vlan
;
965 static int vlancreate_nocheck(int vlan
)
968 vlant
[vlan
].table
=ba_alloc(numports
);
969 vlant
[vlan
].bctag
=ba_alloc(numports
);
970 vlant
[vlan
].bcuntag
=ba_alloc(numports
);
971 vlant
[vlan
].notlearning
=ba_alloc(numports
);
972 if (vlant
[vlan
].table
== NULL
|| vlant
[vlan
].bctag
== NULL
||
973 vlant
[vlan
].bcuntag
== NULL
)
980 bac_set(validvlan
,NUMOFVLAN
,vlan
);
986 static int vlancreate(int vlan
)
988 if (vlan
> 0 && vlan
< NUMOFVLAN
-1) { /*vlan NOVLAN (0xfff a.k.a. 4095) is reserved */
989 if (bac_check(validvlan
,vlan
))
992 return vlancreate_nocheck(vlan
);
997 static int vlanremove(int vlan
)
999 if (vlan
>= 0 && vlan
< NUMOFVLAN
) {
1000 if (bac_check(validvlan
,vlan
)) {
1001 register int i
,used
=0;
1002 ba_FORALL(vlant
[vlan
].table
,numports
,used
++,i
);
1006 bac_clr(validvlan
,NUMOFVLAN
,vlan
);
1007 free(vlant
[vlan
].table
);
1008 free(vlant
[vlan
].bctag
);
1009 free(vlant
[vlan
].bcuntag
);
1010 free(vlant
[vlan
].notlearning
);
1011 vlant
[vlan
].table
=NULL
;
1012 vlant
[vlan
].bctag
=NULL
;
1013 vlant
[vlan
].bcuntag
=NULL
;
1014 vlant
[vlan
].notlearning
=NULL
;
1016 fstremovevlan(vlan
);
1026 static int vlanaddport(char *arg
)
1029 if (sscanf(arg
,"%i %i",&vlan
,&port
) != 2)
1031 if (vlan
<0 || vlan
>= NUMOFVLAN
-1 || port
< 0 || port
>= numports
)
1033 if (!bac_check(validvlan
,vlan
) || portv
[port
] == NULL
)
1035 if (portv
[port
]->ep
!= NULL
&& portv
[port
]->vlanuntag
!= vlan
) {
1036 /* changing active port*/
1037 ba_set(vlant
[vlan
].bctag
,port
);
1039 fstaddport(vlan
,port
,1);
1042 ba_set(vlant
[vlan
].table
,port
);
1046 static int vlandelport(char *arg
)
1049 if (sscanf(arg
,"%i %i",&vlan
,&port
) != 2)
1051 if (vlan
<0 || vlan
>= NUMOFVLAN
-1 || port
< 0 || port
>= numports
)
1053 if (!bac_check(validvlan
,vlan
) || portv
[port
] == NULL
)
1055 if (portv
[port
]->vlanuntag
== vlan
)
1057 if (portv
[port
]->ep
!= NULL
) {
1058 /*changing active port*/
1059 ba_clr(vlant
[vlan
].bctag
,port
);
1061 fstdelport(vlan
,port
);
1064 ba_clr(vlant
[vlan
].table
,port
);
1065 hash_delete_port(port
);
1069 #define STRSTATUS(PN,V) \
1070 ((ba_check(vlant[(V)].notlearning,(PN))) ? "Discarding" : \
1071 (ba_check(vlant[(V)].bctag,(PN)) || ba_check(vlant[(V)].bcuntag,(PN))) ? \
1072 "Forwarding" : "Learning")
1074 static void vlanprintactive(int vlan
,FILE *fd
)
1077 printoutc(fd
,"VLAN %04d",vlan
);
1079 if (pflag
& FSTP_TAG
) {
1081 printoutc(fd
," ++ FST root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n"
1082 " designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x port %d cost %d age %d",
1083 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
1084 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7],
1085 fsttab
[vlan
]->desbr
[0], fsttab
[vlan
]->desbr
[1], fsttab
[vlan
]->desbr
[2], fsttab
[vlan
]->desbr
[3],
1086 fsttab
[vlan
]->desbr
[4], fsttab
[vlan
]->desbr
[5], fsttab
[vlan
]->desbr
[6], fsttab
[vlan
]->desbr
[7],
1087 fsttab
[vlan
]->rootport
,
1088 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
1089 qtime()-fsttab
[vlan
]->roottimestamp
);
1090 ba_FORALL(vlant
[vlan
].table
,numports
,
1091 ({ int tagged
=portv
[i
]->vlanuntag
!= vlan
;
1093 printoutc(fd
," -- Port %04d tagged=%d act=%d learn=%d forw=%d cost=%d role=%s",
1094 i
, tagged
, 1, !(NOTLEARNING(i
,vlan
)),
1095 (tagged
)?(ba_check(vlant
[vlan
].bctag
,i
) != 0):(ba_check(vlant
[vlan
].bcuntag
,i
) != 0),
1097 (fsttab
[vlan
]->rootport
==i
?"Root":
1098 ((ba_check(fsttab
[vlan
]->backup
,i
)?"Alternate/Backup":"Designated")))
1104 ba_FORALL(vlant
[vlan
].table
,numports
,
1105 ({ int tagged
=portv
[i
]->vlanuntag
!= vlan
;
1107 printoutc(fd
," -- Port %04d tagged=%d active=1 status=%s", i
, tagged
,
1115 static int vlanprint(FILE *fd
,char *arg
)
1120 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
1121 if (bac_check(validvlan
,vlan
))
1122 vlanprintactive(vlan
,fd
);
1128 bac_FORALLFUN(validvlan
,NUMOFVLAN
,vlanprintactive
,fd
);
1132 static void vlanprintelem(int vlan
,FILE *fd
)
1135 printoutc(fd
,"VLAN %04d",vlan
);
1136 ba_FORALL(vlant
[vlan
].table
,numports
,
1137 printoutc(fd
," -- Port %04d tagged=%d active=%d status=%s",
1138 i
, portv
[i
]->vlanuntag
!= vlan
, portv
[i
]->ep
!= NULL
, STRSTATUS(i
,vlan
)),i
);
1141 static int vlanprintall(FILE *fd
,char *arg
)
1146 if (vlan
> 0 && vlan
< NUMOFVLAN
-1) {
1147 if (bac_check(validvlan
,vlan
))
1148 vlanprintelem(vlan
,fd
);
1154 bac_FORALLFUN(validvlan
,NUMOFVLAN
,vlanprintelem
,fd
);
1158 /* NOT sure about the effects of changing address on FSTP */
1161 static int setmacaddr(char *strmac
)
1163 int maci
[ETH_ALEN
],rv
;
1165 if (index(strmac
,':') != NULL
)
1166 rv
=sscanf(strmac
,"%x:%x:%x:%x:%x:%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
1168 rv
=sscanf(strmac
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
1173 for (i
=0;i
<ETH_ALEN
;i
++)
1174 switchmac
[i
]=maci
[i
];
1181 static struct comlist cl
[]={
1182 {"port","============","PORT STATUS MENU",NULL
,NOARG
},
1183 {"port/showinfo","","show port info",showinfo
,NOARG
|WITHFILE
},
1184 {"port/setnumports","N","set the number of ports",portsetnumports
,INTARG
},
1185 /*{"port/setmacaddr","MAC","set the switch MAC address",setmacaddr,STRARG},*/
1186 {"port/sethub","0/1","1=HUB 0=switch",portsethub
,INTARG
},
1187 {"port/setvlan","N VLAN","set port VLAN (untagged)",portsetvlan
,STRARG
},
1188 {"port/create","N","create the port N (inactive|notallocatable)",portcreate
,INTARG
},
1189 {"port/remove","N","remove the port N",portremove
,INTARG
},
1190 {"port/allocatable","N 0/1","Is the port allocatable as unnamed? 1=Y 0=N",portallocatable
,STRARG
},
1191 {"port/setuser","N user","access control: set user",portsetuser
,STRARG
},
1192 {"port/setgroup","N user","access control: set group",portsetgroup
,STRARG
},
1193 {"port/epclose","N ID","remove the endpoint port N/id ID",epclose
,STRARG
},
1195 {"port/resetcounter","[N]","reset the port (N) counters",portresetcounters
,STRARG
},
1197 {"port/print","[N]","print the port/endpoint table",print_ptable
,STRARG
|WITHFILE
},
1198 {"port/allprint","[N]","print the port/endpoint table (including inactive port)",print_ptableall
,STRARG
|WITHFILE
},
1199 {"vlan","============","VLAN MANAGEMENT MENU",NULL
,NOARG
},
1200 {"vlan/create","N","create the VLAN with tag N",vlancreate
,INTARG
},
1201 {"vlan/remove","N","remove the VLAN with tag N",vlanremove
,INTARG
},
1202 {"vlan/addport","N PORT","add port to the vlan N (tagged)",vlanaddport
,STRARG
},
1203 {"vlan/delport","N PORT","add port to the vlan N (tagged)",vlandelport
,STRARG
},
1204 {"vlan/print","[N]","print the list of defined vlan",vlanprint
,STRARG
|WITHFILE
},
1205 {"vlan/allprint","[N]","print the list of defined vlan (including inactive port)",vlanprintall
,STRARG
|WITHFILE
},
1208 void port_init(int initnumports
)
1210 if((numports
=initnumports
) <= 0) {
1211 printlog(LOG_ERR
,"The switch must have at least 1 port\n");
1214 portv
=calloc(numports
,sizeof(struct port
*));
1216 validvlan
=bac_alloc(NUMOFVLAN
);
1217 if (portv
==NULL
|| validvlan
== NULL
) {
1218 printlog(LOG_ERR
,"ALLOC port data structures");
1225 if (vlancreate_nocheck(0) != 0) {
1226 printlog(LOG_ERR
,"ALLOC vlan port data structures");