END_TEST START_TEST(tc_pico_mld_timer_expired) { struct mld_timer *t,*s; t = PICO_ZALLOC(sizeof(struct mld_timer)); t->stopped = MLD_TIMER_STOPPED; t->type = 0; pico_string_to_ipv6("AAAA::1", t->mcast_link.addr); pico_string_to_ipv6("AAAA::1", t->mcast_group.addr); //void function, just check for side effects pico_mld_timer_expired(NULL, (void *)t); pico_tree_insert(&MLDTimers, t); s = PICO_ZALLOC(sizeof(struct mld_timer)); memcpy(s,t,sizeof(struct mld_timer)); // t will be freed next test pico_mld_timer_expired(NULL, (void *)t); /* will be freed */ s->stopped++; s->start = PICO_TIME_MS()*2; s->type++; pico_tree_insert(&MLDTimers, s); t = PICO_ZALLOC(sizeof(struct mld_timer)); memcpy(t,s,sizeof(struct mld_timer)); // s will be freed next test pico_mld_timer_expired(NULL, (void *)s); /* s will be freed */ t->mld_callback = mock_callback; pico_mld_timer_expired(NULL, (void *)t); /* t will be freed */ }
END_TEST START_TEST(tc_mld_srst) { struct mld_parameters *p; struct pico_device *dev = pico_null_create("dummy3"); struct pico_ipv6_link *link; struct pico_ipv6_mcast_group g; struct mldv2_report *report; struct mld_timer t; //Building example frame p = PICO_ZALLOC(sizeof(struct mld_parameters)); pico_string_to_ipv6("AAAA::1", p->mcast_link.addr); pico_string_to_ipv6("FF00::e007:707", p->mcast_group.addr); p->MCASTFilter = &_MCASTFilter; p->filter_mode = 0; g.filter_mode = 0; g.mcast_addr = p->mcast_group; g.MCASTSources.root = &LEAF; g.MCASTSources.compare = mcast_sources_cmp_ipv6; pico_tree_insert(&MLDParameters, p); //no link fail_if(mld_srst(p) != -1); link = pico_ipv6_link_add(dev, p->mcast_link, p->mcast_link); link->mcast_compatibility = PICO_MLDV1; // invalid proto fail_if(mld_srst(p) != -1); link->mcast_compatibility = PICO_MLDV2; pico_tree_insert(link->MCASTGroups, &g); fail_if(mld_srst(p) != 0); }
END_TEST START_TEST(tc_pico_mld_process_in) { struct mld_parameters *p; struct pico_device *dev = pico_null_create("dummy3"); struct pico_ipv6_link *link; struct pico_tree *filter = PICO_ZALLOC(sizeof(struct pico_tree)); int i,j, _i,_j,result; struct pico_ipv6_mcast_group g; struct mldv2_report *report; //Building example frame p = PICO_ZALLOC(sizeof(struct mld_parameters)); pico_string_to_ipv6("AAAA::1", p->mcast_link.addr); pico_string_to_ipv6("FF00::e007:707", p->mcast_group.addr); //no link fail_if(pico_mld_generate_report(p) != -1); link = pico_ipv6_link_add(dev, p->mcast_link, p->mcast_link); pico_string_to_ipv6("AAAA::1", p->mcast_group.addr); fail_if(pico_mld_generate_report(p) != -1); pico_string_to_ipv6("FF00::e007:707", p->mcast_group.addr); link->mcast_compatibility = PICO_MLDV1; g.mcast_addr = p->mcast_group; g.MCASTSources.root = &LEAF; g.MCASTSources.compare = mcast_sources_cmp_ipv6; // No mcastsources tree link->mcast_compatibility = PICO_MLDV2; fail_if(pico_mld_generate_report(p) != -1); pico_tree_insert(link->MCASTGroups, &g); pico_tree_insert(&MLDParameters, p); link->mcast_compatibility = 99; fail_if(pico_mld_generate_report(p) != -1); link->mcast_compatibility = PICO_MLDV1; fail_if(pico_mld_generate_report(p) != 0); link->mcast_compatibility = PICO_MLDV2; for(_j =0; _j<3; _j++) { //FILTER (_j == 2) ? (result = -1) : (result = 0); for(_i=0; _i<3; _i++) { //FILTER if(_i == 2) result = -1; for(i = 0; i<3; i++) { //STATES for(j = 0; j<6; j++) { //EVENTS p->MCASTFilter = &_MCASTFilter; p->filter_mode = _i; g.filter_mode = _j; if(p->event == MLD_EVENT_DELETE_GROUP || p->event == MLD_EVENT_QUERY_RECV) p->event++; fail_if(pico_mld_generate_report(p) != result); p->state = i; p->event = j; if(result != -1 && p->f) {//in some combinations, no frame is created report = p->f->transport_hdr + MLD_ROUTER_ALERT_LEN; report->crc = short_be(pico_icmp6_checksum(p->f)); fail_if(pico_mld_process_in(p->f) != 0); } } } } } }
static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr) { struct pico_dhcp_server_negotiation *dhcpn = NULL; struct pico_dhcp_server_setting test = { 0 }; if (pico_dhcp_server_find_negotiation(hdr->xid)) return NULL; dhcpn = PICO_ZALLOC(sizeof(struct pico_dhcp_server_negotiation)); if (!dhcpn) { pico_err = PICO_ERR_ENOMEM; return NULL; } dhcpn->xid = hdr->xid; dhcpn->state = PICO_DHCP_STATE_DISCOVER; dhcpn->bcast = ((short_be(hdr->flags) & PICO_DHCP_FLAG_BROADCAST) != 0) ? (1) : (0); memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH); test.dev = dev; dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test); if (!dhcpn->dhcps) { dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name); PICO_FREE(dhcpn); return NULL; } dhcp_negotiation_set_ciaddr(dhcpn); pico_tree_insert(&DHCPNegotiations, dhcpn); return dhcpn; }
static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_prefix *hdr, uint16_t len, struct pico_dns_query_suffix *suffix, void (*callback)(char *, void *), void *arg) { struct pico_dns_query *q = NULL, *found = NULL; q = pico_zalloc(sizeof(struct pico_dns_query)); if (!q) return NULL; q->query = (char *)hdr; q->len = len; q->id = short_be(hdr->id); q->qtype = short_be(suffix->qtype); q->qclass = short_be(suffix->qclass); q->retrans = 1; q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); q->callback = callback; q->arg = arg; q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); if (!q->s) { pico_free(q); return NULL; } found = pico_tree_insert(&DNSTable, q); if (found) { pico_err = PICO_ERR_EAGAIN; pico_socket_close(q->s); pico_free(q); return NULL; } return q; }
static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr) { struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}}; dns = pico_zalloc(sizeof(struct pico_dns_ns)); if (!dns) { pico_err = PICO_ERR_ENOMEM; return NULL; } dns->ns = *ns_addr; found = pico_tree_insert(&NSTable, dns); if (found) { /* nameserver already present */ pico_free(dns); return found; } /* default NS found, remove it */ pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr); found = pico_tree_findKey(&NSTable, &test); if (found && (found->ns.addr != ns_addr->addr)) pico_dns_client_del_ns(&found->ns); return dns; }
static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid) { struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = { 0 }; test.xid = xid; found = pico_tree_findKey(&DHCPCookies, &test); if (found) { pico_err = PICO_ERR_EAGAIN; return NULL; } dhcpc = pico_zalloc(sizeof(struct pico_dhcp_client_cookie)); if (!dhcpc) { pico_err = PICO_ERR_ENOMEM; return NULL; } dhcpc->state = DHCP_CLIENT_STATE_INIT; dhcpc->status = DHCP_CLIENT_STATUS_INIT; dhcpc->xid = xid; dhcpc->uid = uid; *(dhcpc->uid) = 0; dhcpc->cb = cb; dhcpc->dev = dev; pico_tree_insert(&DHCPCookies, dhcpc); return dhcpc; }
END_TEST START_TEST(tc_mld_stsdifs) { struct mld_parameters *p; struct pico_device *dev = pico_null_create("dummy3"); struct pico_ipv6_link *link; struct pico_ipv6_mcast_group g; struct mldv2_report *report; struct mld_timer t; //Building example frame p = PICO_ZALLOC(sizeof(struct mld_parameters)); pico_string_to_ipv6("AAAA::1", p->mcast_link.addr); pico_string_to_ipv6("FF00::e007:707", p->mcast_group.addr); //no link fail_if(mld_stsdifs(p) != -1); link = pico_ipv6_link_add(dev, p->mcast_link, p->mcast_link); link->mcast_compatibility = PICO_MLDV1; // no timer fail_if(mld_stsdifs(p) != -1); t.type = MLD_TIMER_GROUP_REPORT; t.mcast_link = p->mcast_link; t.mcast_group = p->mcast_group; pico_tree_insert(&MLDTimers, &t); fail_if(mld_stsdifs(p) != 0); //set flag pico_mld_flag = 1; fail_if(mld_stsdifs(p) != 0); }
static struct pico_dhcp_server_setting *pico_dhcp_server_add_setting(struct pico_dhcp_server_setting *setting) { uint16_t port = PICO_DHCPD_PORT; struct pico_dhcp_server_setting *dhcps = NULL, *found = NULL, test = {0}; struct pico_ipv4_link *link = NULL; link = pico_ipv4_link_get(&setting->server_ip); if (!link) { pico_err = PICO_ERR_EINVAL; return NULL; } test.dev = setting->dev; found = pico_tree_findKey(&DHCPSettings, &test); if (found) { pico_err = PICO_ERR_EINVAL; return NULL; } dhcps = pico_zalloc(sizeof(struct pico_dhcp_server_setting)); if (!dhcps) { pico_err = PICO_ERR_ENOMEM; return NULL; } dhcps->lease_time = setting->lease_time; dhcps->pool_start = setting->pool_start; dhcps->pool_next = setting->pool_next; dhcps->pool_end = setting->pool_end; dhcps->dev = link->dev; dhcps->server_ip = link->address; dhcps->netmask = link->netmask; /* default values if not provided */ if (!dhcps->pool_start) dhcps->pool_start = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_START; if (!dhcps->pool_end) dhcps->pool_end = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_END; if (!dhcps->lease_time) dhcps->lease_time = DHCP_SERVER_LEASE_TIME; dhcps->pool_next = dhcps->pool_start; dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup); if (!dhcps->s) { dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err)); pico_free(dhcps); return NULL; } if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) { dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err)); pico_free(dhcps); return NULL; } pico_tree_insert(&DHCPSettings, dhcps); return dhcps; }
END_TEST START_TEST(tc_pico_mld_state_change) { struct pico_ip6 mcast_link, mcast_group; struct mld_parameters p; pico_string_to_ipv6("AAAA::1", mcast_link.addr); pico_string_to_ipv6("AAAA::1", mcast_group.addr); p.mcast_link = mcast_link; p.mcast_group = mcast_group; fail_if(pico_mld_state_change(NULL, &mcast_group, 0,NULL, PICO_MLD_STATE_CREATE) != -1); fail_if(pico_mld_state_change(&mcast_link, &mcast_group, 0,NULL, PICO_MLD_STATE_CREATE) != -1); fail_if(pico_mld_state_change(&mcast_link, &mcast_group, 0,NULL, 99) != -1); pico_tree_insert(&MLDParameters, &p); fail_if(pico_mld_state_change(&mcast_link, &mcast_group, 0,NULL, 99) != -1); }
END_TEST START_TEST(tc_pico_mld_find_parameter) { struct pico_ip6 mcast_link, mcast_group; struct mld_parameters test = { 0 }; fail_if(pico_mld_find_parameter(NULL,NULL) != NULL); pico_string_to_ipv6("AAAA::1", mcast_link.addr); fail_if(pico_mld_find_parameter(&mcast_link,NULL) != NULL); pico_string_to_ipv6("AAAA::2", mcast_group.addr); fail_if(pico_mld_find_parameter(&mcast_link,&mcast_group) != NULL); test.mcast_link = mcast_link; test.mcast_group = mcast_group; pico_tree_insert(&MLDParameters, &test); fail_if(pico_mld_find_parameter(&mcast_link,&mcast_group) == NULL); }
static void next_ping(uint32_t now, void *arg) { struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg; IGNORE_PARAMETER(now); if(pico_tree_findKey(&Pings,cookie)){ if (cookie->seq < cookie->count) { newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie)); if (!newcookie) return; memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie)); newcookie->seq++; pico_tree_insert(&Pings,newcookie); send_ping(newcookie); } } }
static inline struct pico_dhcp_server_setting *dhcps_try_open_socket(struct pico_dhcp_server_setting *dhcps) { uint16_t port = PICO_DHCPD_PORT; dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup); if (!dhcps->s) { dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err)); PICO_FREE(dhcps); return NULL; } if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) { dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err)); PICO_FREE(dhcps); return NULL; } pico_tree_insert(&DHCPSettings, dhcps); return dhcps; }
/**************** FILTER API's ****************/ uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr, struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port, int8_t priority, uint8_t tos, enum filter_action action) { static uint32_t filter_id = 1u; /* 0 is a special value used in the binary-tree search for packets being processed */ struct filter_node *new_filter; if (pico_ipv4_filter_add_validate(priority, action) < 0) { pico_err = PICO_ERR_EINVAL; return 0; } new_filter = PICO_ZALLOC(sizeof(struct filter_node)); if (!new_filter) { pico_err = PICO_ERR_ENOMEM; return 0; } new_filter->fdev = dev; new_filter->proto = proto; new_filter->out_addr = (!out_addr) ? (0U) : (out_addr->addr); new_filter->out_addr_netmask = (!out_addr_netmask) ? (0U) : (out_addr_netmask->addr); new_filter->in_addr = (!in_addr) ? (0U) : (in_addr->addr); new_filter->in_addr_netmask = (!in_addr_netmask) ? (0U) : (in_addr_netmask->addr); new_filter->out_port = out_port; new_filter->in_port = in_port; new_filter->priority = priority; new_filter->tos = tos; new_filter->filter_id = filter_id++; new_filter->function_ptr = fp_function[action].fn; if(pico_tree_insert(&filter_tree, new_filter)) { PICO_FREE(new_filter); filter_id--; return 0; } return new_filter->filter_id; }
struct mock_device *pico_mock_create(uint8_t*mac) { struct mock_device*mock = PICO_ZALLOC(sizeof(struct mock_device)); if(!mock) return NULL; mock->dev = PICO_ZALLOC(sizeof(struct pico_device)); if (!mock->dev) { PICO_FREE(mock); return NULL; } if(mac != NULL) { mock->mac = PICO_ZALLOC(6 * sizeof(uint8_t)); if(!mock->mac) { PICO_FREE(mock->mac); PICO_FREE(mock); return NULL; } memcpy(mock->mac, mac, 6); } if( 0 != pico_device_init((struct pico_device *)mock->dev, "mock", mac)) { dbg ("Loop init failed.\n"); pico_mock_destroy((struct pico_device *)mock->dev); if(mock->mac != NULL) PICO_FREE(mock->mac); PICO_FREE(mock); return NULL; } mock->dev->send = pico_mock_send; mock->dev->poll = pico_mock_poll; mock->dev->destroy = pico_mock_destroy; dbg("Device %s created.\n", mock->dev->name); pico_tree_insert(&mock_device_tree, mock); return mock; }
static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr) { struct pico_dhcp_server_negotiation *dhcpn = NULL; struct pico_dhcp_server_setting test = {0}; struct pico_ip4 *ciaddr = NULL; if (pico_dhcp_server_find_negotiation(hdr->xid)) return NULL; dhcpn = pico_zalloc(sizeof(struct pico_dhcp_server_negotiation)); if (!dhcpn) { pico_err = PICO_ERR_ENOMEM; return NULL; } dhcpn->xid = hdr->xid; dhcpn->state = PICO_DHCP_STATE_DISCOVER; memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH); test.dev = dev; dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test); if (!dhcpn->dhcps) { dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name); pico_free(dhcpn); return NULL; } ciaddr = pico_arp_reverse_lookup(&dhcpn->hwaddr); if (!ciaddr) { dhcpn->ciaddr.addr = dhcpn->dhcps->pool_next; dhcpn->dhcps->pool_next = long_be(long_be(dhcpn->dhcps->pool_next) + 1); pico_arp_create_entry(dhcpn->hwaddr.addr, dhcpn->ciaddr, dhcpn->dhcps->dev); } else { dhcpn->ciaddr = *ciaddr; } pico_tree_insert(&DHCPNegotiations, dhcpn); return dhcpn; }
int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)) { static uint16_t next_id = 0x91c0; struct pico_icmp4_ping_cookie *cookie; if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)){ pico_err = PICO_ERR_EINVAL; return -1; } cookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie)); if (!cookie) { pico_err = PICO_ERR_ENOMEM; return -1; } if (pico_string_to_ipv4(dst, &cookie->dst.addr) < 0) { pico_err = PICO_ERR_EINVAL; pico_free(cookie); return -1; } cookie->seq = 1; cookie->id = next_id++; cookie->err = PICO_PING_ERR_PENDING; cookie->size = (uint16_t)size; cookie->interval = interval; cookie->timeout = timeout; cookie->cb = cb; cookie->count = count; pico_tree_insert(&Pings,cookie); send_ping(cookie); return 0; }
int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) { struct pico_dns_ns test, *key = NULL; if (!ns) { pico_err = PICO_ERR_EINVAL; return -1; } switch (flag) { case PICO_DNS_NS_ADD: key = pico_zalloc(sizeof(struct pico_dns_ns)); if (!key) { pico_err = PICO_ERR_ENOMEM; return -1; } key->ns = *ns; if(pico_tree_insert(&NSTable,key)){ dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr); pico_err = PICO_ERR_EINVAL; pico_free(key); return -1; /* Element key already exists */ } dns_dbg("DNS: nameserver %08X added\n", ns->addr); /* If default NS found, remove it */ pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr); if (ns->addr != test.ns.addr) { key = pico_tree_findKey(&NSTable,&test); if (key) { if(pico_tree_delete(&NSTable,key)) { dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr); pico_free(key); } else { pico_err = PICO_ERR_EAGAIN; return -1; } } } break; case PICO_DNS_NS_DEL: test.ns = *ns; key = pico_tree_findKey(&NSTable,&test); if (!key) { dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr); pico_err = PICO_ERR_EINVAL; return -1; } /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ if(pico_tree_delete(&NSTable,key)) { dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr); pico_free(key); } else { pico_err = PICO_ERR_EAGAIN; return -1; } /* If no NS left, add default NS */ if(pico_tree_first(&NSTable) == NULL){ dns_dbg("DNS: add default nameserver\n"); return pico_dns_client_init(); } break; default: pico_err = PICO_ERR_EINVAL; return -1; } return 0; }