Пример #1
0
static uint8_t multi_core_store_address(struct multi_link_info_static *mlis, 
        uint8_t *key_data, uint8_t *value_data, uint8_t *addr_count){
    struct in_addr ipaddr;
    
    if(inet_pton(AF_INET, value_data, &ipaddr) == 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not convert %s (invalid parameter?)\n", 
                value_data);
        return 1;
    }

    //Only netmask and address is required, if any address information is
    //specified
    if(!strcmp(key_data, ADDRESS)){
        memcpy(&(mlis->cfg_static.address), &ipaddr, sizeof(struct in_addr));
        (*addr_count)++;
    } else if(!strcmp(key_data, NETMASK)){
        memcpy(&(mlis->cfg_static.netmask), &ipaddr, sizeof(struct in_addr));
        (*addr_count)++;
    } else if(!strcmp(key_data, GATEWAY))
        memcpy(&(mlis->cfg_static.gateway), &ipaddr, sizeof(struct in_addr));
    else {
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Found unknown parameter %s\n", key_data);
        return 1;
    }

    return 0;
}
Пример #2
0
static int32_t multi_link_flush_links(){
    struct ip_info ip_info;
    uint8_t buf[MNL_SOCKET_BUFFER_SIZE];
    struct nlmsghdr *nlh;
    struct rtgenmsg *rt;
    uint32_t seq;

    memset(buf, 0, MNL_SOCKET_BUFFER_SIZE);
    memset(&ip_info, 0, sizeof(ip_info));

    //Initialize list
    TAILQ_INIT(&(ip_info.ip_addr_n));
    TAILQ_INIT(&(ip_info.ip_rules_n));
    TAILQ_INIT(&(ip_info.ip_routes_n));

    //Sets room for one nlmsghdr in buffer buf
    nlh = mnl_nlmsg_put_header(buf);
    nlh->nlmsg_type = RTM_GETADDR;
    nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
    nlh->nlmsg_seq = seq = time(NULL); //How will this work with event? Send 0?
    rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
    rt->rtgen_family = AF_INET; //I need all interfaces

    //Address
    if(mnl_socket_sendto(multi_link_nl_request, nlh, nlh->nlmsg_len) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Cannot request address dump\n");
        return EXIT_FAILURE;
    }

    multi_link_filter(seq, multi_link_filter_ipaddr, &ip_info);

    //Rules
    nlh->nlmsg_type = RTM_GETRULE;
    if(mnl_socket_sendto(multi_link_nl_request, nlh, nlh->nlmsg_len) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Cannot request rules dump\n");
        return EXIT_FAILURE;
    }

    multi_link_filter(seq, multi_link_filter_iprules, &ip_info);

    //Routes
    nlh->nlmsg_type = RTM_GETROUTE;
    if(mnl_socket_sendto(multi_link_nl_request, nlh, nlh->nlmsg_len) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Cannot request rules dump\n");
        return EXIT_FAILURE;
    }

    multi_link_filter(seq, multi_link_filter_iproutes, &ip_info);
 
    /* Remove existing information and free memory */
    multi_link_del_info(ip_info.ip_routes_n, RTM_DELROUTE);
    multi_link_del_info(ip_info.ip_rules_n, RTM_DELRULE);
    multi_link_del_info(ip_info.ip_addr_n, RTM_DELADDR);
    multi_link_free_ip_info(&ip_info);
    return EXIT_SUCCESS;
}
Пример #3
0
//Addresses and routes are always deleted when an interface goes down, but not
//rules. Netlink is not reliable and there are scenarios where we will loose
//messages and not clean up properly. We therefore need to make sure that there
//exists no rules poining to this address/interface
static int32_t multi_link_rules_sanity(struct multi_link_info *li)
{
    struct ip_info ip_info;
    uint8_t buf[MNL_SOCKET_BUFFER_SIZE];
    struct nlmsghdr *nlh;
    struct rtgenmsg *rt;
    uint32_t seq;
    int32_t ret;
    struct multi_link_filter_iprule filter_iprule = {0};

    memset(buf, 0, MNL_SOCKET_BUFFER_SIZE);
    memset(&ip_info, 0, sizeof(ip_info));

    //I am lazy and will use ip_info for now
    TAILQ_INIT(&(ip_info.ip_rules_n));

    filter_iprule.li = li;
    ip_info.data = &filter_iprule;

    //Sets room for one nlmsghdr in buffer buf
    nlh = mnl_nlmsg_put_header(buf);
    nlh->nlmsg_type = RTM_GETRULE;
    nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
    nlh->nlmsg_seq = seq = time(NULL);
    rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
    rt->rtgen_family = AF_INET; //Multi only supports v4

    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Will check for dirty rules\n");

    if(mnl_socket_sendto(multi_link_nl_request, nlh, nlh->nlmsg_len) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Cannot request rules dump\n");
        return EXIT_FAILURE;
    }

    ret = multi_link_filter(seq, multi_link_filter_iprules_addr, &ip_info);

    if (ret) {
        //Some rules might have been added
        multi_link_free_ip_info(&ip_info);
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Sanity check failed (memory)\n");
        return EXIT_FAILURE;
    }

    if (!ip_info.ip_rules_n.tqh_first)
        return EXIT_SUCCESS;

    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Will delete dirty rules\n");

    multi_link_del_info(ip_info.ip_rules_n, RTM_DELRULE);
    multi_link_free_ip_info(&ip_info);

    return EXIT_SUCCESS;
}
Пример #4
0
static void multi_link_populate_links_list(){
    //MNL_SOCKET_BUFFER_SIZE is 8k, which is the max nlmsg size (see
    //linux/netlink.h)
    uint8_t buf[MNL_SOCKET_BUFFER_SIZE];
    struct nlmsghdr *nlh;
    struct rtgenmsg *rt;
    uint32_t seq;

    memset(buf, 0, MNL_SOCKET_BUFFER_SIZE);

    //Sets room for one nlmsghdr in buffer buf
    nlh = mnl_nlmsg_put_header(buf);
    nlh->nlmsg_type = RTM_GETLINK;
    nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
    nlh->nlmsg_seq = seq = time(NULL); //How will this work with event? Send 0?
    rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
    rt->rtgen_family = AF_UNSPEC; //I need all interfaces

    if(mnl_socket_sendto(multi_link_nl_request, nlh, nlh->nlmsg_len) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Cannot request info dump\n");
        return;
    }

    multi_link_filter(seq, multi_link_filter_links, NULL);
}
Пример #5
0
static void multi_link_delete_link(struct multi_link_info *li, 
    uint32_t probe_pipe){
    MULTI_DEBUG_PRINT_SYSLOG(stderr, "M D %s %u %u\n", li->dev_name, 
            li->ifi_idx, li->metric);

    if(li->cfg.address.s_addr != 0)
        multi_link_remove_link(li);
    
    pthread_cancel(li->dhcp_thread);
    pthread_join(li->dhcp_thread, NULL);

    LIST_REMOVE(li, next);
    --multi_link_num_links;

    if(!li->keep_metric)
        //Remember that metric is one higher than index
        multi_shared_metrics_set ^= 1 << (li->metric-1);
    
    //Should maybe be done earlier
    multi_link_notify_probing(probe_pipe, li->ifi_idx, LINK_DOWN); 

    if(li->decline_pipe[0] > 0){
        close(li->decline_pipe[0]);
        close(li->decline_pipe[1]);
    }

    free(li);
}
Пример #6
0
/* Allocates and returns a config struct needed for multi to work */
struct multi_config* multi_core_initialize_config(uint8_t *cfg_file, 
        uint8_t unique){
    struct multi_config *mc;

    multi_shared_metrics_set = 0;
    //multi_shared_metrics_set = 0;
    mc = (struct multi_config *) malloc(sizeof(struct multi_config));
    memset(mc, 0, sizeof(struct multi_config));

    /* Not mandatory */
    if(cfg_file != NULL)
        //Parse configuration file
        if(multi_core_parse_config(cfg_file))
            return NULL;


    if(pipe(mc->socket_pipe) == -1){
        MULTI_DEBUG_PRINT_SYSLOG(stderr,"Failed to create pipe\n");
        return NULL;
    }
    
    //Require unique IP address or not
    mc->unique = unique;

    return mc;
}
Пример #7
0
/* This will also be started as a thread */
static void* multi_core_init(void *arg){
    struct multi_core_sync mcs;
    pthread_t link_thread, probing_thread;
    struct multi_core_sync *mcs_main = (struct multi_core_sync *) arg;

    mcs.mc = mcs_main->mc;
    pthread_cond_init(&(mcs.sync_cond), NULL);
    pthread_mutex_init(&(mcs.sync_mutex), NULL);

    /* Needs to be served config file, but ignore that for now */
    pthread_mutex_lock(&(mcs.sync_mutex));
    pthread_create(&link_thread, NULL, multi_link_module_init, &mcs);
    pthread_cond_wait(&(mcs.sync_cond), &(mcs.sync_mutex));
    pthread_mutex_unlock(&(mcs.sync_mutex));

    MULTI_DEBUG_PRINT_SYSLOG(stderr,"MULTI is ready and running\n");

    pthread_mutex_lock(&(mcs_main->sync_mutex));
    pthread_cond_signal(&(mcs_main->sync_cond));
    pthread_mutex_unlock(&(mcs_main->sync_mutex));

    pthread_join(link_thread, NULL);

    return NULL;
}
Пример #8
0
static void multi_link_notify_probing(int32_t probe_pipe, uint32_t ifi_idx, 
        link_state state){
    uint8_t buffer[sizeof(ifi_idx) + 1];

    buffer[0] = state;
    memcpy((buffer + 1), &ifi_idx, sizeof(ifi_idx));
    if(write(probe_pipe, buffer, sizeof(buffer)) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not send link notification\n"); 
    }
}
Пример #9
0
//TODO: RENAME to something more generic
static void multi_link_check_ppp(void* data, void* user_data){
    struct multi_link_info *li = (struct multi_link_info *) data;

    if(li->state == LINK_DOWN_PPP){
        multi_link_get_iface_info(li);

        //Need to do something smart here! Remover link or something!
        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 "
                    "(check_ppp)!\n", li->ifi_idx);
        } else{
            multi_link_remove_ppp(li);
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Got info for PPP link %u "
                    "(check_ppp)!\n", li->ifi_idx);
        }
    } else if(li->state == LINK_DOWN_AP)
        multi_link_get_iface_info(li);
}
Пример #10
0
struct multi_link_info *multi_link_create_new_link(uint8_t* dev_name, 
        uint32_t metric){
    struct multi_link_info *li = (struct multi_link_info *) 
        malloc(sizeof(struct multi_link_info));

    memset(li, 0, sizeof(struct multi_link_info));

    //If a link is static, use the stored metric. Otherwise, first available
    if(metric > 0){
        li->metric = metric;
        li->keep_metric = 1;
    } else {
        //Get the first available metric. I dont need to check error code, as
        //the check for num. links in modify_link ensures that there will always
        //be one metric available if the code gets here
        li->metric = ffs(~multi_shared_metrics_set);

        if (!li->metric) {
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "No available metrics\n");
            free(li);
            return NULL;
        }

        //ffs starts indexing from 1
        multi_shared_metrics_set ^= 1 << (li->metric - 1);
    }
    
    li->state = WAITING_FOR_DHCP;
    li->ifi_idx = if_nametoindex((char*) dev_name);
    li->write_pipe = multi_link_dhcp_pipes[1];
    memcpy(&(li->dev_name), dev_name, strlen((char*) dev_name));
    pthread_mutex_init(&(li->state_lock), NULL);

    if(pipe(li->decline_pipe) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create decline pipe\n");
        free(li);
        return NULL;
    }

    return li;
}
Пример #11
0
/* Remove all links that have been deleted. This is only used when 
 * DHCP fails! */
static void multi_link_clean_links(){
    struct multi_link_info *li, *li_tmp;

    for(li = multi_link_links_2.lh_first; li != NULL; ){
        //I update the list while iterating, so I need to forward iterator
        li_tmp = li;
        li = li->next.le_next;

        /* No need for lock here, the state DELETE_LINK is ONLY set by this 
         * thread and DHCP thread has been cancelled */
        if(li_tmp->state == DELETE_LINK){
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Will delete %s\n", li_tmp->dev_name);
            LIST_REMOVE(li_tmp, next);
            --multi_link_num_links;
            free(li_tmp);
        }
    }
}
Пример #12
0
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);
            }
        }
    }
}
Пример #13
0
static void multi_link_check_link(void *data, void *user_data){
    struct multi_link_info *li = (struct multi_link_info *) data;
    struct multi_config *mc = (struct multi_config *) user_data;
    int32_t probe_pipe = mc->socket_pipe[1];

    pthread_mutex_lock(&(li->state_lock));
    if(li->state == GOT_IP_DHCP || li->state == GOT_IP_STATIC_UP || 
            li->state == GOT_IP_STATIC || li->state == GOT_IP_PPP || 
            li->state == GOT_IP_AP){
        
        /* Add routes */
        //Check for uniqueness if needed
        if(li->state == GOT_IP_DHCP && mc->unique && 
                !multi_link_check_unique(li, 0)){
            li->state = WAITING_FOR_DHCP;
            memset(&li->cfg, 0, sizeof(li->cfg));
            if(write(li->decline_pipe[1], "a", 1) < 0){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not decline IP\n");
            }
            pthread_mutex_unlock(&(li->state_lock));
            return;
        }

        /* Check for leftover rules  */
        multi_link_rules_sanity(li);

        //TODO: Add error checks!
        multi_link_configure_link(li);
        if(li->state == GOT_IP_STATIC_UP){
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "IP address set for %s (iface idx %u)\n",
                    li->dev_name, li->ifi_idx);
            //Do not advertise interfaces that are only UP, they can't be used
            //yet
            li->state = LINK_UP_STATIC_IFF;
            return;
        } else
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "IP address, routes and rules set for "
                    "device %s (iface idx %u)\n", li->dev_name, li->ifi_idx);

        MULTI_DEBUG_PRINT_SYSLOG(stderr, "M U %s %u %u\n", li->dev_name, 
                li->ifi_idx, li->metric); 
        multi_link_notify_probing(probe_pipe, li->ifi_idx, LINK_UP);

		if(li->state == GOT_IP_STATIC)
			li->state = LINK_UP_STATIC;
        else if(li->state == GOT_IP_PPP)
            li->state = LINK_UP_PPP;
		else if(li->state == GOT_IP_AP)
            li->state = LINK_UP_AP;
        else{
			li->state = LINK_UP;
        }
    } else if(li->state == DHCP_IP_CHANGED){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s changed IP\n", li->dev_name);

        if(mc->unique && !multi_link_check_unique(li, 1)){
            li->state = WAITING_FOR_DHCP;
            if(write(li->decline_pipe[1], "a", 1) < 0){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not decline IP\n");
            }
            pthread_mutex_unlock(&(li->state_lock));
            return;
        }

        /* Delete and then add ip and routes */
        multi_link_notify_probing(probe_pipe, li->ifi_idx, LINK_DOWN);
        multi_link_remove_link(li);

        //Configure the new routes
        li->cfg = li->new_cfg;
        multi_link_configure_link(li);
        li->state = LINK_UP;
        multi_link_notify_probing(probe_pipe, li->ifi_idx, LINK_UP);
    } else if (li->state == DHCP_IP_INVALID){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s IP is marked as invalid\n", 
                li->dev_name);
        //Delete information about link
        multi_link_remove_link(li);

        //Notify module that link is down (to an application, down and invalid
        //is the same) 
        multi_link_notify_probing(probe_pipe, li->ifi_idx, LINK_DOWN);
        li->state = LINK_INVALID;
    } else if(li->state == DHCP_FAILED){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "DHCP has failed, will clean up and "
                "remove thread!\n");
        
        /* Remove routes if link has an IP */
        if(li->cfg.address.s_addr != 0){
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Remove routes\n");
            multi_link_remove_link(li);
        }

        li->state = DELETE_LINK;
        multi_link_notify_probing(probe_pipe, li->ifi_idx, LINK_DOWN);
    }

    pthread_mutex_unlock(&(li->state_lock));
}
Пример #14
0
void multi_dhcp_parse_dhcp_msg(struct multi_dhcp_info *di, 
        struct multi_dhcp_message *dm, struct multi_link_info *li){
    struct multi_dhcp_config cfg;
    uint32_t t_now, t_diff;
    uint8_t ipaddr[INET_ADDRSTRLEN];
    uint8_t baddr[INET_ADDRSTRLEN];
    uint8_t gwaddr[INET_ADDRSTRLEN];
    uint8_t netmask[INET_ADDRSTRLEN];

    multi_dhcp_parse_options(dm, &cfg);

    if (dm->xid != di->xid || dm->hlen != 6 || 
            memcmp(dm->chaddr, &(di->mac_addr),6)){ 
        //fprintf(stderr, "Message intended for someone else!\n");
        return;
    }

    switch(di->state){
        case SELECTING:
            //One typical scenario here is if the lease expires before the 
            //DHCP ACK for final REBIND is received
            if(cfg.dhcpmsgtype != DHCP_TYPE_OFFER){ 
                MULTI_DEBUG_PRINT_SYSLOG(stderr,"Mismatch state. In INIT but did not "
                        "get OFFER. Got %u\n", cfg.dhcpmsgtype);
                return;
            }

            /* Move on to the next state, retrans count must be reset */
            di->retrans_count = 0;

            MULTI_DEBUG_PRINT_SYSLOG(stderr,"Received DHCP OFFER on interface %s "
                    "(iface idx %u), will send DHCP REQUEST\n", li->dev_name, 
                    li->ifi_idx);

            di->cfg = cfg;
            di->state = REQUESTING; 
            multi_dhcp_create_dhcp_msg(di);
            break;
        case RENEWING:
        case REBINDING:
        case REQUESTING:
        case REBOOTING:
            /* All these states  */
            if(cfg.dhcpmsgtype == DHCP_TYPE_NAK){
                /* According to the RFC, a NAK involves moving straight back to
                 * INIT and resending request. Moving to INIT implies resetting
                 * variables and state, just in case */
                MULTI_DEBUG_PRINT_SYSLOG(stderr,"Got NAK in state %u. Resetting and "
                        "retrying DISCOVER! (iface idx %u)\n", di->state, 
                        di->ifidx);
                di->state = INIT;
                di->req_sent_time = 0;
                //Since next packet is sent immideatly, this can 0 (as opposed 
                //to -1 for ACK)
                di->retrans_count = 0; 

                /* Set state as waiting. I can here if a) rebooting fails b)
                 * requesting fails c) renewing fails d) rebinding fails. In the
                 * last two, the link can be in UP state */
                pthread_mutex_lock(&(li->state_lock));
                li->state = WAITING_FOR_DHCP;
                pthread_mutex_unlock(&(li->state_lock));

                multi_dhcp_create_dhcp_msg(di);
            } else if(cfg.dhcpmsgtype == DHCP_TYPE_ACK){
                //Always decline DHCP address
                di->cfg = cfg; //Just in case, I know these are the good values
                
                di->state = BOUND;
                
                inet_ntop(AF_INET, &(cfg.address), (char*) ipaddr, INET_ADDRSTRLEN);
                inet_ntop(AF_INET, &(cfg.broadcast), (char*) baddr, INET_ADDRSTRLEN);
                inet_ntop(AF_INET, &(cfg.gateway), (char*) gwaddr, INET_ADDRSTRLEN);
                inet_ntop(AF_INET, &(cfg.netmask), (char*) netmask, INET_ADDRSTRLEN);
                
                //Do the timeout calculation. Be warned that inet_ntoa is NOT
                    //reentrant. In other words, the IP adresses are wrong!
                MULTI_DEBUG_PRINT_SYSLOG(stderr,"Got DHCP ACK on interface %s "
                        "(iface idx %u). %s will be bound to IP: %s Broadcast: "
                        "%s Gateway: %s Netmask %s (%u) Lease: %u T1: %u T2: "
                        "%u\n", li->dev_name, li->ifi_idx, li->dev_name, 
                        ipaddr, baddr, gwaddr, netmask, 
                        32 - (ffs(ntohl(cfg.netmask.s_addr)) - 1), 
                        cfg.lease, cfg.t1, cfg.t2);


                //TODO: I need some variable or check to prevent adding the same IP twice. Compare cfg is maybe sufficient? Or at least address?
                pthread_mutex_lock(&(li->state_lock));

                /* This is needed if one interface switches network. Otherwise,
                 * the main thread will not know that it has to clean up (it
                 * will just see a new set of addresses)! */
                /* Need to wireless access points in order to test this, with
                 * different subnets */
                if(li->cfg.address.s_addr != 0 && 
                    (li->cfg.address.s_addr != cfg.address.s_addr || 
                     li->cfg.broadcast.s_addr != cfg.broadcast.s_addr || 
                     li->cfg.gateway.s_addr != cfg.gateway.s_addr || 
                     li->cfg.netmask.s_addr != cfg.netmask.s_addr)){

                    li->state = DHCP_IP_CHANGED;
                    li->new_cfg = cfg;
                    multi_dhcp_notify_link_module(li->write_pipe);
                } else{ 
                    li->cfg = cfg;

                    /* This is correct becuase if the information has not
                     * changed, then there is no need to update the state. The
                     * cfg must be updated due to leases and so on */
                    if(li->state != LINK_UP){
                        li->state = GOT_IP_DHCP;
                        multi_dhcp_notify_link_module(li->write_pipe);
                    }
                }

                pthread_mutex_unlock(&(li->state_lock));

                t_now = time(NULL);
                t_diff = t_now - di->req_sent_time;

                di->lease = cfg.lease;
                di->t1 = cfg.t1 ? cfg.t1 : cfg.lease / 2;
                di->t2 = cfg.t2 ? cfg.t2 : cfg.lease * 0.875;

                /* Not exactly sure what to do in this case */                
                assert(t_diff < di->t1 || t_diff < di->t2);
                assert(di->t1 < di->t2);

                /* Lease is from WHEN the request was sent */
                di->lease -= t_diff;
                di->t1 -= t_diff;
                di->t2 -= t_diff;

                /* Convert values to be absolute */
                di->lease += t_now;
                di->t1 += t_now;
                di->t2 += t_now;
 
                /* Every packet has been accounted for, so timers and everything can be reset */
                di->req_sent_time = 0;
                //This will overflow, but it is ok. When the next timeout (T1) 
                //is triggered, retrans_count will be increased by 1 and, thus,
                //be 0 again (but a little hackish)

                di->retrans_count = -1; 
                /* New timeout event started */
                di->output_timer = 1;
           }
        default:
            break;
    }
}
Пример #15
0
void multi_dhcp_create_dhcp_msg(struct multi_dhcp_info *di){
    struct multi_dhcp_message dhcp_msg;
    uint8_t dhcp_type;
    uint8_t iface_id[7];
    struct in_addr ipaddr;
    uint32_t lease_time = ~0;
    //uint32_t lease_time = htonl(60);
    uint32_t t_now;
    uint8_t ip_addr[INET_ADDRSTRLEN];
    FILE *hostname_file;
    uint8_t hostname[HOST_NAME_MAX + 1] = {0};
    char *hostname_parsed = NULL;
    size_t retval;

    //Read hostname, we don't care if we fail (most important is to get lease)
    hostname_file = fopen("/etc/hostname", "r");

    if (hostname_file != NULL) {
        retval = fread(hostname, 1, HOST_NAME_MAX, hostname_file);

        if (ferror(hostname_file)) {
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"Failed to read hostname\n");
        } else {
            hostname_parsed = strtok(hostname, "\r\n");
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"Hostname: %s\n", hostname_parsed);
        }

        fclose(hostname_file); 
    } else {
        MULTI_DEBUG_PRINT_SYSLOG(stderr,"Failed to open hostname file\n");
    }

    multi_dhcp_dm_init(&dhcp_msg);
    //Unique ID to separate DHCP requests from one another
    dhcp_msg.xid = di->xid; 
    dhcp_msg.op = BOOTP_OPCODE_REQUEST;
    //Found in RFC1700, seems to be a default value for all Ethernet-standards
    dhcp_msg.htype = 1; 
    //Length of MAC-address
    dhcp_msg.hlen = 6; 
    memcpy(dhcp_msg.chaddr, &(di->mac_addr), 6);

    t_now = time(NULL);

    /* Which message to send depends on the client's state. Also, changes state 
     * if needed */
    switch(di->state){
        case INIT:
        case SELECTING:
            /* If I get here, it is either the first packet or a timeout has 
             * occured */
            di->state = SELECTING;
            dhcp_type = DHCP_TYPE_DISCOVER; 
            ipaddr.s_addr = 0;
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_TYPE, 1, 
                    &dhcp_type);
            if (hostname_parsed)
                multi_dhcp_dm_add_option(&dhcp_msg, BOOTP_OPTION_HOSTNAME,
                        strlen(hostname_parsed), hostname_parsed);

            /* According to RFC, it is time of ORIGINAL request */
            if(di->req_sent_time == 0)
                di->req_sent_time = t_now;

            di->req_retrans = t_now + (4 * (di->retrans_count + 1));
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"Sending DHCP DISCOVER (iface idx %u).\n", 
                    di->ifidx);
            di->output_timer = 1;
            break;
        case INIT_REBOOT:
        case REBOOTING:
            di->state = REBOOTING;
            ipaddr.s_addr = 0;
            dhcp_type = DHCP_TYPE_REQUEST;
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_TYPE, 1, 
                    &dhcp_type);
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_REQADDR, 4, 
                    &di->cfg.address.s_addr);
            if (hostname_parsed)
                multi_dhcp_dm_add_option(&dhcp_msg, BOOTP_OPTION_HOSTNAME,
                        strlen(hostname_parsed), hostname_parsed);

            /* As always, this is a NEW request so time will be set for the 
             * first packet */
            if(di->req_sent_time == 0)
                di->req_sent_time = t_now;

            di->req_retrans = t_now + (4 * (di->retrans_count + 1));

            inet_ntop(AF_INET, &di->cfg.address, (char*) ip_addr, INET_ADDRSTRLEN);
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"REBOOTING and requesting %s, Sending "
                    "DHCP REQUEST (iface idx %u).\n", ip_addr, di->ifidx);
            di->output_timer = 1;
            break;
        case REQUESTING:
            ipaddr.s_addr = 0; 
            dhcp_type = DHCP_TYPE_REQUEST;
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_TYPE, 1, 
                    &dhcp_type);
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_REQADDR, 4, 
                    &di->cfg.address.s_addr);
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_SERVER, 4, 
                    &di->cfg.dhcpd_addr.s_addr);
            if (hostname_parsed)
                multi_dhcp_dm_add_option(&dhcp_msg, BOOTP_OPTION_HOSTNAME,
                        strlen(hostname_parsed), hostname_parsed);
      
            //Not updating req_sent_time, as this is just a step in a request
            di->req_retrans = t_now + (4 * (di->retrans_count + 1));
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"Sending DHCP REQUEST (iface idx %u).\n", 
                    di->ifidx);
            di->output_timer = 1;
            break;
        case BOUND:
        case RENEWING:
            di->state = RENEWING;
            ipaddr = di->cfg.dhcpd_addr; //Messages for renewing is sent unicast
            dhcp_type = DHCP_TYPE_REQUEST;
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_TYPE, 1, 
                    &dhcp_type);
            if (hostname_parsed)
                multi_dhcp_dm_add_option(&dhcp_msg, BOOTP_OPTION_HOSTNAME,
                        strlen(hostname_parsed), hostname_parsed);
            dhcp_msg.ciaddr = di->cfg.address.s_addr;

            /* As always, this is a NEW request so time will be set for the 
             * first packet */
            if(di->req_sent_time == 0)
                di->req_sent_time = t_now;

            di->req_retrans = t_now + (4 * (di->retrans_count + 1));
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"RENEWING, sending DHCP REQUEST (iface "
                    "idx %u).\n", di->ifidx);
            di->output_timer = 1;
            break;
        case REBINDING:
            di->state = REBINDING;
            //According to RFC, the old IP must be stored here
            ipaddr = di->cfg.address; 
            dhcp_type = DHCP_TYPE_REQUEST;
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_TYPE, 1, 
                    &dhcp_type);
            if (hostname_parsed)
                multi_dhcp_dm_add_option(&dhcp_msg, BOOTP_OPTION_HOSTNAME,
                        strlen(hostname_parsed), hostname_parsed);
            dhcp_msg.ciaddr = di->cfg.address.s_addr;

            di->req_retrans = t_now + (4 * (di->retrans_count + 1));
            MULTI_DEBUG_PRINT_SYSLOG(stderr,"REBINDING, sending DHCP REQUEST "
                    "(iface idx %u).\n", di->ifidx);
            di->output_timer = 1;
            break;
        case DECLINE:
            dhcp_type = DHCP_TYPE_DECLINE;
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_TYPE, 1, 
                    &dhcp_type);
            multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_REQADDR, 4, 
                    &di->cfg.address.s_addr);
            if (hostname_parsed)
                multi_dhcp_dm_add_option(&dhcp_msg, BOOTP_OPTION_HOSTNAME,
                        strlen(hostname_parsed), hostname_parsed);

            //According to the RFC, move back to init
            //di->state = INIT;
            di->retrans_count = 0;
            di->req_sent_time = 0;
            di->req_retrans = t_now + 10; //Timeout after decline is 10 seconds
            break;
        default:
            break;
    }

    /* Must be done manually due to the pair (see RFC2132) */
    iface_id[0] = 1;
    memcpy(iface_id+1, &(di->mac_addr), 6);
    multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_CLIENT_IDENTIFIER, 7, 
            iface_id);

    /* The server will only reply when I specify what info I want, naturally. However, RFC states it should return something, check at work tomorrow */
    if(dhcp_type == DHCP_TYPE_DISCOVER || dhcp_type == DHCP_TYPE_REQUEST){
        multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_OPTIONREQ, 
                sizeof(multi_dhcp_optlist), multi_dhcp_optlist);
        multi_dhcp_dm_add_option(&dhcp_msg, DHCP_OPTION_LEASE, 
                sizeof(lease_time), &lease_time);
    }

    multi_dhcp_dm_finish_options(&dhcp_msg);

    //Send packet. I suspect that the reason I don't receive a unicast reply is
    //because the interface don't have a source IP set
    if(di->state == RENEWING){
        multi_dhcp_snd_msg_udp(di->udp_sock, &ipaddr, &dhcp_msg);
    } else {
        multi_dhcp_snd_msg_raw(di->raw_sock, ipaddr, di->ifidx, &dhcp_msg, 1);
    }
}
Пример #16
0
uint8_t multi_core_parse_iface_info(struct multi_link_info_static *mlis, 
        yaml_parser_t *parser){
    yaml_event_t key, value;
    uint8_t *value_data, *key_data;
    uint8_t error = 0;
    uint32_t metric = 0;

    //Used for checking if address, netmask and gateway is provided (all
    //required if one is present)
    uint8_t addr_count = 0;
    //Proto must be set
    uint8_t proto = 0;

    while(1){
        if(!yaml_parser_parse(parser, &key)){
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not parse key\n");
            error = 1;
            break;
        }

        if(key.type == YAML_MAPPING_END_EVENT){
            yaml_event_delete(&key);
            if((addr_count > 0 && addr_count != 2) || !proto){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Required information"
                        "(address/netmask/proto) is missing\n");
                error = 1;
            }

            break;
        } else if(key.type == YAML_SCALAR_EVENT){
            if(!yaml_parser_parse(parser, &value)){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not parse value\n");
                error = 1;
                break;
            } else if(value.type != YAML_SCALAR_EVENT){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Found something else than scalar\n");
                yaml_event_delete(&value);
                error = 1;
                break;
            }

            key_data = key.data.scalar.value;
            value_data = value.data.scalar.value;

            if(!strcmp(key_data, METRIC)){
                metric = atoi(value_data);
                //Metric of 0 is not allowed
                if(!metric || metric > MAX_NUM_LINKS){
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Invalid metric\n");
                    error = 1;
                    break;
                } else {
                    //Start at index 0
                    mlis->metric = metric;

                    //Check if metric is set
                    if(multi_shared_metrics_set & (1<<(metric-1))){
                        MULTI_DEBUG_PRINT_SYSLOG(stderr, 
                                "Metric for %s is already used\n", 
                                mlis->dev_name);
                        error = 1;
                        break;
                    }

                    //The static metrics are always reserved
                    multi_shared_metrics_set ^= 1 << (metric-1);
                }
            } else if(!strcmp(key_data, PROTO)){
                proto = 1;

                if(!strcmp(value_data, "static"))
                    mlis->proto = PROTO_STATIC;
                else if(!strcmp(value_data, "other"))
                    mlis->proto = PROTO_OTHER;
                else if(!strcmp(value_data, "ignore"))
                    mlis->proto = PROTO_IGNORE;
                else{
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Unknown protocol\n");
                    error = 1;
                    break;
                }
            } else {
                if((error = multi_core_store_address(mlis, key_data, value_data, 
                                &addr_count)))
                    break;
            }

            DEL_KEY_VALUE(key, value);
        }
    }

    return error;
}
Пример #17
0
static int32_t multi_link_event_loop(struct multi_config *mc){
    struct multi_link_info *li;
    pthread_attr_t detach_attr;
    uint8_t buf[MAX_PIPE_MSG_LEN];
    uint8_t mnl_buf[MNL_SOCKET_BUFFER_SIZE];
    int32_t retval, numbytes;
    uint32_t i;
    int32_t mnl_sock_event, mnl_sock_set, mnl_sock_get;
    fd_set masterfds, readfds;
    int fdmax = 0;
    struct timeval tv;

    FD_ZERO(&masterfds);
    FD_ZERO(&readfds);

    //NETLINK_ROUTE is where I want to hook into the kernel
    if(!(multi_link_nl_request = mnl_socket_open(NETLINK_ROUTE))){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create mnl socket (request)\n");
        return EXIT_FAILURE;
    }

    if(!(multi_link_nl_set = mnl_socket_open(NETLINK_ROUTE))){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create mnl socket (set)\n");
        return EXIT_FAILURE;
    }

    if(!(multi_link_nl_event = mnl_socket_open(NETLINK_ROUTE))){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create mnl socket (event)\n");
        return EXIT_FAILURE;
    }

    if(mnl_socket_bind(multi_link_nl_request, 0, MNL_SOCKET_AUTOPID) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not bind mnl event socket\n");
        mnl_socket_close(multi_link_nl_event);
        return EXIT_FAILURE;
    }

    if(mnl_socket_bind(multi_link_nl_set, 0, MNL_SOCKET_AUTOPID) < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not bind mnl event socket\n");
        mnl_socket_close(multi_link_nl_event);
        return EXIT_FAILURE;
    }

    if(mnl_socket_bind(multi_link_nl_event, 1 << (RTNLGRP_LINK - 1), MNL_SOCKET_AUTOPID) 
            < 0){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not bind mnl event socket\n");
        mnl_socket_close(multi_link_nl_event);
        return EXIT_FAILURE;
    }

    if(pipe(multi_link_dhcp_pipes) < 0){
        //perror("Pipe failed\n");
        MULTI_DEBUG_PRINT_SYSLOG(stderr,"Pipe failed\n");
        return EXIT_FAILURE;
    }

    /* Find interfaces that are already up, removes info and then reruns 
     * DHCP (need config) */
    multi_link_populate_links_list();

    /* Check if I have any PPP links. */
    //TODO: Give this one a better name since it is not only for PPP any more
    LIST_FOREACH_CB(&multi_link_links_2, next, multi_link_check_ppp, li, NULL);

    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Done populating links list!\n");

    if(multi_link_flush_links() == EXIT_FAILURE)
        return EXIT_FAILURE;

    //Go through already seen interfaces and start DHCP as needed
    if(multi_link_num_links > 0){
        pthread_attr_init(&detach_attr);
        pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED);

        for(li = multi_link_links_2.lh_first; li != NULL;
                li = li->next.le_next){
            /* Start DHCP */
            if(li->state == WAITING_FOR_DHCP){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Starting DHCP for existing "
                        "interface %s\n", li->dev_name);
                pthread_create(&(li->dhcp_thread), &detach_attr, 
                        multi_dhcp_main, (void *) li);
            }
        }
    }

	/* Do a scan of the list here to check for links with static IP/PPP */
    LIST_FOREACH_CB(&multi_link_links_2, next, multi_link_check_link, li, mc);

    mnl_sock_event = mnl_socket_get_fd(multi_link_nl_event);
    mnl_sock_set = mnl_socket_get_fd(multi_link_nl_set);
    mnl_sock_get = mnl_socket_get_fd(multi_link_nl_request);

    FD_SET(mnl_sock_event, &masterfds); 
    fdmax = fdmax > mnl_sock_event ? fdmax : mnl_sock_event;
    FD_SET(mnl_sock_get, &masterfds);
    fdmax = fdmax > mnl_sock_get ? fdmax : mnl_sock_get;
    FD_SET(mnl_sock_set, &masterfds);
    fdmax = fdmax > mnl_sock_set ? fdmax : mnl_sock_set;
    FD_SET(multi_link_dhcp_pipes[0], &masterfds);
    fdmax = fdmax > multi_link_dhcp_pipes[0] ? fdmax : multi_link_dhcp_pipes[0];

    tv.tv_sec = 5;
    tv.tv_usec = 0;

    while(1){
        readfds = masterfds;

        retval = select(fdmax+1, &readfds, NULL, NULL, &tv);

        if(retval == 0){
            //Check for any PPP that is marked as down 
            LIST_FOREACH_CB(&multi_link_links_2, next, multi_link_check_ppp,
                    li, NULL);
            LIST_FOREACH_CB(&multi_link_links_2, next, multi_link_check_link,
                    li, mc);

            tv.tv_sec = 5;
            tv.tv_usec = 0;
            continue;
        }

        //TODO: Rewrite this so I only call the callbacks at the end, not per
        //message
        for(i=0; i<=fdmax; i++){
            if(FD_ISSET(i, &readfds)){
                if (i == mnl_sock_event){
                    numbytes = mnl_socket_recvfrom(multi_link_nl_event, 
                            mnl_buf, sizeof(mnl_buf));
                    mnl_cb_run(mnl_buf, numbytes, 0, 0, 
                            multi_link_parse_netlink, mc);
                    LIST_FOREACH_CB(&multi_link_links_2, next,
                            multi_link_check_link, li, mc);
                } else if (i == mnl_sock_set){
                    numbytes = mnl_socket_recvfrom(multi_link_nl_set, mnl_buf, 
                            sizeof(mnl_buf));
                } else if (i == mnl_sock_get){
                    numbytes = mnl_socket_recvfrom(multi_link_nl_request, 
                            mnl_buf, sizeof(mnl_buf));
                } else if (i == multi_link_dhcp_pipes[0]){
                    numbytes = read(i, buf, MAX_PIPE_MSG_LEN);
                    LIST_FOREACH_CB(&multi_link_links_2, next,
                            multi_link_check_link, li, mc);
                    multi_link_clean_links();
                }
            } 
        }
    }
}
Пример #18
0
static uint8_t multi_core_parse_config(uint8_t *cfg_filename){
    yaml_parser_t parser;
    yaml_event_t event;
    FILE *cfgfile = NULL;
    uint8_t error = 0;
    struct multi_link_info_static *mlis;
      
    //Only in use when a configuration file is present
    TAILQ_INIT(&multi_shared_static_links);

    if((cfgfile = fopen(cfg_filename, "rb")) == NULL){
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not open configuration file\n");
        error = 1;
        return error;
    }

    //Initialized the parser
    assert(yaml_parser_initialize(&parser));
    yaml_parser_set_input_file(&parser, cfgfile);

    while(1){
        if(!yaml_parser_parse(&parser, &event)){
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Parsing failed\n");
            error = 1;
            break;
        }

        if(event.type == YAML_STREAM_END_EVENT){
            //LibYAML might allocate memory for events and so forth. Must 
            //therefore free
            yaml_event_delete(&event);
            break;
        } else if(event.type == YAML_SCALAR_EVENT){
            if(strlen(event.data.scalar.value) > IFNAMSIZ){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface name is too long\n");
                error = 1;
                break;
            }

            //The outer loop should only see scalars, which is the interface
            //names
            mlis = (struct multi_link_info_static *) 
                malloc(sizeof(struct multi_link_info_static));
            memset(mlis, 0, sizeof(*mlis));
            mlis->metric = 0;
            memcpy(mlis->dev_name, event.data.scalar.value, 
                    strlen(event.data.scalar.value) + 1);
            yaml_event_delete(&event);

            //Make sure next event is mapping!
            if(!yaml_parser_parse(&parser, &event)){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Parsing failed\n");
                error = 1;
                break;
            } else if(event.type != YAML_MAPPING_START_EVENT){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Configuration file is incorrect." 
                        "No information for interface\n");
                error = 1;
                break;
            }
            
            if(multi_core_parse_iface_info(mlis, &parser)){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, 
                        "Parsing of configuration file failed\n");
                error = 1;
                break;
            } else {
                TAILQ_INSERT_TAIL(&multi_shared_static_links, mlis, 
                        list_ptr);
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s added to static list\n", 
                        mlis->dev_name);
            }
        }
    }

    yaml_parser_delete(&parser);
    fclose(cfgfile);

    return error;
}