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 */
6
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>
20
21 #include <config.h>
22 #include <vde.h>
23 #include <vdecommon.h>
24
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"
33
34 #include "packetq.h"
35
36 static int pflag=0;
37 static int numports;
38 #ifdef VDE_PQ2
39 static int stdqlen=128;
40 #endif
41
42 static struct port **portv;
43
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},
60 };
61 #endif
62
63 // for dedugging if needed
64
65 /*
66 void packet_dump (struct packet *p)
67 {
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 }*/
80
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;
92 };
93
94 #define NOTINPOOL 0x8000
95
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
112 };
113
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
119 */
120
121 struct {
122 bitarray table;
123 bitarray bctag;
124 bitarray bcuntag;
125 bitarray notlearning;
126 } vlant[NUMOFVLAN+1];
127 bitarray validvlan;
128
129 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
130
131
alloc_port(unsigned int portno)132 static int alloc_port(unsigned int portno)
133 {
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++)
139 ;
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
151 {
152 DBGOUT(DBGPORTNEW,"%02d", i);
153 EVENTOUT(DBGPORTNEW,i);
154
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);
171 }
172 }
173 return i;
174 }
175 }
176
free_port(unsigned int portno)177 static void free_port(unsigned int portno)
178 {
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);
187 }
188 }
189 }
190
191 /* 1 if user belongs to the group, 0 otherwise) */
user_belongs_to_group(uid_t uid,gid_t gid)192 static int user_belongs_to_group(uid_t uid, gid_t gid)
193 {
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;
210 }
211 }
212 }
213 }
214 endgrent();
215 return 0;
216 }
217 }
218 }
219
220
221 /* Access Control check:
222 returns 0->OK -1->Permission Denied */
checkport_ac(struct port * port,uid_t user)223 static int checkport_ac(struct port *port, uid_t user)
224 {
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;
237 }
238 }
239
240 /* initialize a new endpoint */
setup_ep(int portno,int fd_ctl,int fd_data,uid_t user,struct mod_support * modfun)241 struct endpoint *setup_ep(int portno, int fd_ctl, int fd_data, uid_t user,
242 struct mod_support *modfun)
243 {
244 struct port *port;
245 struct endpoint *ep;
246
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
277 }
278 }),i);
279 if (port->vlanuntag != NOVLAN) {
280 ba_set(vlant[port->vlanuntag].bcuntag,portno);
281 ba_clr(vlant[port->vlanuntag].bctag,portno);
282 }
283 ba_clr(vlant[port->vlanuntag].notlearning,portno);
284 } else {
285 ep->next=port->ep;
286 port->ep=ep;
287 }
288 return ep;
289 }
290 else {
291 if (port->curuser != user)
292 errno=EADDRINUSE;
293 else
294 errno=ENOMEM;
295 return NULL;
296 }
297 }
298 else {
299 errno=ENOMEM;
300 return NULL;
301 }
302 }
303
ep_get_port(struct endpoint * ep)304 int ep_get_port(struct endpoint *ep)
305 {
306 return ep->port;
307 }
308
setup_description(struct endpoint * ep,char * descr)309 void setup_description(struct endpoint *ep, char *descr)
310 {
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;
314 }
315
rec_close_ep(struct endpoint ** pep,int fd_ctl)316 static int rec_close_ep(struct endpoint **pep, int fd_ctl)
317 {
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;
335 }
336
close_ep_port_fd(int portno,int fd_ctl)337 static int close_ep_port_fd(int portno, int fd_ctl)
338 {
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);
359 }
360 return rv;
361 } else
362 return ENXIO;
363 } else
364 return EINVAL;
365 }
366
close_ep(struct endpoint * ep)367 int close_ep(struct endpoint *ep)
368 {
369 return close_ep_port_fd(ep->port, ep->fd_ctl);
370 }
371
372 #ifdef VDE_PQ2
rec_setqlen_ep(struct endpoint * ep,int fd_ctl,int len)373 static int rec_setqlen_ep(struct endpoint *ep, int fd_ctl, int len)
374 {
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;
384 }
385
setqlen_ep_port_fd(int portno,int fd_ctl,int len)386 static int setqlen_ep_port_fd(int portno, int fd_ctl, int len)
387 {
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);
392 }
393 else
394 return ENXIO;
395 } else
396 return EINVAL;
397 }
398 #endif
399
portflag(int op,int f)400 int portflag(int op,int f)
401 {
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;
408 }
409 return oldflag;
410 }
411
412
413 /*********************** sending macro used by Core ******************/
414
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
421
422 #ifndef VDE_PQ2
423 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
424 ({\
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); \
431 } \
432 })
433 #else
434 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN,TMPBUF) \
435 ({\
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);\
446 } \
447 } \
448 })
449 #endif
450
451 #ifdef FSTP
452
453 /* functions for FSTP */
port_send_packet(int portno,void * packet,int len)454 void port_send_packet(int portno, void *packet, int len)
455 {
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
462 }
463
portset_send_packet(bitarray portset,void * packet,int len)464 void portset_send_packet(bitarray portset, void *packet, int len)
465 {
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
475 }
476
477
port_set_status(int portno,int vlan,int status)478 void port_set_status(int portno, int vlan, int status)
479 {
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);
495 }
496 }
497 }
498
port_get_status(int portno,int vlan)499 int port_get_status(int portno, int vlan)
500 {
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;
509 }
510 }
511
port_getcost(int port)512 int port_getcost(int port)
513 {
514 return portv[port]->cost;
515 }
516 #endif
517
518 /************************************ CORE PACKET MGMT *****************************/
519
520 /* TAG2UNTAG packet:
521 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
522 * | Destination | Source |81 00|pvlan| L/T | data
523 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
524 *
525 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
526 * | Destination | Source | L/T | data
527 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
528 *
529 * Destination/Source: 4 byte right shift
530 * Length -4 bytes
531 * Pointer to the packet: +4 bytes
532 * */
533
534 #define TAG2UNTAG(P,LEN) \
535 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
536 (struct packet *)((char *)(P)+4); })
537
538 /* TAG2UNTAG packet:
539 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
540 * | Destination | Source | L/T | data
541 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
542 *
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.
551 */
552
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); })
558
559
560 #ifdef VDE_PQ2
trysendfun(struct endpoint * ep,void * packet,int len)561 static int trysendfun(struct endpoint *ep, void *packet, int len)
562 {
563 int port=ep->port;
564 return portv[port]->ms->sender(ep->fd_ctl, ep->fd_data, packet, len, port);
565 }
566
handle_out_packet(struct endpoint * ep)567 void handle_out_packet(struct endpoint *ep)
568 {
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);
573 }
574 #endif
575
handle_in_packet(struct endpoint * ep,struct packet * packet,int len)576 void handle_in_packet(struct endpoint *ep, struct packet *packet, int len)
577 {
578 int tarport;
579 int vlan,tagged;
580 int port=ep->port;
581
582 if(PACKETFILTER(PKTFILTIN,port,packet,len)) {
583
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*/
610 }
611
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 */
617 }
618 #endif
619 /* The port is in blocked status, no packet received */
620 if (ba_check(vlant[vlan].notlearning,port)) return;
621
622 /* We don't like broadcast source addresses */
623 if(! (IS_BROADCAST(packet->header.src))) {
624
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);
629 }
630 }
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
672 }
673 }
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);
686 }
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);
693 }
694 }
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);
703 }
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);
711 }
712 }
713 #endif
714 } /* if(BROADCAST) */
715 } /* if(HUB) */
716 } /* if(PACKETFILTER) */
717 }
718
719 /**************************************** COMMAND MANAGEMENT ****************************************/
720
showinfo(FILE * fd)721 static int showinfo(FILE *fd)
722 {
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;
734 }
735
portsetnumports(int val)736 static int portsetnumports(int val)
737 {
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);
748 }
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);
755 }
756 }
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);
762 }
763 }
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);
769 }
770 }
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);
776 }
777 }
778 }
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;
788 }
789
portallocatable(char * arg)790 static int portallocatable(char *arg)
791 {
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;
804 }
805
portsetuser(char * arg)806 static int portsetuser(char *arg)
807 {
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;
829 }
830
portsetgroup(char * arg)831 static int portsetgroup(char *arg)
832 {
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;
854 }
855
portremove(int val)856 static int portremove(int val)
857 {
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;
866 }
867
portcreate(int val)868 static int portcreate(int val)
869 {
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;
880 }
881
portcreateauto(FILE * fd)882 static int portcreateauto(FILE* fd)
883 {
884 int port = alloc_port(0);
885
886 if (port < 0)
887 return ENOSPC;
888
889 portv[port]->flag |= NOTINPOOL;
890 printoutc(fd, "Port %04d", port);
891 return 0;
892 }
893
epclose(char * arg)894 static int epclose(char *arg)
895 {
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);
901 }
902
903 #ifdef VDE_PQ2
defqlen(int len)904 static int defqlen(int len)
905 {
906 if (len < 0)
907 return EINVAL;
908 else {
909 stdqlen=len;
910 return 0;
911 }
912 }
913
epqlen(char * arg)914 static int epqlen(char *arg)
915 {
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);
921 }
922 #endif
923
port_getuser(uid_t uid)924 static char *port_getuser(uid_t uid)
925 {
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;
937 }
938 }
939 }
940
port_getgroup(gid_t gid)941 static char *port_getgroup(gid_t gid)
942 {
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;
954 }
955 }
956 }
957
print_port(FILE * fd,int i,int inclinactive)958 static int print_port(FILE *fd,int i,int inclinactive)
959 {
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
980 }
981 return 0;
982 } else
983 return ENXIO;
984 }
985
print_ptable(FILE * fd,char * arg)986 static int print_ptable(FILE *fd,char *arg)
987 {
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);
995 }
996 } else {
997 for (i=0;i<numports;i++)
998 print_port(fd,i,0);
999 return 0;
1000 }
1001 }
1002
print_ptableall(FILE * fd,char * arg)1003 static int print_ptableall(FILE *fd,char *arg)
1004 {
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);
1012 }
1013 } else {
1014 for (i=0;i<numports;i++)
1015 print_port(fd,i,1);
1016 return 0;
1017 }
1018 }
1019
1020 #ifdef PORTCOUNTERS
portzerocounter(int i)1021 static void portzerocounter(int i)
1022 {
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;
1028 }
1029 }
1030
portresetcounters(char * arg)1031 static int portresetcounters(char *arg)
1032 {
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;
1041 }
1042 } else {
1043 for (i=0;i<numports;i++)
1044 portzerocounter(i);
1045 return 0;
1046 }
1047 }
1048 #endif
1049
portsethub(int val)1050 static int portsethub(int val)
1051 {
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;
1060 }
1061
portsetvlan(char * arg)1062 static int portsetvlan(char *arg)
1063 {
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);
1082 }
1083 #ifdef FSTP
1084 if (oldvlan != NOVLAN) fstdelport(oldvlan,port);
1085 if (vlan != NOVLAN) fstaddport(vlan,port,0);
1086 #endif
1087 }
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;
1092 }
1093
vlancreate_nocheck(int vlan)1094 static int vlancreate_nocheck(int vlan)
1095 {
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);
1110 }
1111 return rv;
1112 }
1113 }
1114
vlancreate(int vlan)1115 static int vlancreate(int vlan)
1116 {
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;
1124 }
1125
vlanremove(int vlan)1126 static int vlanremove(int vlan)
1127 {
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;
1148 }
1149 } else
1150 return ENXIO;
1151 } else
1152 return EINVAL;
1153 }
1154
vlanaddport(char * arg)1155 static int vlanaddport(char *arg)
1156 {
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
1170 }
1171 ba_set(vlant[vlan].table,port);
1172 return 0;
1173 }
1174
vlandelport(char * arg)1175 static int vlandelport(char *arg)
1176 {
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
1192 }
1193 ba_clr(vlant[vlan].table,port);
1194 hash_delete_port(port);
1195 return 0;
1196 }
1197
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")
1202
vlanprintactive(int vlan,FILE * fd)1203 static void vlanprintactive(int vlan,FILE *fd)
1204 {
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
1240 }
1241 #endif
1242 }
1243
vlanprint(FILE * fd,char * arg)1244 static int vlanprint(FILE *fd,char *arg)
1245 {
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;
1259 }
1260
vlanprintelem(int vlan,FILE * fd)1261 static void vlanprintelem(int vlan,FILE *fd)
1262 {
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);
1268 }
1269
vlanprintall(FILE * fd,char * arg)1270 static int vlanprintall(FILE *fd,char *arg)
1271 {
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;
1285 }
1286
1287 /* NOT sure about the effects of changing address on FSTP */
1288
1289 #if 0
1290 static int setmacaddr(char *strmac)
1291 {
1292 int maci[ETH_ALEN],rv;
1293
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;
1305 }
1306 }
1307 #endif
1308
port_user(int port)1309 uid_t port_user(int port)
1310 {
1311 if (port<0 || port>=numports || portv[port]==NULL)
1312 return -1;
1313 else
1314 return portv[port]->curuser;
1315 }
1316
port_descr(int portno,int epn)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--)
1327 ;
1328 if (ep)
1329 return ep->descr;
1330 else
1331 return NULL;
1332 }
1333 }
1334 }
1335
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},
1366 };
1367
port_init(int initnumports)1368 void port_init(int initnumports)
1369 {
1370 if((numports=initnumports) <= 0) {
1371 printlog(LOG_ERR,"The switch must have at least 1 port\n");
1372 exit(1);
1373 }
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);
1380 }
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);
1388 }
1389 }
1390