1 /* Copyright 2003 Renzo Davoli
2 * Based on the code of uml_switch Copyright 2002 Yon Uriarte and Jeff Dike
3 * Licensed under the GPL
12 #include <sys/socket.h>
19 /* a full ethernet 802.3 frame */
22 unsigned char dest
[ETH_ALEN
];
23 unsigned char src
[ETH_ALEN
];
24 unsigned char proto
[2];
26 unsigned char data
[1500];
30 // for dedugging if needed
32 void packet_dump (struct packet *p)
35 printf ("packet dump dst");
36 for (i=0;i<ETH_ALEN;i++)
37 printf(":%02x",p->header.dest[i]);
39 for (i=0;i<ETH_ALEN;i++)
40 printf(":%02x",p->header.src[i]);
43 printf(":%02x",p->header.proto[i]);
48 /* descriptor of a port group */
50 /* identifier of the port group */
52 /* number of ports which reference this descriptor */
58 /* tap case: NULL; data case: pointer to sock_data */
61 /* pointer to a structure containing group description; reference counting
62 * allows to share the same structure, and know at the same time how many
63 * ports are grouped together */
65 void (*sender
)(int fd
, void *packet
, int len
, void *data
);
69 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
71 void close_port(int i
, int fd
)
73 struct port
*port
=(struct port
*)(g_fdsdata
[i
]);
76 printlog(LOG_WARNING
, "No port associated with descriptor %d", fd
);
79 else if(port
->control
!= fd
){
80 printlog(LOG_WARNING
, "file descriptor mismatch %d %d", port
->control
, fd
);
84 if (port
->pg
!= NULL
) {
85 if (--port
->pg
->counter
== 0) {
88 hash_delete_port(port
);
96 for(i
=g_minfds
; i
<g_nfds
; i
++) {
97 p
=(struct port
*)(g_fdsdata
[i
]);
98 if(port
!= NULL
&& port
!= p
&& port
->pg
== p
->pg
) break;
101 printlog(LOG_WARNING
,"portgroup inconsistency");
104 hash_reassign(port
,p
);
110 hash_delete_port(port
);
114 printlog(LOG_INFO
,"Disconnect %d",port
->control
);
119 static void update_src(struct port
*port
, struct packet
*p
)
123 /* We don't like broadcast source addresses */
124 if(IS_BROADCAST(p
->header
.src
)) return;
126 last
= find_in_hash(p
->header
.src
);
128 if(last
== NULL
|| (port
!= last
&& (port
->pg
== NULL
||
129 port
->pg
!= last
->pg
))){
130 /* old value differs from actual input port - this can happen in two ways:
131 * or the address is simply unknown (probably been forgot by the ARP cache,
132 * or just connected), or it belongs to an unkown port group / different
136 printlog(LOG_INFO
," Addr: %02x:%02x:%02x:%02x:%02x:%02x New port %d",
137 p
->header
.src
[0], p
->header
.src
[1], p
->header
.src
[2],
138 p
->header
.src
[3], p
->header
.src
[4], p
->header
.src
[5],
142 /* there was an entry for this address, but we felt compelled to add a new
143 * one, so at least remove the old one before */
146 printlog(LOG_INFO
," old port %d", last
->control
);
148 delete_hash(p
->header
.src
);
151 /* add the new ARP entry */
152 insert_into_hash(p
->header
.src
, port
);
154 update_entry_time(p
->header
.src
);
157 static void send_dst(struct port
*port
, struct packet
*packet
, int len
,
160 struct port
*target
, *p
;
163 target
= find_in_hash(packet
->header
.dest
);
164 /*fprintf(stderr,"%02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x %p\n",
165 packet->header.src[0], packet->header.src[1],
166 packet->header.src[2], packet->header.src[3],
167 packet->header.src[4], packet->header.src[5],
168 packet->header.dest[0], packet->header.dest[1],
169 packet->header.dest[2], packet->header.dest[3],
170 packet->header.dest[4], packet->header.dest[5],
172 if((target
== NULL
) || IS_BROADCAST(packet
->header
.dest
) || hub
){
174 if((target
== NULL
) && !IS_BROADCAST(packet
->header
.dest
)){
176 printlog(LOG_WARNING
,"unknown Addr: %02x:%02x:%02x:%02x:%02x:%02x from port UNKNOWN",
177 packet
->header
.dest
[0], packet
->header
.dest
[1],
178 packet
->header
.dest
[2], packet
->header
.dest
[3],
179 packet
->header
.dest
[4], packet
->header
.dest
[5]);
181 printlog(LOG_WARNING
,"unknown Addr: %02x:%02x:%02x:%02x:%02x:%02x from port %d",
182 packet
->header
.dest
[0], packet
->header
.dest
[1],
183 packet
->header
.dest
[2], packet
->header
.dest
[3],
184 packet
->header
.dest
[4], packet
->header
.dest
[5], port
->control
);
188 /* no cache or broadcast/multicast == all ports */
189 for(i
=g_minfds
; i
<g_nfds
; i
++) {
190 p
=(struct port
*)(g_fdsdata
[i
]);
191 if (p
!= NULL
&& ((p
->pg
== NULL
&& p
!= port
) ||
193 (*p
->sender
)(p
->control
, packet
, len
, p
->data
);
197 if (target
->pg
== NULL
)
198 (*target
->sender
)(target
->control
, packet
, len
, target
->data
);
199 else if (target
->pg
!= port
->pg
) {
200 if (target
->pg
->counter
== 1)
201 (*target
->sender
)(target
->control
, packet
, len
, target
->data
);
203 for(i
=g_minfds
; i
<g_nfds
; i
++) {
204 p
=(struct port
*)(g_fdsdata
[i
]);
205 if (p
!= NULL
&& p
->pg
== target
->pg
)
206 (*p
->sender
)(p
->control
, packet
, len
, p
->data
);
213 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
214 static unsigned char bpduaddrp
[]=BPDUADDR
;
215 #define ISBPDU(P) (memcmp((P)->header.dest,bpduaddrp,ETH_ALEN)==0)
217 /* we have received a packet of data; take the packet 'packet' of size 'len'
218 * and send it to port 'p', acting as a hub if asked for. if p is NULL, then we
219 * assume that data comes from no known source (this should not happen) */
220 static void handle_direct_data (struct port
*p
, int hub
, struct packet
*packet
, int len
)
222 /* if we have an incoming port (we should) */
223 if(p
!= NULL
) update_src(p
, packet
);
226 printlog(LOG_WARNING
,"Unknown connection for packet, shouldn't happen.");
229 /* throw away FSP packets: VDE1 is unable to manage FSP, run VDE2 instead
232 send_dst(p
, packet
, len
, hub
);
236 void handle_tap_data(int i
, int fd
, int hub
)
238 struct packet packet
;
242 len
= read(fd
, &packet
, sizeof(packet
));
244 if(errno
!= EAGAIN
) printlog(LOG_WARNING
,"Reading tap data %s",strerror(errno
));
247 port
=(struct port
*)(g_fdsdata
[i
]);
248 handle_direct_data(port
, hub
, &packet
, len
);
251 /* initialize a port structure with control=fd, given data+data_len and sender
252 * function; add it to the port group given by identifier portgroup iff != 0,
253 * and then add it to the g_fdsdata array at index i. */
254 int setup_port(int i
, int fd
, void (*sender
)(int fd
, void *packet
, int len
,
255 void *data
), void *data
, int data_len
, int portgroup
)
259 port
= malloc(sizeof(struct port
));
261 printlog(LOG_WARNING
,"malloc %s",strerror(errno
));
267 port
->data_len
= data_len
;
268 port
->sender
= sender
;
272 // search for other port on the same group
274 for(i
=g_minfds
; i
<g_nfds
; i
++) {
275 if (g_fdsdata
!= NULL
) {
276 p
=(struct port
*)(g_fdsdata
[i
]);
277 if (p
->pg
!= NULL
&& p
->pg
->ident
== portgroup
) {
284 /* enlarge the structure if needed */
285 if (port
->pg
== NULL
)
287 port
->pg
=malloc(sizeof(struct portgroup
));
288 if(port
->pg
== NULL
){
289 printlog(LOG_WARNING
,"malloc %s",strerror(errno
));
292 port
->pg
->ident
=portgroup
;
297 printlog(LOG_INFO
,"New connection %d",fd
);
303 /* fd from which data is read */
305 /* source address of read data */
306 struct sockaddr_un sock
;
309 static void send_sock(int fd
, void *packet
, int len
, void *data
)
311 struct sock_data
*mine
= data
;
315 err
= sendto(mine
->fd
, packet
, len
, 0, (struct sockaddr
*) &mine
->sock
,
317 //} while (err == -1 && errno == EAGAIN);
319 printlog(LOG_WARNING
, "send_sock sending to fd %d %s", mine
->fd
, strerror(errno
));
322 //static int match_sock(int port_fd, int data_fd, void *port_data,
323 //int port_data_len, void *data)
325 //struct sock_data *mine = data;
326 //struct sock_data *port = port_data;
328 //if(port_data_len != sizeof(*mine)) return(0);
329 //return(!memcmp(&port->sock, &mine->sock, sizeof(mine->sock)));
332 /* handle data reception from data socket fd. hub is 1 if we act as hubs, 0
334 int handle_sock_data(int fd
, int hub
)
336 struct packet packet
;
337 struct sock_data data
;
338 int len
, socklen
= sizeof(data
.sock
);
341 struct sock_data
*mine
;
342 struct sock_data
*port
;
344 len
= recvfrom(fd
, &packet
, sizeof(packet
), 0,
345 (struct sockaddr
*) &data
.sock
, &socklen
);
347 if(len
< 0 && errno
!= EAGAIN
) printlog(LOG_WARNING
,"handle_sock_data %s",strerror(errno
));
348 if (len
== 0) return 1;
349 /* EGAIN case: receive would block, so tell everything's alright, and it
350 * will be managed in the next select again */
355 /* goes through all ports, and look if it already knows about the one from
356 * which we received some data */
358 for(i
=g_minfds
; i
<g_nfds
; i
++) {
359 if (g_fdsdata
[i
] != NULL
) {
360 p
=(struct port
*)(g_fdsdata
[i
]);
363 //if(match_sock(p->control, fd, p->data, p->data_len, &data)) break;
364 if(p
->data_len
== sizeof(struct sock_data
) &&
365 !(memcmp(&(port
->sock
), &mine
->sock
, sizeof(mine
->sock
)))) break;
368 handle_direct_data(p
,hub
,&packet
,len
);
372 int handle_sock_direct_data(int i
, int fd
, int hub
)
374 struct packet packet
;
375 struct sock_data data
;
377 int len
, socklen
= sizeof(data
.sock
);
379 len
= recvfrom(fd
, &packet
, sizeof(packet
), 0,
380 (struct sockaddr
*) &data
.sock
, &socklen
);
382 if(len
< 0 && errno
!= EAGAIN
) printlog(LOG_WARNING
,"handle_sock_direct_data %s",strerror(errno
));
383 if (len
== 0) return 1;
388 port
=(struct port
*)(g_fdsdata
[i
]);
389 handle_direct_data(port
, hub
, &packet
, len
);
393 int setup_sock_port(int i
, int fd
, struct sockaddr_un
*name
, int data_fd
, int portgroup
)
395 struct sock_data
*data
;
397 data
= malloc(sizeof(*data
));
399 printlog(LOG_WARNING
,"setup_sock_port %s",strerror(errno
));
402 *data
= ((struct sock_data
) { fd
: data_fd
,
404 return(setup_port(i
, fd
, send_sock
, data
, sizeof(*data
), portgroup
));