1 /*******************************************************************************
2 * input_vlan.c: vlan input method
4 *******************************************************************************
6 *******************************************************************************/
8 /* ???????????????????????????????????????????????????????????????????????????
9 * This works (well, it should :), but should have a good place in horror museum:
10 * - the vlan-capable interfaces are retrieved from a names list, instead
11 * of being read from the system
12 * - the vlan server sucks, and therefore the vlan clients sucks:
13 * - it is unable to process several operations between a login and a logout
14 * A lot of requests could be grouped if it could.
15 * - it is incoherent concerning it's messages (and what it needs to perform
17 * - it is totally unable to handle several mac adresses on a single switch
18 * port (and therefore bridged/hubbed machines)
19 * - however, the API is ok, should be able to handle all futures evolutions,
20 * including vlan-conscient cards.
22 * So there is a lot to do in this file, but not before having reprogrammed the
24 * What would be a good interface to the vlan server ? Here are some ideas:
26 * ??????????????????????????????????????????????????????????????????????????? */
28 /*******************************************************************************
30 *******************************************************************************/
36 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <sys/ioctl.h>
40 #include <sys/soundcard.h>
43 #include <X11/extensions/XShm.h>
48 #include "vlc_thread.h"
52 #include "input_vlan.h"
54 #include "audio_output.h"
57 #include "video_output.h"
60 #include "interface.h"
69 /* List of vlan-capable interfaces names */
70 static const char *psz_ifaces_names[] = { "eth0", "eth1", "eth2", "eth3", "eth4", "eth5", NULL };
75 static int IfaceInfo ( input_vlan_iface_t *p_iface );
76 static int IfaceDependance ( input_vlan_method_t *p_method, int i_iface );
77 static int ServerLogin ( input_vlan_server_t *p_server );
78 static void ServerLogout ( input_vlan_server_t *p_server );
79 static int ServerRequestChange ( input_vlan_server_t *p_server,
80 input_vlan_iface_t *p_iface, int i_vlan );
81 static int ServerRequestInfo ( input_vlan_server_t *p_server,
82 input_vlan_iface_t *p_iface );
84 /*******************************************************************************
85 * input_VlanMethodInit: initialize global vlan method data
86 *******************************************************************************
87 * Initialize vlan input method global data. This function should be called
88 * once before any input thread is created or any call to other input_Vlan*()
89 * function is attempted.
90 *******************************************************************************/
91 int input_VlanMethodInit( input_vlan_method_t *p_method, char *psz_server, int i_port )
93 int i_index; /* interface/servers index */
94 input_vlan_iface_t * p_iface; /* interfaces */
96 /* Build vlan server descriptor */
97 if( BuildInetAddr( &p_method->server.sa_in, psz_server, i_port ) )
102 /* Allocate interfaces array */
103 for( i_index = 0; psz_ifaces_names[i_index] != NULL; i_index++ )
107 p_iface = malloc( sizeof(input_vlan_iface_t) * i_index );
108 if( p_iface == NULL )
113 /* Initialize interfaces array */
114 for( i_index = p_method->i_ifaces = 0; psz_ifaces_names[i_index] != NULL; i_index++ )
116 /* Retrieve interface name */
117 p_iface[p_method->i_ifaces].psz_name = (char *) psz_ifaces_names[i_index];
119 /* Test if interface is vlan-capable */
120 if( !IfaceInfo( &p_iface[p_method->i_ifaces] ) )
122 /* If interface passed first step, login to vlan server */
123 if( !ServerLogin( &p_method->server ) )
125 /* Request informations from server about the interface - if the interface
126 * pass this last test, it is vlan-capable and can be added to the list of
128 if( !ServerRequestInfo( &p_method->server, &p_iface[p_method->i_ifaces]) )
130 /* Check if interface is dependant */
131 if( !IfaceDependance( p_method, p_method->i_ifaces ) )
133 /* Interface is master: initialize properties */
134 p_iface[p_method->i_ifaces].i_default_vlan = p_iface[p_method->i_ifaces].i_vlan;
135 p_iface[p_method->i_ifaces].i_refcount = 0;
136 intf_DbgMsg("input debug: added vlan-capable interface %s (%s)\n",
137 p_iface[p_method->i_ifaces].psz_name,
138 p_iface[p_method->i_ifaces].psz_mac);
143 /* Interface is slave */
144 intf_DbgMsg("input debug: added vlan-capable interface %s (%s), depends from %s\n",
145 p_iface[p_method->i_ifaces].psz_name,
146 p_iface[p_method->i_ifaces].psz_mac,
147 p_iface[p_iface[p_method->i_ifaces].i_master].psz_name );
150 /* Increment size counter */
151 p_method->i_ifaces++;
153 /* Logout from server */
154 ServerLogout( &p_method->server );
159 /* If number of vlan-capable interfaces is null, then desactivate vlans */
160 if( p_method->i_ifaces == 0 )
166 /* Reallocate interfaces array to save memory */
167 p_method->p_iface = realloc( p_iface, sizeof(input_vlan_iface_t) * p_method->i_ifaces );
168 if( p_method->p_iface == NULL )
170 /* Realloc failed, but the previous pointer is still valid */
171 p_method->p_iface = p_iface;
174 /* Initialize lock */
175 vlc_mutex_init( &p_method->lock );
177 intf_Msg("input: vlans input method installed\n", p_method->i_ifaces);
181 /*******************************************************************************
182 * input_VlanMethodFree: free global vlan method data
183 *******************************************************************************
184 * Free resources allocated by input_VlanMethodInit. This function should be
185 * called at the end of the program.
186 *******************************************************************************/
187 void input_VlanMethodFree( input_vlan_method_t *p_method )
189 int i_index; /* server/interface index */
191 /* Leave all remaining vlans */
192 for( i_index = 0; i_index < p_method->i_ifaces; i_index++ )
195 /* Check if interface is still locked */
196 if( p_method->p_iface[i_index].i_refcount )
198 intf_DbgMsg("input debug: interface %s is still vlan-locked\n",
199 p_method->p_iface[i_index].psz_name);
200 p_method->p_iface[i_index].i_refcount = 0;
203 /* Join default (starting) vlan */
204 input_VlanJoin( VLAN_ID( i_index, p_method->p_iface[i_index].i_default_vlan ) );
207 /* Free interfaces array */
208 free( p_method->p_iface );
210 intf_DbgMsg("input debug: vlan method terminated\n");
213 /*******************************************************************************
214 * input_VlanId: get a vlan_id for a given interface
215 *******************************************************************************
216 * Get a vlan_id given a network interface and a vlan number. If psz_iface is
217 * NULL, then the default network interface will be used. A negative value
218 * will be returned in case of error.
219 *******************************************************************************/
220 int input_VlanId( char *psz_iface, int i_vlan )
222 input_vlan_method_t * p_method; /* method global data */
223 int i_index; /* interface index */
225 p_method = &p_program_data->input_vlan_method;
227 /* If psz_iface is NULL, use first (default) interface (if there is one) */
228 if( psz_iface == NULL )
230 return( p_method->i_ifaces ? VLAN_ID( 0, i_vlan ) : -1 );
233 /* Browse all interfaces */
234 for( i_index = 0; i_index < p_program_data->input_vlan_method.i_ifaces ; i_index++ )
236 /* If interface has been found, return */
237 if( !strcmp( p_program_data->input_vlan_method.p_iface[i_index].psz_name, psz_iface ) )
239 return( VLAN_ID( i_index, i_vlan ) );
246 /*******************************************************************************
247 * input_VlanJoin: join a vlan
248 *******************************************************************************
249 * This function will try to join a vlan. If the relevant interface is already
250 * on the good vlan, nothing will be done. Else, and if possible (if the
251 * interface is not locked), the vlan server will be contacted and a change will
252 * be requested. The function will block until the change is effective. Note
253 * that once a vlan is no more used, it's interface should be unlocked using
255 * Non 0 will be returned in case of error.
256 *******************************************************************************/
257 int input_VlanJoin( int i_vlan_id )
259 input_vlan_method_t * p_method; /* method global data */
260 input_vlan_iface_t * p_iface; /* interface (shortcut) */
261 int i_err; /* error indicator */
263 /* Initialize shortcuts, and use master if interface is dependant */
265 p_method = &p_program_data->input_vlan_method;
266 p_iface = &p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ];
267 if( p_iface->i_master >= 0 )
269 p_iface = &p_method->p_iface[ p_iface->i_master ];
273 vlc_mutex_lock( &p_method->lock );
275 /* If the interface is in the wished vlan, increase lock counter */
276 if( p_iface->i_vlan != VLAN_ID_VLAN( i_vlan_id ) )
278 p_iface->i_refcount++;
280 /* If not, if it is not locked, the vlan can be changed */
281 else if( !p_iface->i_refcount )
283 /* Login to server */
284 if( (i_err = !ServerLogin( &p_method->server )) )
287 /* Request vlan change */
288 if( (i_err = !ServerRequestChange( &p_method->server,
289 p_iface, VLAN_ID_VLAN( i_vlan_id ) ) ) )
291 p_iface->i_refcount++;
294 ServerLogout( &p_method->server );
297 /* Else, the vlan is locked and can't be changed */
303 /* Release lock (if this point is reached, the function succeeded) */
304 vlc_mutex_unlock( &p_method->lock );
308 /*******************************************************************************
309 * input_VlanLeave: leave a vlan
310 *******************************************************************************
311 * This function tells the vlan library that the designed interface is no more
312 * locked and than vlan changes can occur.
313 *******************************************************************************/
314 void input_VlanLeave( int i_vlan_id )
316 input_vlan_method_t * p_method; /* method global data */
317 input_vlan_iface_t * p_iface; /* interface (shortcut) */
318 int i_err; /* error indicator */
320 /* Initialize shortcuts, and use master if interface is dependant */
322 p_method = &p_program_data->input_vlan_method;
323 p_iface = &p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ];
324 if( p_iface->i_master >= 0 )
326 p_iface = &p_method->p_iface[ p_iface->i_master ];
330 vlc_mutex_lock( &p_method->lock );
332 /* Decrease reference counter */
333 p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ].i_refcount--;
336 vlc_mutex_unlock( &p_method->lock );
339 /*******************************************************************************
340 * input_VlanRequest: request vlan number for a given interface
341 *******************************************************************************
342 * Request the vlan number (and not id) of a given network interface. A
343 * connection to the server can eventually occur, event if it not the case in
344 * current implementation. A negative number can be returned on error.
345 *******************************************************************************/
346 int input_VlanRequest( char *psz_iface )
348 input_vlan_method_t * p_method; /* method global data */
349 int i_index; /* interface index */
351 p_method = &p_program_data->input_vlan_method;
353 /* If psz_iface is NULL, use first (default) interface (if there is one) -
354 * note that interface 0 can't be dependant, so dependance does not need
356 if( psz_iface == NULL )
358 return( p_method->i_ifaces ? p_method->p_iface[0].i_vlan : -1 );
361 /* Browse all interfaces */
362 for( i_index = 0; i_index < p_method->i_ifaces ; i_index++ )
364 /* If interface has been found, return vlan */
365 if( !strcmp( p_method->p_iface[i_index].psz_name, psz_iface ) )
367 /* If interface is dependant, use master, else return own vlan */
368 return( (p_method->p_iface[i_index].i_master >= 0) ?
369 p_method->p_iface[p_method->p_iface[i_index].i_master].i_vlan :
370 p_method->p_iface[i_index].i_vlan );
374 /* If not found, return an error */
378 /*******************************************************************************
379 * input_VlanSynchronize: resynchronize with vlan server
380 *******************************************************************************
381 * Resynchronize with the vlan server. Vlans for all interfaces are requested
382 * and changed if required. This call may take a lot of time, and is intended
383 * for emergency situations.
384 *******************************************************************************/
385 int input_VlanSynchronize( void )
387 input_vlan_method_t * p_method; /* method global data */
388 input_vlan_iface_t * p_iface; /* interface (shortcut) */
389 int i_index; /* interface index */
390 int i_vlan; /* vlan for current interface */
393 p_method = &p_program_data->input_vlan_method;
394 vlc_mutex_lock( &p_method->lock );
396 for( i_index = 0; i_index < p_method->i_ifaces; i_index++ )
398 p_iface = &p_method->p_iface[ i_index ];
400 /* Ignore dependant interfaces and interfaces for wich login failed */
401 if( (p_iface->i_master < 0) && !ServerLogin( &p_method->server ) )
403 /* Request interface informations */
404 i_vlan = p_iface->i_vlan;
405 if( !ServerRequestInfo( &p_method->server, p_iface ) )
407 /* If synchronization has been lost, then try to resynchronize -
408 * this part is ugly because of the vlan server bug requiring a
409 * logout between two requests */
410 if( p_iface->i_vlan != i_vlan )
412 intf_Msg("input: lost vlan synchronization for interface %s\n",
414 ServerLogout( &p_method->server );
415 if( !ServerLogin( &p_method->server ) )
417 if( !ServerRequestChange( &p_method->server, p_iface, i_vlan ) )
419 intf_Msg("input: retrieved vlan synchronization for interface %s\n",
423 /* Note that when this login fails, then the next logout will
424 * also fail... but I don't want to spend time finding a
425 * clean way to avoid this if the vlan server bug is fixed */
429 ServerLogout( &p_method->server );
434 vlc_mutex_unlock( &p_method->lock );
438 /* following functions are local */
440 /*******************************************************************************
441 * IfaceInfo: read info about an interface
442 *******************************************************************************
443 * This function reads informations about a network interface. It should return
444 * 0 and updated interface informations for vlan capable interfaces, and non 0
445 * if interface is not vlan-capable or informations request failed.
446 *******************************************************************************/
447 static int IfaceInfo( input_vlan_iface_t *p_iface )
452 /* Copy interface name */
453 strcpy(device.ifr_name, p_iface->psz_name);
455 /* Open a datagram socket */
456 i_socket = socket(AF_INET, SOCK_DGRAM, 0);
459 intf_ErrMsg("input error: unable to open socket on %s: %s\n",
460 p_iface->psz_name, strerror(errno));
464 /* Read IP address */
465 if(ioctl(i_socket, SIOCGIFDSTADDR, &device) < 0)
467 intf_ErrMsg("input error: can not read IP address for %s: %s\n",
468 p_iface->psz_name, strerror(errno));
471 memcpy( &p_iface->sa_in, &device.ifr_hwaddr, sizeof(struct sockaddr_in));
473 /* Read MAC address */
474 if(ioctl(i_socket, SIOCGIFHWADDR, &device) < 0)
476 intf_ErrMsg("input error: can not read MAC address for %s: %s\n",
477 p_iface->psz_name, strerror(errno));
481 /* Translate MAC address to ASCII standard */
482 sprintf(p_iface->psz_mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
483 device.ifr_hwaddr.sa_data[0]&0xff,
484 device.ifr_hwaddr.sa_data[1]&0xff,
485 device.ifr_hwaddr.sa_data[2]&0xff,
486 device.ifr_hwaddr.sa_data[3]&0xff,
487 device.ifr_hwaddr.sa_data[4]&0xff,
488 device.ifr_hwaddr.sa_data[5]&0xff);
493 /*******************************************************************************
494 * IfaceDependance: check interface dependance
495 *******************************************************************************
496 * Check if an interface designed by it's index is dependant from another one.
497 * All the interfaces from 0 to i_index excluded are tested. If a 'master'
498 * interface is found, then the 'i_master' field is set to a positive value.
499 * Non 0 is returned if the interface is dependant.
500 *******************************************************************************/
501 static int IfaceDependance( input_vlan_method_t *p_method, int i_iface )
503 int i_index; /* interface index */
505 for( i_index = 0; i_index < i_iface; i_index++ )
507 /* Two interface are dependant if they are on the same switch and
509 if( ( p_method->p_iface[i_index].i_switch == p_method->p_iface[i_iface].i_switch )
510 && ( p_method->p_iface[i_index].i_port == p_method->p_iface[i_iface].i_port ) )
512 /* Interface is slave */
513 p_method->p_iface[i_iface].i_master = i_index;
518 /* Interface is master */
519 p_method->p_iface[i_iface].i_master = -1;
523 /*******************************************************************************
524 * ServerLogin: login to a vlan server
525 *******************************************************************************
526 * Initiate login sequence to a vlan server: open a socket, bind it and send
527 * login sequence. If the login fails for any reason, non 0 is returned.
528 *******************************************************************************/
529 static int ServerLogin( input_vlan_server_t *p_server )
531 struct sockaddr_in sa_client; /* client address */
532 char psz_msg[VLAN_SERVER_MSG_LENGTH + 1];/* server message */
533 int i_bytes; /* number of bytes read */
535 psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0'; /* make sure the string ends */
537 /* Initialize local socket */
538 BuildInetAddr( &sa_client, NULL, 0 );
539 p_server->i_socket = socket(AF_INET, SOCK_STREAM, 0);
540 if( p_server->i_socket < 0 )
542 /* Error: return an error */
543 intf_ErrMsg("input error: can not open socket (%s)\n", strerror(errno));
547 /* Bind the server socket to client */
548 if( bind( p_server->i_socket, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
550 /* Error: close socket and return an error */
551 intf_ErrMsg("input error: can not bind socket (%s)\n", strerror(errno));
552 close( p_server->i_socket );
556 /* Try to connect to the VLANserver */
557 if( connect( p_server->i_socket, (struct sockaddr *) &p_server->sa_in,
558 sizeof(p_server->sa_in)) < 0)
560 /* Error: close socket and return an error */
561 intf_ErrMsg("input error: unable to connect to the VLAN server (%s)\n",
563 close( p_server->i_socket );
567 /* Send login message */
568 snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d %s %s %s\n",
569 VLAN_LOGIN_REQUEST, VLAN_CLIENT_VERSION,
570 p_server->psz_login, p_server->psz_passwd );
571 if( send(p_server->i_socket, psz_msg, sizeof(char) * strlen( psz_msg ), 0) < 0)
573 intf_ErrMsg("input error: unable to login to the VLANserver: %s",
575 close( p_server->i_socket );
579 /* Listen to response */
580 i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
583 intf_ErrMsg("input error: no response from VLANserver: %s\n",
585 ServerLogout( p_server );
589 /* Parse answer to login request */
590 psz_msg[ i_bytes ] = '\0'; /* terminate string */
591 if( atoi(psz_msg) == VLAN_LOGIN_REJECTED )
593 intf_ErrMsg("input error: login rejected by VLANserver: %s\n", psz_msg);
594 ServerLogout( p_server );
597 else if( atoi(psz_msg) != VLAN_LOGIN_ANSWER )
599 intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
600 ServerLogout( p_server );
604 intf_DbgMsg("input debug: VLANserver login ok.\n");
608 /*******************************************************************************
609 * ServerLogout: logout from a vlan server
610 *******************************************************************************
611 * Logout from a vlan server. This function sends the logout message to the
612 * server and close the socket.
613 *******************************************************************************/
614 static void ServerLogout( input_vlan_server_t *p_server )
616 char psz_msg[VLAN_SERVER_MSG_LENGTH + 1]; /* server message */
618 psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0'; /* make sure the string ends */
621 snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d\n", VLAN_LOGOUT);
622 if( send(p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
624 intf_ErrMsg("input error: can't send logout message to VLANserver: %s\n",
629 if( close(p_server->i_socket) < 0)
631 intf_ErrMsg("input error: unable to close socket: %s\n", strerror(errno));
634 intf_DbgMsg("input debug: VLANserver logout ok\n");
637 /*******************************************************************************
638 * ServerRequestChange: request vlan change from a server
639 *******************************************************************************
640 * Request vlan change from a vlan server. The client must be logged in. If the
641 * change succeeded, the interface structure is updated. Note that only masters
642 * should be sent to this function.
643 *******************************************************************************/
644 static int ServerRequestChange( input_vlan_server_t *p_server,
645 input_vlan_iface_t *p_iface, int i_vlan )
647 char psz_msg[VLAN_SERVER_MSG_LENGTH + 1]; /* server message */
648 int i_bytes; /* number of bytes read */
650 psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0'; /* make sure the string ends */
653 snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d %s %s %d %d",
654 VLAN_CHANGE_REQUEST, p_iface->psz_mac,
655 inet_ntoa(p_iface->sa_in.sin_addr), i_vlan, p_iface->i_vlan);
656 if( send( p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
658 intf_ErrMsg("input error: unable to send request to VLANserver: %s\n",
663 /* Listen to response */
664 i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
667 intf_ErrMsg("input error: no response from VLANserver: %s",
672 /* Parse answer to vlan request */
673 psz_msg[ i_bytes ] = '\0'; /* terminate string */
674 if( atoi( psz_msg ) == VLAN_CHANGE_REJECTED )
676 intf_ErrMsg("input error: change request rejected by VLANserver: %s\n", psz_msg );
679 else if( atoi( psz_msg ) != VLAN_CHANGE_ANSWER )
681 intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
685 /* ?? send packet for the switch to learn mac again */
687 /* Update interface and return */
688 intf_DbgMsg("input debug: interface %s moved to vlan %d\n",
689 p_iface->psz_name, i_vlan );
690 p_iface->i_vlan = i_vlan;
694 /*******************************************************************************
695 * ServerRequestInfo: ask current vlan to server
696 *******************************************************************************
697 * Request current vlan from a vlan server. The client must be logged in. This
698 * function updates the p_iface structure or returns non 0. Note that only
699 * masters should be sent to this function.
700 *******************************************************************************/
701 static int ServerRequestInfo( input_vlan_server_t *p_server,
702 input_vlan_iface_t *p_iface )
704 char psz_msg[VLAN_SERVER_MSG_LENGTH + 1]; /* server message */
705 int i_bytes; /* number of bytes read */
706 int i_switch; /* switch number */
707 int i_port; /* port number */
708 int i_vlan; /* vlan number */
709 int i_sharers; /* number of mac addresses on this port */
711 psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0'; /* make sure the string ends */
714 snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d", VLAN_INFO_REQUEST);
715 if( send( p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
717 intf_ErrMsg("input error: unable to send request to VLANserver: %s\n",
722 /* Listen to response */
723 i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
726 intf_ErrMsg("input error: no response from VLANserver: %s",
731 /* Parse answer to vlan request */
732 psz_msg[ i_bytes ] = '\0'; /* terminate string */
733 if( atoi( psz_msg ) == VLAN_INFO_REJECTED )
735 intf_ErrMsg("input error: info request rejected by VLANserver: %s\n", psz_msg );
738 else if( atoi( psz_msg ) != VLAN_INFO_ANSWER )
740 intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
743 else if( sscanf(psz_msg, "%*d %d %d %d %d", &i_switch, &i_port, &i_vlan, &i_sharers) != 4 )
745 intf_ErrMsg("input error: invalid answer from VLAN server: %s\n", psz_msg);
749 /* Update interface and return */
750 intf_DbgMsg("input debug: interface %s is on switch %d, port %d, vlan %d, %d sharers\n",
751 p_iface->psz_name, i_switch, i_port, i_vlan, i_sharers);
752 p_iface->i_switch = i_switch;
753 p_iface->i_port = i_port;
754 p_iface->i_vlan = i_vlan;
755 p_iface->i_sharers = i_sharers;