static void multi_link_modify_link(const struct nlmsghdr *nlh, uint32_t probe_pipe, uint8_t unique){ struct ifinfomsg *ifi = mnl_nlmsg_get_payload(nlh); struct nlattr *tb[IFLA_MAX + 1] = {}; uint8_t iface_state = 0; struct multi_link_info *li = NULL; struct multi_link_info_static *li_static = NULL; pthread_attr_t detach_attr; uint8_t wireless_mode = 0; uint8_t *if_name; mnl_attr_parse(nlh, sizeof(*ifi), multi_link_fill_rtattr, tb); if (!tb[IFLA_IFNAME]) { MULTI_DEBUG_PRINT_SYSLOG(stderr, "Missing interface name\n"); return; } if_name = (uint8_t*) mnl_attr_get_str(tb[IFLA_IFNAME]); if (!strncmp(if_name, "veth", 4) || ifi->ifi_type == ARPHRD_VOID || (ifi->ifi_type == ARPHRD_NONE && strncmp(if_name,"wwan", 4)) || ifi->ifi_type == ARPHRD_TUNNEL || ifi->ifi_flags & IFF_LOOPBACK) return; if(tb[IFLA_OPERSTATE]){ iface_state = mnl_attr_get_u8(tb[IFLA_OPERSTATE]); /* Check linux/Documentation/networking/operstates.txt. IFF_RUNNING * wraps both UP and UNKNOWN*/ if (ifi->ifi_flags & IFF_RUNNING){ //IF_OPER_UP == 6, defined in linux/if.h, chaos with includes //if(iface_state == 6){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (%u) is RUNNING, " "length %u\n", if_name, ifi->ifi_index, multi_link_num_links); if((wireless_mode = multi_link_check_wlan_mode(if_name))) if(wireless_mode == 6){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s is monitor, " "ignoring\n", if_name); return; } LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &(ifi->ifi_index), multi_cmp_ifidx); if(li != NULL){ if(li->state == LINK_UP_STATIC_IFF){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (idx %u) has " "gone from UP to RUNNING\n", if_name, ifi->ifi_index); li->state = GOT_IP_STATIC; } else MULTI_DEBUG_PRINT_SYSLOG(stderr,"Interface %s (idx %u) has " "already been seen. Ignoring event\n", if_name, ifi->ifi_index); return; } if(multi_link_num_links < MAX_NUM_LINKS){ TAILQ_FIND_CUSTOM(li_static, &multi_shared_static_links, list_ptr, if_name, multi_cmp_devname); if(li_static != NULL){ if(li_static->proto == PROTO_IGNORE){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Ignoring %s\n", if_name); return; } else li = multi_link_create_new_link(if_name, li_static->metric); } else { /* Allocate a new link, add to list and start DHCP */ li = multi_link_create_new_link(if_name, 0); } if (!li) { MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create link\n"); return; } //Insert link into link list LIST_INSERT_HEAD(&multi_link_links_2, li, next); ++multi_link_num_links; /* Add as a case here! The check for point to point */ if(li_static != NULL && li_static->proto == PROTO_STATIC){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s found in static list\n", if_name); li->state = GOT_IP_STATIC; li->cfg = li_static->cfg_static; } else if (ifi->ifi_type == ARPHRD_PPP){ /* PPP will be dealt with separatley, since they get the IP * remotely by themself */ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s (%u) is PPP! state " "%u %u\n", if_name, ifi->ifi_index, iface_state, IFF_RUNNING); li->state = LINK_DOWN_PPP; multi_link_get_iface_info(li); if(li->state != GOT_IP_PPP){ //Need to treat this in a special way! Remove li, keep //li and have some sort of timeout? MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not get info for PPP " "link %u (first look)!\n", ifi->ifi_index); } else { //Clean the information that is automatically added to //routing table multi_link_remove_ppp(li); } } else if(wireless_mode){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s is wlan access point\n", if_name); li->state = LINK_DOWN_AP; multi_link_get_iface_info(li); //Remove the automatic route multi_link_remove_ap(li); } else { pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_create(&(li->dhcp_thread), &detach_attr, multi_dhcp_main, (void *) li); } } else MULTI_DEBUG_PRINT_SYSLOG(stderr, "Limit reached, cannot add more links\n"); } else if(ifi->ifi_flags & IFF_UP){ //Might replace with IF_OPER_DOWN //Check if interface has already been seen LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &(ifi->ifi_index), multi_cmp_ifidx); //Interface is already seen as UP, so clean up, no matter if static //or not. Static is a special case: remove routes, li from list //and free li if(li != NULL){ //Need a generic cleanup, move the next "else" into a separate //function MULTI_DEBUG_PRINT_SYSLOG(stderr,"Interface %s (idx %u) has already " "been seen as UP, will clean\n", if_name, ifi->ifi_index); multi_link_delete_link(li, probe_pipe); return; } //Check if interface is in static list TAILQ_FIND_CUSTOM(li_static, &multi_shared_static_links, list_ptr, if_name, multi_cmp_devname); if(li_static != NULL && li_static->proto == PROTO_STATIC){ //Allocate a new link MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s is UP\n", if_name); li = multi_link_create_new_link(if_name, li_static->metric); if (li == NULL) { MULTI_DEBUG_PRINT_SYSLOG(stderr, "Failed to create new link\n"); return; } li->state = GOT_IP_STATIC_UP; li->cfg = li_static->cfg_static; LIST_INSERT_HEAD(&multi_link_links_2, li, next); ++multi_link_num_links; } } else { uint32_t dev_idx = ifi->ifi_index; LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &dev_idx, multi_cmp_ifidx); MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (index %u) is down, " "length %u\n", if_name, ifi->ifi_index, multi_link_num_links); if(li == NULL){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not find %s (index %u), " "length %u\n", if_name, ifi->ifi_index, multi_link_num_links); } else{ multi_link_delete_link(li, probe_pipe); } } } }
void multi_test_visible_loop(struct multi_config *mc){ uint8_t buf[MAX_BUFSIZE]; int32_t retval; int32_t i; int32_t netlink_sock = 0; uint32_t ifi_idx = 0; struct iface *ni = NULL; /* Needed to create the netlink messages */ struct sockaddr_nl src_addr, dest_addr; struct iovec iov; struct msghdr msg; /* Select is used for easier timeouts */ fd_set copy, master; int32_t fdmax; struct timeval tv; memset(buf, 0, MAX_BUFSIZE); /* Initialise list */ LIST_INIT(&iface_list); /* Define a private constant later! Needs to be set in netlink.h so that the * kernel will allow the socket to be created! */ if((netlink_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC)) < 0){ perror("Could not create netlink socket: "); exit(EXIT_FAILURE); } /* These are both constant! */ memset(&src_addr, 0, sizeof(src_addr)); memset(&dest_addr, 0, sizeof(dest_addr)); memset(&msg, 0, sizeof(msg)); src_addr.nl_family = AF_NETLINK; //If PID is set to zero, then the kernel assigns the unique value src_addr.nl_pid = 0; //This is the source, it only multicasts, so it does not have to be //member of any groups! src_addr.nl_groups = 0; if(bind(netlink_sock, (struct sockaddr *) &src_addr, sizeof(src_addr)) < 0){ perror("Could not bind netlink socket: "); exit(EXIT_FAILURE); } dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; dest_addr.nl_groups = 1; MULTI_DEBUG_PRINT(stderr, "Multi manager is ready! Netlink socket %d\n", netlink_sock); MULTI_DEBUG_PRINT(stderr, "M S\n"); //Look at the Wikipedia site for iovec and man(7) netlink for examples on //how to properly parse netlink and have multiple iovec-entries msg.msg_name = (void *) &dest_addr; //This is the message's destination msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; //Initialise everything related to select FD_ZERO(&master); FD_ZERO(©); FD_SET(mc->socket_pipe[0], &master); fdmax = mc->socket_pipe[0]; tv.tv_sec = 30; tv.tv_usec = 0; pthread_t multi_thread = multi_start(mc); while(1){ copy = master; retval = select(fdmax + 1, ©, NULL, NULL, &tv); //Repeat every UP message if(retval == 0){ for(ni = iface_list.lh_first; ni != NULL; ni = ni->next.le_next){ printf("Hei\n"); iov.iov_base = (void *) ni->nlmsg; iov.iov_len = ni->nlmsg->nlmsg_len; sendmsg(netlink_sock, &msg, 0); } tv.tv_sec = 30; tv.tv_usec = 0; continue; } memset(buf, 0, MAX_BUFSIZE); //Sufficient to just memcpy this one and broadcast the netlink message retval = read(mc->socket_pipe[0], buf, MAX_BUFSIZE); if(retval == -1) perror("Failed to read from pipe"); else { memcpy(&ifi_idx, (buf+1), sizeof(uint32_t)); //This check needs to be performed irrespective of if link goes up //or down. LIST_FIND_CUSTOM(ni, &iface_list, next, &ifi_idx, multi_mc_cmp_ifi); if(buf[0] == LINK_UP){ //Sanity check. If the interface is already found, ignore the //announcement from MULTI. if(ni) continue; //Create a new iface, buffer the up message and add to list ni = (struct iface*) malloc(sizeof(struct iface)); ni->ifi_idx = ifi_idx; ni->nlmsg = (struct nlmsghdr *) malloc(NLMSG_SPACE(retval)); memset(ni->nlmsg, 0, NLMSG_SPACE(retval)); ni->nlmsg->nlmsg_pid = getpid(); ni->nlmsg->nlmsg_flags = 0; ni->nlmsg->nlmsg_len = NLMSG_SPACE(retval); memcpy(NLMSG_DATA(ni->nlmsg), buf, retval); LIST_INSERT_HEAD(&iface_list, ni, next); //Adjust the base pointer of the message and broadcast message iov.iov_base = (void *) ni->nlmsg; iov.iov_len = ni->nlmsg->nlmsg_len; retval = sendmsg(netlink_sock, &msg, 0); MULTI_DEBUG_PRINT(stderr,"Broadcasted %d bytes about an UP " "change in network state\n", retval); } else { if(ni){ //Forward message from MULTI ni->nlmsg->nlmsg_len = NLMSG_SPACE(retval); memcpy(NLMSG_DATA(ni->nlmsg), buf, retval); iov.iov_base = (void *) ni->nlmsg; iov.iov_len = ni->nlmsg->nlmsg_len; retval = sendmsg(netlink_sock, &msg, 0); MULTI_DEBUG_PRINT(stderr,"Broadcasted %d bytes about a " "DOWN change in network state\n", retval); LIST_REMOVE(ni, next); free(ni); } } } } }