]> git.sesse.net Git - vlc/blob - src/input/input_vlan.c
A tout kass�.
[vlc] / src / input / input_vlan.c
1 /*******************************************************************************
2  * input_vlan.c: vlan input method
3  * (c)1999 VideoLAN
4  *******************************************************************************
5  * ?? 
6  *******************************************************************************/
7
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
16  *        an operation
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.
21  *
22  * So there is a lot to do in this file, but not before having reprogrammed the
23  * vlan server !
24  * What would be a good interface to the vlan server ? Here are some ideas:
25  *      ( later ! )
26  * ??????????????????????????????????????????????????????????????????????????? */
27
28 /*******************************************************************************
29  * Preamble
30  *******************************************************************************/
31 #include "vlc.h"
32
33 /*#include <errno.h>
34 #include <pthread.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <arpa/inet.h>
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <sys/ioctl.h>
44 #include <sys/soundcard.h>
45 #include <sys/uio.h>
46 #include <X11/Xlib.h>
47 #include <X11/extensions/XShm.h>
48
49 #include "config.h"
50 #include "common.h"
51 #include "mtime.h"
52 #include "vlc_thread.h"
53 #include "netutils.h"
54
55 #include "input.h"
56 #include "input_vlan.h"
57
58 #include "audio_output.h"
59
60 #include "video.h"
61 #include "video_output.h"
62
63 #include "xconsole.h"
64 #include "interface.h"
65 #include "intf_msg.h"
66
67 #include "pgm_data.h"*/
68
69 /*******************************************************************************
70  * input_vlan_iface_t: vlan-capable network interface
71  *******************************************************************************
72  * This structure describes the abilities of a network interface capable of
73  * vlan management. Note that an interface could have several IP adresses, but
74  * since only the MAC address is used to change vlan, only one needs to be
75  * retrieved.
76  * ?? it could be interesting to send a port id on vlan request, to know if two
77  * interfaces are dependant regarding vlan changes.
78  *******************************************************************************/
79 typedef struct
80 {
81     char *                  psz_name;                        /* interface name */
82     struct sockaddr_in      sa_in;                             /* interface IP */
83     char                    psz_mac[20];                      /* interface MAC */
84
85     /* Hardware properties */
86     int                     i_master;                /* master interface index */
87     int                     i_switch;                         /* switch number */
88     int                     i_port;                             /* port number */
89     int                     i_sharers;          /* number of MACs on this port */
90     
91     /* Vlan properties - these are only used if i_master is negative */
92     int                     i_refcount;                       /* locks counter */
93     int                     i_vlan;                            /* current vlan */
94     int                     i_default_vlan;                    /* default vlan */
95 } input_vlan_iface_t;
96
97 /*******************************************************************************
98  * input_vlan_server_t: vlan server
99  *******************************************************************************
100  * This structure describes a vlan server.
101  *******************************************************************************/
102 typedef struct
103 {
104     struct sockaddr_in  sa_in;                               /* server address */
105     int                 i_socket;                         /* socket descriptor */
106
107     /* Login informations */
108     char *              psz_login;                             /* server login */
109     char *              psz_passwd;                         /* server password */
110 } input_vlan_server_t;
111
112 /*******************************************************************************
113  * vlan_method_data_t
114  *******************************************************************************
115  * Store global vlan library data.
116  *******************************************************************************/
117 typedef struct input_vlan_method_s
118 {    
119     vlc_mutex_t             lock;                              /* library lock */
120
121     /* Server */
122     input_vlan_server_t     server;                             /* vlan server */
123  
124     /* Network interfaces */
125     int                     i_ifaces;   /* number of vlan-compliant interfaces */
126     input_vlan_iface_t *    p_iface;                             /* interfaces */
127 } input_vlan_method_t;
128
129 /*
130  * Constants
131  */
132
133 /* List of vlan-capable interfaces names */
134 static const char *psz_ifaces_names[] = { "eth0", "eth1", "eth2", "eth3", "eth4", "eth5", NULL };
135    
136 /*
137  * Local prototypes
138  */
139 static int  IfaceInfo               ( input_vlan_iface_t *p_iface );
140 static int  IfaceDependance         ( input_vlan_method_t *p_method, int i_iface );
141 static int  ServerLogin             ( input_vlan_server_t *p_server );
142 static void ServerLogout            ( input_vlan_server_t *p_server );
143 static int  ServerRequestChange     ( input_vlan_server_t *p_server,
144                                       input_vlan_iface_t *p_iface, int i_vlan );
145 static int  ServerRequestInfo       ( input_vlan_server_t *p_server,
146                                       input_vlan_iface_t *p_iface );
147
148 /*******************************************************************************
149  * input_VlanCreate: initialize global vlan method data
150  *******************************************************************************
151  * Initialize vlan input method global data. This function should be called
152  * once before any input thread is created or any call to other input_Vlan*()
153  * function is attempted.
154  *******************************************************************************/
155 int input_VlanCreate( void )
156 {
157     char *                  psz_server; // ??? get from environment
158     int                     i_port;     // ??? get from environment
159     int                     i_index;                /* interface/servers index */
160     input_vlan_iface_t *    p_iface;                             /* interfaces */
161     input_vlan_method_t *p_method = p_main->p_input_vlan; //??
162
163     /* Build vlan server descriptor */
164     if( BuildInetAddr( &p_method->server.sa_in, psz_server, i_port ) )
165     {
166         return( -1 );        
167     }    
168
169     /* Allocate interfaces array */
170     for( i_index = 0; psz_ifaces_names[i_index] != NULL; i_index++ )
171     {
172         ;        
173     }    
174     p_iface = malloc( sizeof(input_vlan_iface_t) * i_index );
175     if( p_iface == NULL )
176     {        
177         return( ENOMEM );
178     }   
179
180     /* Initialize interfaces array */
181     for( i_index = p_method->i_ifaces = 0; psz_ifaces_names[i_index] != NULL; i_index++ )
182     {
183         /* Retrieve interface name */
184         p_iface[p_method->i_ifaces].psz_name = (char *) psz_ifaces_names[i_index];
185
186         /* Test if interface is vlan-capable */
187         if( !IfaceInfo( &p_iface[p_method->i_ifaces] ) )
188         {
189             /* If interface passed first step, login to vlan server */
190             if( !ServerLogin( &p_method->server ) )
191             {
192                 /* Request informations from server about the interface - if the interface
193                  * pass this last test, it is vlan-capable and can be added to the list of
194                  * interfaces. */
195                 if( !ServerRequestInfo( &p_method->server, &p_iface[p_method->i_ifaces]) )
196                 {
197                     /* Check if interface is dependant */
198                     if( !IfaceDependance( p_method, p_method->i_ifaces ) )
199                     {                        
200                         /* Interface is master: initialize properties */
201                         p_iface[p_method->i_ifaces].i_default_vlan = p_iface[p_method->i_ifaces].i_vlan;
202                         p_iface[p_method->i_ifaces].i_refcount = 0;
203                         intf_DbgMsg("input debug: added vlan-capable interface %s (%s)\n", 
204                                     p_iface[p_method->i_ifaces].psz_name, 
205                                     p_iface[p_method->i_ifaces].psz_mac);
206                     }          
207 #ifdef DEBUG
208                     else
209                     {
210                         /* Interface is slave */
211                         intf_DbgMsg("input debug: added vlan-capable interface %s (%s), depends from %s\n",
212                                     p_iface[p_method->i_ifaces].psz_name, 
213                                     p_iface[p_method->i_ifaces].psz_mac,
214                                     p_iface[p_iface[p_method->i_ifaces].i_master].psz_name );
215                     }
216 #endif
217                     /* Increment size counter */            
218                     p_method->i_ifaces++;
219                 }
220                 /* Logout from server */
221                 ServerLogout( &p_method->server );    
222             }
223         }
224     }
225
226     /* If number of vlan-capable interfaces is null, then desactivate vlans */
227     if( p_method->i_ifaces == 0 )
228     {
229         free( p_iface );        
230         return( -1 );        
231     }
232     
233     /* Reallocate interfaces array to save memory */
234     p_method->p_iface = realloc( p_iface, sizeof(input_vlan_iface_t) * p_method->i_ifaces );
235     if( p_method->p_iface == NULL )
236     {        
237         /* Realloc failed, but the previous pointer is still valid */
238         p_method->p_iface = p_iface;
239     }      
240
241     /* Initialize lock */
242     vlc_mutex_init( &p_method->lock );
243
244     intf_Msg("input: vlans input method installed\n", p_method->i_ifaces);
245     return( 0 );    
246 }
247
248 /*******************************************************************************
249  * input_VlanDestroy: free global vlan method data
250  *******************************************************************************
251  * Free resources allocated by input_VlanMethodInit. This function should be
252  * called at the end of the program.
253  *******************************************************************************/
254 void input_VlanDestroy( void )
255 {
256     int i_index;                                     /* server/interface index */
257     input_vlan_method_t *p_method = p_main->p_input_vlan; // ??
258
259     /* Leave all remaining vlans */
260     for( i_index = 0; i_index < p_method->i_ifaces; i_index++ )
261     {
262 #ifdef DEBUG
263         /* Check if interface is still locked */
264         if( p_method->p_iface[i_index].i_refcount )
265         {
266             intf_DbgMsg("input debug: interface %s is still vlan-locked\n", 
267                         p_method->p_iface[i_index].psz_name);
268             p_method->p_iface[i_index].i_refcount = 0;
269         }        
270 #endif
271         /* Join default (starting) vlan */
272         input_VlanJoin( VLAN_ID( i_index, p_method->p_iface[i_index].i_default_vlan ) );        
273     }    
274
275     /* Free interfaces array */
276     free( p_method->p_iface );    
277
278     intf_DbgMsg("input debug: vlan method terminated\n");
279 }
280
281 /*******************************************************************************
282  * input_VlanId: get a vlan_id for a given interface
283  *******************************************************************************
284  * Get a vlan_id given a network interface and a vlan number. If psz_iface is
285  * NULL, then the default network interface will be used. A negative value
286  * will be returned in case of error.
287  *******************************************************************************/
288 int input_VlanId( char *psz_iface, int i_vlan )
289 {
290     input_vlan_method_t *   p_method;                    /* method global data */
291     int                     i_index;                        /* interface index */
292
293     p_method = p_main->p_input_vlan;
294
295     /* If psz_iface is NULL, use first (default) interface (if there is one) */
296     if( psz_iface == NULL )
297     {           
298         return( p_method->i_ifaces ? VLAN_ID( 0, i_vlan ) : -1 );    
299     }
300         
301     /* Browse all interfaces */
302     for( i_index = 0; i_index < p_main->p_input_vlan->i_ifaces ; i_index++ )
303     {
304         /* If interface has been found, return */
305         if( !strcmp( p_main->p_input_vlan->p_iface[i_index].psz_name, psz_iface ) )
306         {
307             return( VLAN_ID( i_index, i_vlan ) );
308         }        
309     }    
310     
311     return( -1 );
312 }
313
314 /*******************************************************************************
315  * input_VlanJoin: join a vlan
316  *******************************************************************************
317  * This function will try to join a vlan. If the relevant interface is already
318  * on the good vlan, nothing will be done. Else, and if possible (if the 
319  * interface is not locked), the vlan server will be contacted and a change will
320  * be requested. The function will block until the change is effective. Note
321  * that once a vlan is no more used, it's interface should be unlocked using
322  * input_VlanLeave().
323  * Non 0 will be returned in case of error.
324  *******************************************************************************/
325 int input_VlanJoin( int i_vlan_id )
326 {    
327     input_vlan_method_t *   p_method;                    /* method global data */
328     input_vlan_iface_t *    p_iface;                   /* interface (shortcut) */
329     int                     i_err;                          /* error indicator */
330
331     /* Initialize shortcuts, and use master if interface is dependant */
332     i_err = 0;    
333     p_method = p_main->p_input_vlan;
334     p_iface = &p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ];
335     if( p_iface->i_master >= 0 )
336     {
337         p_iface = &p_method->p_iface[ p_iface->i_master ];     
338     }
339     
340     /* Get lock */
341     vlc_mutex_lock( &p_method->lock );
342     
343     /* If the interface is in the wished vlan, increase lock counter */
344     if( p_iface->i_vlan != VLAN_ID_VLAN( i_vlan_id ) )
345     {
346         p_iface->i_refcount++;         
347     }
348     /* If not, if it is not locked, the vlan can be changed */
349     else if( !p_iface->i_refcount )
350     {        
351         /* Login to server */
352         if( (i_err = !ServerLogin( &p_method->server )) )
353         {
354
355             /* Request vlan change */
356             if( (i_err = !ServerRequestChange( &p_method->server, 
357                                                p_iface, VLAN_ID_VLAN( i_vlan_id ) ) ) )
358             {
359                 p_iface->i_refcount++;   
360             }            
361             /* Logout */
362             ServerLogout( &p_method->server );
363         }
364     }
365     /* Else, the vlan is locked and can't be changed */
366     else
367     {
368         i_err = 1;
369     }                    
370
371     /* Release lock (if this point is reached, the function succeeded) */
372     vlc_mutex_unlock( &p_method->lock );       
373     return( i_err );    
374 }
375
376 /*******************************************************************************
377  * input_VlanLeave: leave a vlan
378  *******************************************************************************
379  * This function tells the vlan library that the designed interface is no more
380  * locked and than vlan changes can occur.
381  *******************************************************************************/
382 void input_VlanLeave( int i_vlan_id )
383 {
384     input_vlan_method_t *   p_method;                    /* method global data */
385     input_vlan_iface_t *    p_iface;                   /* interface (shortcut) */
386     int                     i_err;                          /* error indicator */
387
388     /* Initialize shortcuts, and use master if interface is dependant */
389     i_err = 0;    
390     p_method = p_main->p_input_vlan;
391     p_iface = &p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ];
392     if( p_iface->i_master >= 0 )
393     {
394         p_iface = &p_method->p_iface[ p_iface->i_master ];     
395     }
396     
397     /* Get lock */
398     vlc_mutex_lock( &p_method->lock );
399
400     /* Decrease reference counter */
401     p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ].i_refcount--;    
402
403     /* Release lock */
404     vlc_mutex_unlock( &p_method->lock );   
405 }
406
407 /*******************************************************************************
408  * input_VlanRequest: request vlan number for a given interface
409  *******************************************************************************
410  * Request the vlan number (and not id) of a given network interface. A 
411  * connection to the server can eventually occur, event if it not the case in
412  * current implementation. A negative number can be returned on error.
413  *******************************************************************************/
414 int input_VlanRequest( char *psz_iface )
415 {
416     input_vlan_method_t *   p_method;                    /* method global data */
417     int                     i_index;                        /* interface index */
418     
419     p_method = p_main->p_input_vlan;
420
421     /* If psz_iface is NULL, use first (default) interface (if there is one) - 
422      * note that interface 0 can't be dependant, so dependance does not need
423      * to be tested */
424     if( psz_iface == NULL )
425     {           
426         return( p_method->i_ifaces ? p_method->p_iface[0].i_vlan : -1 );    
427     }
428         
429     /* Browse all interfaces */
430     for( i_index = 0; i_index < p_method->i_ifaces ; i_index++ )
431     {
432         /* If interface has been found, return vlan */
433         if( !strcmp( p_method->p_iface[i_index].psz_name, psz_iface ) )
434         {
435             /* If interface is dependant, use master, else return own vlan */
436             return( (p_method->p_iface[i_index].i_master >= 0) ?
437                     p_method->p_iface[p_method->p_iface[i_index].i_master].i_vlan :
438                     p_method->p_iface[i_index].i_vlan );
439         }        
440     }    
441
442     /* If not found, return an error */
443     return( -1 );    
444 }
445
446 /*******************************************************************************
447  * input_VlanSynchronize: resynchronize with vlan server
448  *******************************************************************************
449  * Resynchronize with the vlan server. Vlans for all interfaces are requested
450  * and changed if required. This call may take a lot of time, and is intended
451  * for emergency situations.
452  *******************************************************************************/
453 int input_VlanSynchronize( void )
454 {
455     input_vlan_method_t *   p_method;                    /* method global data */
456     input_vlan_iface_t *    p_iface;                   /* interface (shortcut) */
457     int                     i_index;                        /* interface index */
458     int                     i_vlan;              /* vlan for current interface */
459     
460     /* Get lock */
461     p_method = p_main->p_input_vlan;
462     pthread_mutex_lock( &p_method->lock );
463 /* ??
464     p_method = &p_program_data->input_vlan_method;
465     vlc_mutex_lock( &p_method->lock );
466 */
467
468     for( i_index = 0; i_index < p_method->i_ifaces; i_index++ )
469     {        
470         p_iface = &p_method->p_iface[ i_index ];
471         
472         /* Ignore dependant interfaces and interfaces for wich login failed */
473         if( (p_iface->i_master < 0) && !ServerLogin( &p_method->server ) )
474         {            
475             /* Request interface informations */
476             i_vlan = p_iface->i_vlan;
477             if( !ServerRequestInfo( &p_method->server, p_iface ) )
478             {
479                 /* If synchronization has been lost, then try to resynchronize -
480                  * this part is ugly because of the vlan server bug requiring a 
481                  * logout between two requests */
482                 if( p_iface->i_vlan != i_vlan )
483                 {
484                     intf_Msg("input: lost vlan synchronization for interface %s\n", 
485                              p_iface->psz_name );                    
486                     ServerLogout( &p_method->server );
487                     if( !ServerLogin( &p_method->server ) )
488                     {
489                         if( !ServerRequestChange( &p_method->server, p_iface, i_vlan ) )
490                         {
491                             intf_Msg("input: retrieved vlan synchronization for interface %s\n", 
492                                      p_iface->psz_name );          
493                         }                        
494                     }
495                     /* Note that when this login fails, then the next logout will
496                      * also fail... but I don't want to spend time finding a 
497                      * clean way to avoid this if the vlan server bug is fixed */
498                 }                                
499             }            
500             /* Logout */
501             ServerLogout( &p_method->server );            
502         }        
503     }    
504
505     /* Release lock */
506     vlc_mutex_unlock( &p_method->lock );   
507     return( 0 );    
508 }
509
510 /* following functions are local */
511
512 /*******************************************************************************
513  * IfaceInfo: read info about an interface
514  *******************************************************************************
515  * This function reads informations about a network interface. It should return
516  * 0 and updated interface informations for vlan capable interfaces, and non 0
517  * if interface is not vlan-capable or informations request failed.
518  *******************************************************************************/
519 static int IfaceInfo( input_vlan_iface_t *p_iface )
520 {
521     int             i_socket;
522     struct ifreq    device;
523
524     /* Copy interface name */
525     strcpy(device.ifr_name, p_iface->psz_name);
526
527     /* Open a datagram socket */
528     i_socket = socket(AF_INET, SOCK_DGRAM, 0);
529     if(i_socket < 0)
530     {
531         intf_ErrMsg("input error: unable to open socket on %s: %s\n", 
532                     p_iface->psz_name, strerror(errno));
533         return( -1 );        
534     }
535
536     /* Read IP address */
537     if(ioctl(i_socket, SIOCGIFDSTADDR, &device) < 0)
538     {
539         intf_ErrMsg("input error: can not read IP address for %s: %s\n", 
540                     p_iface->psz_name, strerror(errno));
541         return( -1 );
542     }
543     memcpy( &p_iface->sa_in, &device.ifr_hwaddr, sizeof(struct sockaddr_in));
544
545     /* Read MAC address */
546     if(ioctl(i_socket, SIOCGIFHWADDR, &device) < 0)
547     {
548         intf_ErrMsg("input error: can not read MAC address for %s: %s\n",
549                     p_iface->psz_name, strerror(errno));
550         return( -1 );
551     }
552
553     /* Translate MAC address to ASCII standard */
554     sprintf(p_iface->psz_mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
555             device.ifr_hwaddr.sa_data[0]&0xff,
556             device.ifr_hwaddr.sa_data[1]&0xff,
557             device.ifr_hwaddr.sa_data[2]&0xff,
558             device.ifr_hwaddr.sa_data[3]&0xff,
559             device.ifr_hwaddr.sa_data[4]&0xff,
560             device.ifr_hwaddr.sa_data[5]&0xff);
561
562     return( 0 );
563 }
564
565 /*******************************************************************************
566  * IfaceDependance: check interface dependance
567  *******************************************************************************
568  * Check if an interface designed by it's index is dependant from another one.
569  * All the interfaces from 0 to i_index excluded are tested. If a 'master'  
570  * interface is found, then the 'i_master' field is set to a positive value.
571  * Non 0 is returned if the interface is dependant.
572  *******************************************************************************/
573 static int IfaceDependance( input_vlan_method_t *p_method, int i_iface )
574 {
575     int i_index;                                            /* interface index */
576     
577     for( i_index = 0; i_index < i_iface; i_index++ )
578     {
579         /* Two interface are dependant if they are on the same switch and
580          * port */
581         if( ( p_method->p_iface[i_index].i_switch == p_method->p_iface[i_iface].i_switch )
582             && ( p_method->p_iface[i_index].i_port == p_method->p_iface[i_iface].i_port ) )
583         {
584             /* Interface is slave */
585             p_method->p_iface[i_iface].i_master = i_index;
586             return( 1 );            
587         }        
588     }
589
590     /* Interface is master */
591     p_method->p_iface[i_iface].i_master = -1;    
592     return( 0 );    
593 }
594
595 /*******************************************************************************
596  * ServerLogin: login to a vlan server
597  *******************************************************************************
598  * Initiate login sequence to a vlan server: open a socket, bind it and send
599  * login sequence. If the login fails for any reason, non 0 is returned.
600  *******************************************************************************/
601 static int ServerLogin( input_vlan_server_t *p_server )
602 {
603     struct sockaddr_in  sa_client;                           /* client address */
604     char                psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];/* server message */
605     int                 i_bytes;                       /* number of bytes read */    
606
607     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
608
609     /* Initialize local socket */
610     BuildInetAddr( &sa_client, NULL, 0 );
611     p_server->i_socket = socket(AF_INET, SOCK_STREAM, 0);
612     if( p_server->i_socket < 0 )
613     {
614         /* Error: return an error */
615         intf_ErrMsg("input error: can not open socket (%s)\n", strerror(errno));
616         return( errno );
617     }
618            
619     /* Bind the server socket to client */
620     if( bind( p_server->i_socket, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
621     {
622         /* Error: close socket and return an error */
623         intf_ErrMsg("input error: can not bind socket (%s)\n", strerror(errno));        
624         close( p_server->i_socket );
625         return( errno );
626     }
627
628     /* Try to connect to the VLANserver */
629     if( connect( p_server->i_socket, (struct sockaddr *) &p_server->sa_in, 
630                  sizeof(p_server->sa_in)) < 0)
631     {
632         /* Error: close socket and return an error */
633         intf_ErrMsg("input error: unable to connect to the VLAN server (%s)\n", 
634                     strerror(errno));
635         close( p_server->i_socket );
636         return( errno );        
637     }
638
639     /* Send login message */
640     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d %s %s %s\n", 
641              VLAN_LOGIN_REQUEST, VLAN_CLIENT_VERSION, 
642              p_server->psz_login, p_server->psz_passwd );
643     if( send(p_server->i_socket, psz_msg, sizeof(char) * strlen( psz_msg ), 0) < 0)
644     {
645         intf_ErrMsg("input error: unable to login to the VLANserver: %s", 
646                     strerror(errno));
647         close( p_server->i_socket );
648         return( errno );        
649     }
650
651     /* Listen to response */
652     i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
653     if( i_bytes < 0 )
654     {        
655         intf_ErrMsg("input error: no response from VLANserver: %s\n",
656                     strerror(errno));
657         ServerLogout( p_server );
658         return( -1 );
659     }
660
661     /* Parse answer to login request */
662     psz_msg[ i_bytes ] = '\0';                         /* terminate string */    
663     if( atoi(psz_msg) == VLAN_LOGIN_REJECTED )
664     {
665         intf_ErrMsg("input error: login rejected by VLANserver: %s\n", psz_msg);
666         ServerLogout( p_server );
667         return( -1 );        
668     }
669     else if( atoi(psz_msg) != VLAN_LOGIN_ANSWER )
670     {
671         intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
672         ServerLogout( p_server );
673         return( -1 );        
674     }
675     
676     intf_DbgMsg("input debug: VLANserver login ok.\n");    
677     return 0;
678 }
679
680 /*******************************************************************************
681  * ServerLogout: logout from a vlan server
682  *******************************************************************************
683  * Logout from a vlan server. This function sends the logout message to the
684  * server and close the socket.
685  *******************************************************************************/
686 static void ServerLogout( input_vlan_server_t *p_server )
687 {
688     char    psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];            /* server message */
689
690     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
691
692     /* Send logout */
693     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d\n", VLAN_LOGOUT);
694     if( send(p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
695     {
696         intf_ErrMsg("input error: can't send logout message to VLANserver: %s\n", 
697                     strerror(errno));
698     }
699   
700     /* Close socket */
701     if( close(p_server->i_socket) < 0)
702     {
703         intf_ErrMsg("input error: unable to close socket: %s\n", strerror(errno));
704     }
705
706     intf_DbgMsg("input debug: VLANserver logout ok\n");    
707 }
708
709 /*******************************************************************************
710  * ServerRequestChange: request vlan change from a server
711  *******************************************************************************
712  * Request vlan change from a vlan server. The client must be logged in. If the
713  * change succeeded, the interface structure is updated. Note that only masters
714  * should be sent to this function.
715  *******************************************************************************/
716 static int ServerRequestChange( input_vlan_server_t *p_server, 
717                                 input_vlan_iface_t *p_iface, int i_vlan )
718 {
719     char    psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];            /* server message */
720     int     i_bytes;                                   /* number of bytes read */
721           
722     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
723
724     /* Send request */
725     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d %s %s %d %d", 
726              VLAN_CHANGE_REQUEST, p_iface->psz_mac, 
727              inet_ntoa(p_iface->sa_in.sin_addr), i_vlan, p_iface->i_vlan);
728     if( send( p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
729     {
730         intf_ErrMsg("input error: unable to send request to VLANserver: %s\n", 
731                     strerror(errno));        
732         return( -1 );
733     }
734
735     /* Listen to response */
736     i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
737     if( i_bytes < 0 )
738     {        
739         intf_ErrMsg("input error: no response from VLANserver: %s",
740                     strerror(errno));
741         return( -1 );
742     }
743
744     /* Parse answer to vlan request */
745     psz_msg[ i_bytes ] = '\0';                         /* terminate string */    
746     if( atoi( psz_msg ) == VLAN_CHANGE_REJECTED )
747     {
748         intf_ErrMsg("input error: change request rejected by VLANserver: %s\n", psz_msg );
749         return( -1 );      
750     }
751     else if( atoi( psz_msg ) != VLAN_CHANGE_ANSWER )
752     {
753         intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
754         return( -1 );                
755     }
756
757     /* ?? send packet for the switch to learn mac again */
758
759     /* Update interface and return */
760     intf_DbgMsg("input debug: interface %s moved to vlan %d\n", 
761                 p_iface->psz_name, i_vlan );   
762     p_iface->i_vlan = i_vlan;    
763     return( 0 ); 
764 }
765
766 /*******************************************************************************
767  * ServerRequestInfo: ask current vlan to server
768  *******************************************************************************
769  * Request current vlan from a vlan server. The client must be logged in. This
770  * function updates the p_iface structure or returns non 0. Note that only
771  * masters should be sent to this function.
772  *******************************************************************************/
773 static int ServerRequestInfo( input_vlan_server_t *p_server, 
774                               input_vlan_iface_t *p_iface )
775 {
776     char    psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];            /* server message */
777     int     i_bytes;                                   /* number of bytes read */
778     int     i_switch;                                         /* switch number */
779     int     i_port;                                             /* port number */
780     int     i_vlan;                                             /* vlan number */
781     int     i_sharers;                 /* number of mac addresses on this port */    
782           
783     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
784
785     /* Send request */
786     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d", VLAN_INFO_REQUEST);
787     if( send( p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
788     {
789         intf_ErrMsg("input error: unable to send request to VLANserver: %s\n", 
790                     strerror(errno));        
791         return( -1 );
792     }
793
794     /* Listen to response */
795     i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
796     if( i_bytes < 0 )
797     {        
798         intf_ErrMsg("input error: no response from VLANserver: %s",
799                     strerror(errno));
800         return( -1 );
801     }
802
803     /* Parse answer to vlan request */
804     psz_msg[ i_bytes ] = '\0';                         /* terminate string */    
805     if( atoi( psz_msg ) == VLAN_INFO_REJECTED )
806     {
807         intf_ErrMsg("input error: info request rejected by VLANserver: %s\n", psz_msg );
808         return( -1 );      
809     }
810     else if( atoi( psz_msg ) != VLAN_INFO_ANSWER )
811     {
812         intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
813         return( -1 );                
814     }
815     else if( sscanf(psz_msg, "%*d %d %d %d %d", &i_switch, &i_port, &i_vlan, &i_sharers) != 4 )
816     {
817         intf_ErrMsg("input error: invalid answer from VLAN server: %s\n", psz_msg);
818         return( -1 );                        
819     }
820
821     /* Update interface and return */
822     intf_DbgMsg("input debug: interface %s is on switch %d, port %d, vlan %d, %d sharers\n", 
823                 p_iface->psz_name, i_switch, i_port, i_vlan, i_sharers);    
824     p_iface->i_switch = i_switch;    
825     p_iface->i_port = i_port;    
826     p_iface->i_vlan = i_vlan;    
827     p_iface->i_sharers = i_sharers;    
828     return( 0 );    
829 }
830
831
832
833