#include #include #include #include #include #include #include "switch.h" #include "hash.h" #include "port.h" struct packet { struct { unsigned char dest[ETH_ALEN]; unsigned char src[ETH_ALEN]; unsigned char proto[2]; } header; unsigned char data[1500]; }; struct port { struct port *next; struct port *prev; int control; void *data; int data_len; unsigned char src[ETH_ALEN]; void (*sender)(int fd, void *packet, int len, void *data); }; static struct port *head = NULL; #define IS_BROADCAST(addr) ((addr[0] & 1) == 1) static void free_port(struct port *port) { if(port->prev) port->prev->next = port->next; else head = port->next; if(port->next) port->next->prev = port->prev; free(port); } void close_port(int fd) { struct port *port; for(port = head; port != NULL; port = port->next){ if(port->control == fd) break; } if(port == NULL){ fprintf(stderr, "No port associated with descriptor %d\n", fd); return; } delete_hash(port->src); free_port(port); } static void update_src(struct port *port, struct packet *p) { struct port *last; /* We don't like broadcast source addresses */ if(IS_BROADCAST(p->header.src)) return; last = find_in_hash(p->header.src); if(port != last){ /* old value differs from actual input port */ printf(" Addr: %02x:%02x:%02x:%02x:%02x:%02x New port %d", p->header.src[0], p->header.src[1], p->header.src[2], p->header.src[3], p->header.src[4], p->header.src[5], port->control); if(last != NULL){ printf(" old port %d", last->control); delete_hash(p->header.src); } printf("\n"); memcpy(port->src, p->header.src, sizeof(port->src)); insert_into_hash(p->header.src, port); } update_entry_time(p->header.src); } static void send_dst(struct port *port, struct packet *packet, int len, int hub) { struct port *target, *p; target = find_in_hash(packet->header.dest); if((target == NULL) || IS_BROADCAST(packet->header.dest) || hub){ if((target == NULL) && !IS_BROADCAST(packet->header.dest)){ printf("unknown Addr: %02x:%02x:%02x:%02x:%02x:%02x from port ", packet->header.src[0], packet->header.src[1], packet->header.src[2], packet->header.src[3], packet->header.src[4], packet->header.src[5]); if(port == NULL) printf("UNKNOWN\n"); else printf("%d\n", port->control); } /* no cache or broadcast/multicast == all ports */ for(p = head; p != NULL; p = p->next){ /* don't send it back the port it came in */ if(p == port) continue; (*p->sender)(p->control, packet, len, p->data); } } else (*target->sender)(target->control, packet, len, target->data); } static void handle_data(int fd, int hub, struct packet *packet, int len, void *data, int (*matcher)(int port_fd, int data_fd, void *port_data, int port_data_len, void *data)) { struct port *p; for(p = head; p != NULL; p = p->next){ if((*matcher)(p->control, fd, p->data, p->data_len, data)) break; } /* if we have an incoming port (we should) */ if(p != NULL) update_src(p, packet); else printf("Unknown connection for packet, shouldn't happen.\n"); send_dst(p, packet, len, hub); } static int match_tap(int port_fd, int data_fd, void *port_data, int port_data_len, void *data) { return(port_fd == data_fd); } void handle_tap_data(int fd, int hub) { struct packet packet; int len; len = read(fd, &packet, sizeof(packet)); if(len < 0){ if(errno != EAGAIN) perror("Reading tap data"); return; } handle_data(fd, hub, &packet, len, NULL, match_tap); } int setup_port(int fd, void (*sender)(int fd, void *packet, int len, void *data), void *data, int data_len) { struct port *port; port = malloc(sizeof(struct port)); if(port == NULL){ perror("malloc"); return(-1); } port->next = head; if(head) head->prev = port; port->prev = NULL; port->control = fd; port->data = data; port->data_len = data_len; port->sender = sender; head = port; printf("New connection\n"); return(0); } struct sock_data { int fd; struct sockaddr_un sock; }; static void send_sock(int fd, void *packet, int len, void *data) { struct sock_data *mine = data; int err; err = sendto(mine->fd, packet, len, 0, (struct sockaddr *) &mine->sock, sizeof(mine->sock)); if(err != len){ fprintf(stderr, "send_sock sending to fd %d ", mine->fd); perror(""); } } static int match_sock(int port_fd, int data_fd, void *port_data, int port_data_len, void *data) { struct sock_data *mine = data; struct sock_data *port = port_data; if(port_data_len != sizeof(*mine)) return(0); return(!memcmp(&port->sock, &mine->sock, sizeof(mine->sock))); } void handle_sock_data(int fd, int hub) { struct packet packet; struct sock_data data; int len; unsigned int socklen = sizeof(data.sock); len = recvfrom(fd, &packet, sizeof(packet), 0, (struct sockaddr *) &data.sock, &socklen); if(len < 0){ if(errno != EAGAIN) perror("handle_sock_data"); return; } data.fd = fd; handle_data(fd, hub, &packet, len, &data, match_sock); } int setup_sock_port(int fd, struct sockaddr_un *name, int data_fd) { struct sock_data *data; data = malloc(sizeof(*data)); if(data == NULL){ perror("setup_sock_port"); return(-1); } *data = ((struct sock_data) { fd : data_fd, sock : *name }); return(setup_port(fd, send_sock, data, sizeof(*data))); } static void service_port(struct port *port) { int n; char c; n = read(port->control, &c, sizeof(c)); if(n < 0) perror("Reading request"); else if(n == 0) printf("Disconnect\n"); else printf("Bad request\n"); } int handle_port(int fd) { struct port *p; for(p = head; p != NULL; p = p->next){ if(p->control == fd){ service_port(p); return(0); } } return(1); }