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