/** * \brief Take a packet received over the 802.15.4 link, and send it * out over ethernet, performing any translations needed. */ void mac_LowpanToEthernet(void) { #if !RF230BB parsed_frame = sicslowmac_get_frame(); #endif //Setup generic ethernet stuff ETHBUF(uip_buf)->type = uip_htons(UIP_ETHTYPE_IPV6); //Check for broadcast message #if RF230BB if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null)) { // if(linkaddr_cmp((const linkaddr_t *)destAddr, &linkaddr_null)) { #else if( ( parsed_frame->fcf->destAddrMode == SHORTADDRMODE) && ( parsed_frame->dest_addr->addr16 == 0xffff) ) { #endif ETHBUF(uip_buf)->dest.addr[0] = 0x33; ETHBUF(uip_buf)->dest.addr[1] = 0x33; #if UIP_CONF_IPV6 ETHBUF(uip_buf)->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12]; ETHBUF(uip_buf)->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13]; ETHBUF(uip_buf)->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14]; ETHBUF(uip_buf)->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15]; #else //Not intended to be functional, but allows ip4 build without errors. ETHBUF(uip_buf)->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[0]; ETHBUF(uip_buf)->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[1]; ETHBUF(uip_buf)->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[2]; ETHBUF(uip_buf)->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[3]; #endif } else { //Otherwise we have a real address mac_createEthernetAddr((uint8_t *) &(ETHBUF(uip_buf)->dest.addr[0]), (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } #if !UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS //Source ethernet depends on node if(!mac_createEthernetAddr( (uint8_t *) &(ETHBUF(uip_buf)->src.addr[0]), (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER) )) #endif { mac_createDefaultEthernetAddr((uint8_t *) &(ETHBUF(uip_buf)->src.addr[0])); } //We only do address translation in network mode! if (usbstick_mode.translate) { //Some IP packets have link layer in them, need to change them around! mac_translateIPLinkLayer(ll_8023_type); } #if UIP_CONF_IPV6_RPL /* We won't play ping-pong with the host! */ if(uip_ipaddr_cmp(&last_sender, &UIP_IP_BUF->srcipaddr)) { PRINTF("siclow_ethernet: Destination off-link but no route\n"); uip_len=0; return; } #endif PRINTF("Low2Eth: Sending packet to ethernet\n\r"); uip_len += UIP_LLH_LEN; usb_eth_send(uip_buf, uip_len, 1); #if !RF230BB usb_eth_stat.rxok++; #endif uip_len = 0; } /** * \brief Translate IP packet's possible link-layer addresses, passing * the message to the appropriate higher level function for this * packet (aka: ICMP) * \param target The target we want to end up with - either ll_8023_type * for ethernet, or ll_802154_type for 802.15.4 * \return Returns how successful the translation was * \retval 0 Addresses, if present, were translated. * \retval <0 Negative return values indicate various errors, as defined * by the higher level function. */ int8_t mac_translateIPLinkLayer(lltype_t target) { #if UIP_LLADDR_LEN == 8 if (UIP_IP_BUF->proto == UIP_PROTO_ICMP6) { PRINTF("eth2low: ICMP Message detected\n\r"); return mac_translateIcmpLinkLayer(target); } return 0; #else return 1; #endif } #include "net/ipv6/uip-icmp6.h" #include "net/ipv6/uip-nd6.h" typedef struct { uint8_t type; uint8_t length; uint8_t data[16]; } icmp_opts_t; #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN]) #define UIP_ICMP_OPTS(x) ((icmp_opts_t *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN + x]) void slide(uint8_t * data, uint8_t length, int16_t slide); /** * \brief Translate the link-layer (L2) addresses in an ICMP packet. * This will just be NA/NS/RA/RS packets currently. * \param target The target we want to end up with - either ll_8023_type * for ethernet, or ll_802154_type for 802.15.4 * \return Returns how successful the translation was * \retval 0 Addresses, if present, were translated. * \retval -1 ICMP message was unknown type, nothing done. * \retval -2 ICMP Length does not make sense? * \retval -3 Unknown 'target' type */ int8_t mac_translateIcmpLinkLayer(lltype_t target) { uint16_t icmp_opt_offset = 0; int16_t len = UIP_IP_BUF->len[1] | (UIP_IP_BUF->len[0] << 8); uint16_t iplen; uint8_t i; int16_t sizechange; uint8_t llbuf[16]; //Figure out offset to start of options switch(UIP_ICMP_BUF->type) { case ICMP6_NS: case ICMP6_NA: icmp_opt_offset = 24; break; case ICMP6_RS: icmp_opt_offset = 8; break; case ICMP6_RA: icmp_opt_offset = 16; break; case ICMP6_REDIRECT: icmp_opt_offset = 40; break; /** Things without link-layer */ case ICMP6_DST_UNREACH: case ICMP6_PACKET_TOO_BIG: case ICMP6_TIME_EXCEEDED: case ICMP6_PARAM_PROB: case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: return 0; break; default: return -1; } //Figure out length of options len -= icmp_opt_offset; //Sanity check if (len < 8) return -2; //While we have options to do... while (len >= 8){ //If we have one of these, we have something useful! if (((UIP_ICMP_OPTS(icmp_opt_offset)->type) == UIP_ND6_OPT_SLLAO) || ((UIP_ICMP_OPTS(icmp_opt_offset)->type) == UIP_ND6_OPT_TLLAO) ) { /* Shrinking the buffer may thrash things, so we store the old link-layer address */ for(i = 0; i < (UIP_ICMP_OPTS(icmp_opt_offset)->length*8 - 2); i++) { llbuf[i] = UIP_ICMP_OPTS(icmp_opt_offset)->data[i]; } //Shrink/grow buffer as needed if (target == ll_802154_type) { //Current is 802.3, Hence current link-layer option is 6 extra bytes sizechange = 8; slide(UIP_ICMP_OPTS(icmp_opt_offset)->data + 6, len - 6, sizechange); } else if (target == ll_8023_type) { /* Current is 802.15.4, Hence current link-layer option is 14 extra * bytes. * (Actual LL is 8 bytes, but total option length is in multiples of * 8 Bytes, hence 8 + 2 = 10. Closest is 16 bytes, then 16 bytes for * total optional length - 2 bytes for type + length leaves 14 ) */ sizechange = -8; slide(UIP_ICMP_OPTS(icmp_opt_offset)->data + 14, len - 14, sizechange); } else { return -3; //Uh-oh! } //Translate addresses if (target == ll_802154_type) { mac_createSicslowpanLongAddr(llbuf, (uip_lladdr_t *)UIP_ICMP_OPTS(icmp_opt_offset)->data); } else { #if !UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS if(!mac_createEthernetAddr(UIP_ICMP_OPTS(icmp_opt_offset)->data, (uip_lladdr_t *)llbuf)) #endif mac_createDefaultEthernetAddr(UIP_ICMP_OPTS(icmp_opt_offset)->data); } //Adjust the length if (target == ll_802154_type) { UIP_ICMP_OPTS(icmp_opt_offset)->length = 2; } else { UIP_ICMP_OPTS(icmp_opt_offset)->length = 1; } //Adjust the IP header length, as well as uIP length iplen = UIP_IP_BUF->len[1] | (UIP_IP_BUF->len[0]<<8); iplen += sizechange; len += sizechange; UIP_IP_BUF->len[1] = (uint8_t)iplen; UIP_IP_BUF->len[0] = (uint8_t)(iplen >> 8); uip_len += sizechange; //We broke ICMP checksum, be sure to fix that UIP_ICMP_BUF->icmpchksum = 0; #if UIP_CONF_IPV6 //allow non ipv6 builds UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); #endif //Finally set up next run in while loop len -= 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length; icmp_opt_offset += 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length; } else { //Not an option we care about, ignore it len -= 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length; //This shouldn't happen! if (UIP_ICMP_OPTS(icmp_opt_offset)->length == 0) { PRINTF("Option in ND packet has length zero, error?\n\r"); len = 0; } icmp_opt_offset += 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length; } //If ICMP_OPT is one we care about } //while(len >= 8)
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop) { uip_ds6_route_t *r; struct uip_ds6_route_neighbor_route *nbrr; #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ /* Get link-layer address of next hop, make sure it is in neighbor table */ const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop); if(nexthop_lladdr == NULL) { PRINTF("uip_ds6_route_add: neighbor link-local address unknown for "); PRINT6ADDR(nexthop); PRINTF("\n"); return NULL; } /* First make sure that we don't add a route twice. If we find an existing route for our destination, we'll delete the old one first. */ r = uip_ds6_route_lookup(ipaddr); if(r != NULL) { uip_ipaddr_t *current_nexthop; current_nexthop = uip_ds6_route_nexthop(r); if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) { /* no need to update route - already correct! */ return r; } PRINTF("uip_ds6_route_add: old route for "); PRINT6ADDR(ipaddr); PRINTF(" found, deleting it\n"); uip_ds6_route_rm(r); } { struct uip_ds6_route_neighbor_routes *routes; /* If there is no routing entry, create one. We first need to check if we have room for this route. If not, we remove the least recently used one we have. */ if(uip_ds6_route_num_routes() == UIP_DS6_ROUTE_NB) { uip_ds6_route_t *oldest; oldest = NULL; #if UIP_DS6_ROUTE_REMOVE_LEAST_RECENTLY_USED /* Removing the oldest route entry from the route table. The least recently used route is the first route on the list. */ oldest = list_tail(routelist); #endif if(oldest == NULL) { return NULL; } PRINTF("uip_ds6_route_add: dropping route to "); PRINT6ADDR(&oldest->ipaddr); PRINTF("\n"); uip_ds6_route_rm(oldest); } /* Every neighbor on our neighbor table holds a struct uip_ds6_route_neighbor_routes which holds a list of routes that go through the neighbor. We add our route entry to this list. We first check to see if we already have this neighbor in our nbr_route table. If so, the neighbor already has a route entry list. */ routes = nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)nexthop_lladdr); if(routes == NULL) { /* If the neighbor did not have an entry in our neighbor table, we create one. The nbr_table_add_lladdr() function returns a pointer to a pointer that we may use for our own purposes. We initialize this pointer with the list of routing entries that are attached to this neighbor. */ routes = nbr_table_add_lladdr(nbr_routes, (linkaddr_t *)nexthop_lladdr, NBR_TABLE_REASON_ROUTE, NULL); if(routes == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate neighbor table entry\n"); return NULL; } LIST_STRUCT_INIT(routes, route_list); #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK((const linkaddr_t *)nexthop_lladdr); #endif } /* Allocate a routing entry and populate it. */ r = memb_alloc(&routememb); if(r == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate route\n"); return NULL; } /* add new routes first - assuming that there is a reason to add this and that there is a packet coming soon. */ list_push(routelist, r); nbrr = memb_alloc(&neighborroutememb); if(nbrr == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate neighbor route list entry\n"); memb_free(&routememb, r); return NULL; } nbrr->route = r; /* Add the route to this neighbor */ list_add(routes->route_list, nbrr); r->neighbor_routes = routes; num_routes++; PRINTF("uip_ds6_route_add num %d\n", num_routes); /* lock this entry so that nexthop is not removed */ nbr_table_lock(nbr_routes, routes); } uip_ipaddr_copy(&(r->ipaddr), ipaddr); r->length = length; #ifdef UIP_DS6_ROUTE_STATE_TYPE memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE)); #endif PRINTF("uip_ds6_route_add: adding route: "); PRINT6ADDR(ipaddr); PRINTF(" via "); PRINT6ADDR(nexthop); PRINTF("\n"); ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); #if UIP_DS6_NOTIFICATIONS call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop); #endif #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ #ifdef NETSTACK_CONF_ROUTE_ADDED_CALLBACK NETSTACK_CONF_ROUTE_ADDED_CALLBACK(ipaddr); #endif /* NETSTACK_CONF_ROUTE_ADDED_CALLBACK*/ return r; }
node_info_t * node_info_update(uip_ipaddr_t * ipaddr, char * info) { node_info_t *node = NULL; char * sep; uip_ipaddr_t ip_parent; node = node_info_lookup(ipaddr); if (node == NULL) { node = node_info_add(ipaddr); } if ( node != NULL ) { node->last_seen = clock_time(); node->last_message = clock_time(); uint16_t up_sequence = 0; uint16_t down_sequence = 0; sep = index(info, '|'); if (sep != NULL) { node->messages_received++; up_sequence = atoi(info); *sep = 0; info = sep + 1; if (*info == ' ') { info++; } sep = index(info, '|'); if (sep != NULL) { *sep = 0; } if (uiplib_ipaddrconv(info, &ip_parent) == 0) { uip_create_unspecified(&ip_parent); } if(!uip_ipaddr_cmp(&node->ip_parent, &ip_parent)) { uip_ipaddr_copy(&(node->ip_parent), &ip_parent); if (node->messages_received > 1) { node->parent_switch++; } } if (sep != NULL) { info = sep + 1; down_sequence = atoi(info); } if (node->messages_received > 1) { uint16_t up_delta = up_sequence - node->last_up_sequence; if (up_delta < 100) { node->messages_sent += up_delta; node->up_messages_lost += up_delta - 1; if(down_sequence != node->last_down_sequence + 1) { node->down_messages_lost += 1; } } else { //Reset statistics node->messages_sent = 1; node->replies_sent = 0; node->up_messages_lost = 0; node->down_messages_lost = 0; } } else { node->messages_sent = 1; node->replies_sent = 0; node->up_messages_lost = 0; node->down_messages_lost = 0; } node->last_up_sequence = up_sequence; node->last_down_sequence = down_sequence; } else { node->last_up_sequence = 0; node->last_down_sequence = 0; uip_create_unspecified(&node->ip_parent); } } return node; }
/*----------------------------------------------------------------------------*/ void uip_arp_arpin(void) { //spark_print("\n****************************uip_arp_arpin\n"); //spark_printLong(uip_len); if(uip_len < sizeof(struct arp_hdr)) { //spark_print("\nuip len is not updated\n"); //spark_printLong(uip_len); uip_len = 0; return; } uip_len = 0; //spark_print("\n\n\nBUF->opcode\n"); //spark_printLong(BUF->opcode); //spark_print("\n\n\nBUF->hwlen\n"); //spark_printLong(BUF->hwlen); //spark_printLong( ((u16_t *)(BUF->dipaddr))[0] ); //spark_printLong( ((u16_t *)(BUF->dipaddr))[1] ); //spark_printLong( ((u16_t *)(uip_hostaddr))[0] ); //spark_printLong( ((u16_t *)(uip_hostaddr))[1] ); switch(BUF->opcode) { case HTONS(ARP_REQUEST): /* ARP request. If it asked for our address, we send out a reply. */ if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { //spark_print("\n\n\n\n-----------------------ARP_REQUESTFOR Me\n"); //spark_print("--------------------------------FOR ME\n"); /* First, we register the one who made the request in our ARP table, since it is likely that we will do more communication with this host in the future. */ uip_arp_update(BUF->sipaddr, &BUF->shwaddr); /* The reply opcode is 2. */ BUF->opcode = HTONS(2); memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); BUF->dipaddr[0] = BUF->sipaddr[0]; BUF->dipaddr[1] = BUF->sipaddr[1]; BUF->sipaddr[0] = uip_hostaddr[0]; BUF->sipaddr[1] = uip_hostaddr[1]; BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); uip_len = sizeof(struct arp_hdr); } break; case HTONS(ARP_REPLY): //spark_print("\n--------------------------------ARP_REPLY\n"); /* ARP reply. We insert or update the ARP table if it was meant for us. */ if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { //spark_print("\n\n\n\nuip_arp_updating the ARP table \n"); uip_arp_update(BUF->sipaddr, &BUF->shwaddr); } break; } return; }
/*-----------------------------------------------------------------------------------*/ void uip_arp_out(void) { struct arp_entry *tabptr; /* Find the destination IP address in the ARP table and construct the Ethernet header. If the destination IP addres isn't on the local network, we use the default router's IP address instead. If not ARP table entry is found, we overwrite the original IP packet with an ARP request for the IP address. */ /* First check if destination is a local broadcast. */ if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) { memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); } else { /* Check if the destination address is on the local network. */ if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { /* Destination address was not on the local network, so we need to use the default router's IP address instead of the destination address when determining the MAC address. */ uip_ipaddr_copy(ipaddr, uip_draddr); } else { /* Else, we use the destination IP address. */ uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); } for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { tabptr = &arp_table[i]; if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) { break; } } if(i == UIP_ARPTAB_SIZE) { /* The destination address was not in our ARP table, so we overwrite the IP packet with an ARP request. */ memset(BUF->ethhdr.dest.addr, 0xff, 6); memset(BUF->dhwaddr.addr, 0x00, 6); memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); uip_ipaddr_copy(BUF->dipaddr, ipaddr); uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ BUF->hwtype = HTONS(ARP_HWTYPE_ETH); BUF->protocol = HTONS(UIP_ETHTYPE_IP); BUF->hwlen = 6; BUF->protolen = 4; BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; uip_len = sizeof(struct arp_hdr); return; } /* Build an ethernet header. */ memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); } memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); uip_len += sizeof(struct uip_eth_hdr); }
/*-----------------------------------------------------------------------------------*/ void uip_arp_arpin(void) { if(uip_len < sizeof(struct arp_hdr)) { uip_len = 0; return; } uip_len = 0; switch(BUF->opcode) { case HTONS(ARP_REQUEST): /* ARP request. If it asked for our address, we send out a reply. */ if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr) #ifdef RFM12_ARP_PROXY /* If RFM12 ARP-proxy is enabled, check that one's IP address as well and possibly answer it. */ || uip_ipaddr_maskcmp(BUF->dipaddr, rfm12_stack_hostaddr, rfm12_stack_netmask) #endif #ifdef ZBUS_ARP_PROXY /* If ZBUS ARP-proxy is enabled, check that one's IP address as well and possibly answer it. */ || uip_ipaddr_maskcmp(BUF->dipaddr, zbus_stack_hostaddr, zbus_stack_netmask) #endif #ifdef USB_ARP_PROXY /* If USB ARP-proxy is enabled, check that one's IP address as well and possibly answer it. */ || uip_ipaddr_maskcmp(BUF->dipaddr, usb_stack_hostaddr, usb_stack_netmask) #endif ) { /* First, we register the one who made the request in our ARP table, since it is likely that we will do more communication with this host in the future. */ uip_arp_update(BUF->sipaddr, &BUF->shwaddr); /* The reply opcode is 2. */ BUF->opcode = HTONS(2); memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); for (uint8_t i = 0; i < 4; i ++) flip (uint8_t, ((uint8_t *) BUF->dipaddr)[i], ((uint8_t *) BUF->sipaddr)[i]); /* BUF->dipaddr[0] = BUF->sipaddr[0]; BUF->dipaddr[1] = BUF->sipaddr[1]; BUF->sipaddr[0] = uip_hostaddr[0]; BUF->sipaddr[1] = uip_hostaddr[1]; */ BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); uip_len = sizeof(struct arp_hdr); } break; case HTONS(ARP_REPLY): /* ARP reply. We insert or update the ARP table if it was meant for us. */ if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { uip_arp_update(BUF->sipaddr, &BUF->shwaddr); } break; } return; }
void udpio_net_main(void) { uint8_t* answer = uip_appdata; uint8_t i; uip_ipaddr_t nullip; uip_ipaddr(&nullip, 0,0,0,0); if (uip_newdata ()) { // No new data: We will compare pins instead for (i=0;i<ALLOWED_CLIENTS;++i) { if(uip_ipaddr_cmp(&(clients[i].address), &nullip)) continue; // found address of calling client in clients: compare pins now if (vport[clients[i].pinport].read_port(clients[i].pinport) ^ clients[i].last_pin_state) { // update last pin state clients[i].last_pin_state = vport[clients[i].pinport].read_port(clients[i].pinport) & clients[i].pinmask; // send changes answer[0] = 'p'; answer[1] = 'i'; answer[2] = 'n'; answer[3] = 'c'; answer[4] = clients[i].pinport; answer[5] = clients[i].last_pin_state; uip_slen += 6; answer += 6; uip_udp_conn_t echo_conn; uip_ipaddr_copy(echo_conn.ripaddr, BUF->srcipaddr); echo_conn.rport = HTONS(UDP_IO_PORT); // send packages to clients at the udp io module port echo_conn.lport = HTONS(UDP_IO_PORT); uip_udp_conn = &echo_conn; uip_process(UIP_UDP_SEND_CONN); router_output(); uip_slen = 0; } } // No new data, return now return; } uip_slen = 0; uint16_t len = uip_len; uint8_t buffer[uip_len]; memcpy(buffer, uip_appdata, uip_len); struct udpio_packet* packet = (struct udpio_packet*)buffer; while (len>=sizeof(struct udpio_packet)) { switch(packet->mode) { case udpIOOnlyDisable: if (packet->port > IO_HARD_PORTS) break; vport[packet->port].write_port(packet->port, vport[packet->port].read_port(packet->port) & ~(uint8_t)packet->pinmask); break; case udpIOOnlyEnable: if (packet->port > IO_HARD_PORTS) break; vport[packet->port].write_port(packet->port, vport[packet->port].read_port(packet->port) | packet->pinmask); break; case udpIOEnableAndDisable: if (packet->port > IO_HARD_PORTS) break; vport[packet->port].write_port(packet->port, packet->pinmask); break; case udpIOGetAllPortPins: answer[0] = 'p'; answer[1] = 'i'; answer[2] = 'n'; answer[3] = 's'; answer[4] = PORTA; answer[5] = PORTB; answer[6] = PORTC; answer[7] = PORTD; uip_slen += 8; answer += 8; break; case udpIORegisterClientForPortChanges: // look for a not used entry in the array for (;i<ALLOWED_CLIENTS;++i) { if(uip_ipaddr_cmp(&(clients[i].address), nullip)) // found empty entry break; } // override last array entry if no free entry available if (i==ALLOWED_CLIENTS) i = ALLOWED_CLIENTS-1; // create entry with ip adress of the calling client, the ioport to observe, the pinmask and the current port state uip_ipaddr_copy(&(clients[i].address), BUF->srcipaddr); clients[i].pinport = packet->port; clients[i].pinmask = packet->pinmask; clients[i].last_pin_state = vport[packet->port].read_port(packet->port) & clients[i].pinmask; break; case udpIOUnRegisterClientForPortChanges: for (i=0;i<ALLOWED_CLIENTS;++i) { if(uip_ipaddr_cmp(&(clients[i].address), &(BUF->srcipaddr))) // found address of calling client in clients: remove it now uip_ipaddr(&(clients[i].address), 0,0,0,0); } break; default: break; }; packet++; len-=sizeof(struct udpio_packet); } if (uip_slen == 0) return; /* Sent data out */ uip_udp_conn_t echo_conn; uip_ipaddr_copy(echo_conn.ripaddr, BUF->srcipaddr); echo_conn.rport = BUF->srcport; echo_conn.lport = HTONS(UDP_IO_PORT); uip_udp_conn = &echo_conn; uip_process(UIP_UDP_SEND_CONN); router_output(); uip_slen = 0; }
/*---------------------------------------------------------------------------*/ static void handle_incoming_rrep(void) { struct uaodv_msg_rrep *rm = (struct uaodv_msg_rrep *)uip_appdata; struct uaodv_rt_entry *rt; /* Useless HELLO message? */ if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr)) { #ifdef AODV_RESPOND_TO_HELLOS uint32_t net_seqno; #ifdef CC2420_RADIO int ret = cc2420_check_remote(uip_udp_sender()->u16[1]); if(ret == REMOTE_YES) { print_debug("HELLO drop is remote\n"); return; } else if (ret == REMOTE_NO) { /* Is neigbour, accept it. */ } else if(cc2420_last_rssi < RSSI_THRESHOLD) { print_debug("HELLO drop %d %d\n", cc2420_last_rssi, cc2420_last_correlation); return; } #endif /* Sometimes it helps to send a non-requested RREP in response! */ net_seqno = uip_htonl(my_hseqno); send_rrep(&uip_hostaddr, &BUF->srcipaddr, &BUF->srcipaddr, &net_seqno, 0); #endif return; } print_debug("RREP %d.%d.%d.%d -> %d.%d.%d.%d" " dest=%d.%d.%d.%d seq=%lu hops=%u orig=%d.%d.%d.%d\n", uip_ipaddr_to_quad(&BUF->srcipaddr), uip_ipaddr_to_quad(&BUF->destipaddr), uip_ipaddr_to_quad(&rm->dest_addr), uip_ntohl(rm->dest_seqno), rm->hop_count, uip_ipaddr_to_quad(&rm->orig_addr)); rt = uaodv_rt_lookup(&rm->dest_addr); /* New forward route? */ if(rt == NULL || (SCMP32(uip_ntohl(rm->dest_seqno), rt->hseqno) > 0)) { print_debug("Inserting3\n"); rt = uaodv_rt_add(&rm->dest_addr, uip_udp_sender(), rm->hop_count, &rm->dest_seqno); #ifdef CC2420_RADIO /* This link is ok since he is unicasting back to us! */ cc2420_recv_ok(uip_udp_sender()); print_debug("RREP recv ok %d %d\n", cc2420_last_rssi, cc2420_last_correlation); #endif } else { print_debug("Not inserting\n"); } /* Forward RREP towards originator? */ if(uip_ipaddr_cmp(&rm->orig_addr, &uip_hostaddr)) { print_debug("ROUTE FOUND\n"); if(rm->flags & UAODV_RREP_ACK) { struct uaodv_msg_rrep_ack *ack = (void *)uip_appdata; ack->type = UAODV_RREP_ACK_TYPE; ack->reserved = 0; sendto(uip_udp_sender(), ack, sizeof(*ack)); } } else { rt = uaodv_rt_lookup(&rm->orig_addr); if(rt == NULL) { print_debug("RREP received, but no route back to originator... :-( \n"); return; } if(rm->flags & UAODV_RREP_ACK) { print_debug("RREP with ACK request (ignored)!\n"); /* Don't want any RREP-ACKs in return! */ rm->flags &= ~UAODV_RREP_ACK; } rm->hop_count++; print_debug("Fwd RREP to %d.%d.%d.%d\n", uip_ipaddr_to_quad(&rt->nexthop)); sendto(&rt->nexthop, rm, sizeof(struct uaodv_msg_rrep)); } }
void uip_icmpinput(struct uip_driver_s *dev) { struct uip_icmpip_hdr *picmp = ICMPBUF; #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.recv++; #endif #ifndef CONFIG_NET_IPv6 /* ICMPv4 processing code follows. */ /* ICMP echo (i.e., ping) processing. This is simple, we only change the * ICMP type from ECHO to ECHO_REPLY and adjust the ICMP checksum before * we return the packet. */ if (picmp->type == ICMP_ECHO_REQUEST) { /* If we are configured to use ping IP address assignment, we use * the destination IP address of this ping packet and assign it to * ourself. */ #ifdef CONFIG_NET_PINGADDRCONF if (dev->d_ipaddr == 0) { dev->d_ipaddr = picmp->destipaddr; } #endif /* Change the ICMP type */ picmp->type = ICMP_ECHO_REPLY; /* Swap IP addresses. */ uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr); uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); /* Recalculate the ICMP checksum */ #if 0 /* The slow way... sum over the ICMP message */ picmp->icmpchksum = 0; picmp->icmpchksum = ~uip_icmpchksum(dev, (((uint16_t)picmp->len[0] << 8) | (uint16_t)picmp->len[1]) - UIP_IPH_LEN); if (picmp->icmpchksum == 0) { picmp->icmpchksum = 0xffff; } #else /* The quick way -- Since only the type has changed, just adjust the * checksum for the change of type */ if (picmp->icmpchksum >= HTONS(0xffff - (ICMP_ECHO_REQUEST << 8))) { picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8) + 1; } else { picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8); } #endif nllvdbg("Outgoing ICMP packet length: %d (%d)\n", dev->d_len, (picmp->len[0] << 8) | picmp->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.sent++; uip_stat.ip.sent++; #endif } /* If an ICMP echo reply is received then there should also be * a thread waiting to received the echo response. */ #ifdef CONFIG_NET_ICMP_PING else if (picmp->type == ICMP_ECHO_REPLY && g_echocallback) { (void)uip_callbackexecute(dev, picmp, UIP_ECHOREPLY, g_echocallback); } #endif /* Otherwise the ICMP input was not processed */ else { nlldbg("Unknown ICMP cmd: %d\n", picmp->type); goto typeerr; } return; typeerr: #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.typeerr++; uip_stat.icmp.drop++; #endif dev->d_len = 0; #else /* !CONFIG_NET_IPv6 */ /* If we get a neighbor solicitation for our address we should send * a neighbor advertisement message back. */ if (picmp->type == ICMP6_NEIGHBOR_SOLICITATION) { if (uip_ipaddr_cmp(picmp->icmp6data, dev->d_ipaddr)) { if (picmp->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { /* Save the sender's address in our neighbor list. */ uiphdr_neighbor_add(picmp->srcipaddr, &(picmp->options[2])); } /* We should now send a neighbor advertisement back to where the * neighbor solicitation came from. */ picmp->type = ICMP6_NEIGHBOR_ADVERTISEMENT; picmp->flags = ICMP6_FLAG_S; /* Solicited flag. */ picmp->reserved1 = picmp->reserved2 = picmp->reserved3 = 0; uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr); uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); picmp->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; picmp->options[1] = 1; /* Options length, 1 = 8 bytes. */ memcpy(&(picmp->options[2]), &dev->d_mac, IFHWADDRLEN); picmp->icmpchksum = 0; picmp->icmpchksum = ~uip_icmp6chksum(dev); } else { goto drop; } } else if (picmp->type == ICMP6_ECHO_REQUEST) { /* ICMP echo (i.e., ping) processing. This is simple, we only * change the ICMP type from ECHO to ECHO_REPLY and update the * ICMP checksum before we return the packet. */ picmp->type = ICMP6_ECHO_REPLY; uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr); uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); picmp->icmpchksum = 0; picmp->icmpchksum = ~uip_icmp6chksum(dev); } /* If an ICMP echo reply is received then there should also be * a thread waiting to received the echo response. */ #ifdef CONFIG_NET_ICMP_PING else if (picmp->type == ICMP6_ECHO_REPLY && g_echocallback) { uint16_t flags = UIP_ECHOREPLY; if (g_echocallback) { /* Dispatch the ECHO reply to the waiting thread */ flags = uip_callbackexecute(dev, picmp, flags, g_echocallback); } /* If the ECHO reply was not handled, then drop the packet */ if (flags == UIP_ECHOREPLY) { /* The ECHO reply was not handled */ goto drop; } } #endif else { nlldbg("Unknown ICMP6 cmd: %d\n", picmp->type); goto typeerr; } nllvdbg("Outgoing ICMP6 packet length: %d (%d)\n", dev->d_len, (picmp->len[0] << 8) | picmp->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.sent++; uip_stat.ip.sent++; #endif return; typeerr: #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.typeerr++; #endif drop: #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.drop++; #endif dev->d_len = 0; #endif /* !CONFIG_NET_IPv6 */ }
static int eth_output(const uip_lladdr_t * src, const uip_lladdr_t * dest) { if(IS_BROADCAST_ADDR(dest)) { LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: broadcast\n"); } else { LOG6LBR_LLADDR_PRINTF(PACKET, PF_OUT, dest, "eth_output: "); } //Packet filtering //---------------- if(uip_len == 0) { LOG6LBR_ERROR("eth_output: uip_len = 0\n"); return 0; } if(dest && linkaddr_cmp((linkaddr_t *) & dest, (linkaddr_t *) & eth_mac64_addr)) { LOG6LBR_ERROR("ethernet_output: sending to self\n"); return 0; } #if CETIC_6LBR_ETH_FILTER_RPL //Filter out RPL (broadcast) traffic if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_RPL) { //LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Filtering out RPL traffic\n"); return 0; } #endif //IP packet alteration //-------------------- #if CETIC_6LBR_ROUTER //Modify source address if((nvm_data.mode & CETIC_MODE_REWRITE_ADDR_MASK) != 0 && uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) && uip_ipaddr_cmp(&UIP_IP_BUF->srcipaddr, &wsn_ip_local_addr)) { LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Update src address\n"); uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, ð_ip_local_addr); if(UIP_IP_BUF->proto == UIP_PROTO_UDP) { #if UIP_UDP_CHECKSUMS /* Calculate UDP checksum. */ UIP_UDP_BUF->udpchksum = 0; UIP_UDP_BUF->udpchksum = ~(uip_udpchksum()); if(UIP_UDP_BUF->udpchksum == 0) { UIP_UDP_BUF->udpchksum = 0xffff; } #endif /* UIP_UDP_CHECKSUMS */ } else if(UIP_IP_BUF->proto == UIP_PROTO_TCP) { /* Calculate TCP checksum. */ UIP_TCP_BUF->tcpchksum = 0; UIP_TCP_BUF->tcpchksum = ~(uip_tcpchksum()); } else if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6) { /* Calculate ICMP checksum. */ UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); } } #endif #if CETIC_6LBR_SMARTBRIDGE //Reset Hop Limit when in smart-bridge for NDP packets //TODO: Is this still needed after #4467 ? if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && (UIP_ICMP_BUF->type == ICMP6_NS || UIP_ICMP_BUF->type == ICMP6_NA || UIP_ICMP_BUF->type == ICMP6_RS || UIP_ICMP_BUF->type == ICMP6_RA)) { UIP_IP_BUF->ttl = 255; } #endif #if CETIC_6LBR_SMARTBRIDGE || CETIC_6LBR_TRANSPARENTBRIDGE //Remove ROUTER flag when in bridge mode if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_NA) { //LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Updating NA\n"); UIP_ND6_NA_BUF->flagsreserved &= ~UIP_ND6_NA_FLAG_ROUTER; } #endif //Some IP packets have link layer in them, need to change them around! mac_translateIPLinkLayer(ll_8023_type); //IP header alteration //-------------------- #if UIP_CONF_IPV6_RPL rpl_remove_header(); #endif //Create packet header //-------------------- //Packet type BUF->type = uip_htons(UIP_ETHTYPE_IPV6); //Destination address if(IS_BROADCAST_ADDR(dest)) { BUF->dest.addr[0] = 0x33; BUF->dest.addr[1] = 0x33; BUF->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12]; BUF->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13]; BUF->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14]; BUF->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15]; } else { mac_createEthernetAddr(BUF->dest.addr, dest); } //Source address if ( src != NULL ) { mac_createEthernetAddr(BUF->src.addr, src); } else { memcpy(BUF->src.addr, eth_mac_addr, 6); } //Sending packet //-------------- LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Sending packet to Ethernet\n"); eth_drv_send(uip_buf, uip_len + UIP_LLH_LEN); return 1; }
/*-----------------------------------------------------------------------------------*/ void uip_arp_arpin(void) { if(uip_len < sizeof(struct arp_hdr)) { uip_len = 0; return; } uip_len = 0; switch(BUF->opcode) { case HTONS(ARP_HINT): /* Please note this is not a valid ARP type, this is just a * hint to implement prefetch/refresh of ARP mapping */ /* This is a valid hint if we are the source of this request, * the requested ipaddr is in dipaddress */ if(uip_ipaddr_cmp(BUF->sipaddr, uip_hostaddr)) { /* We first try to check for the destination address * in our ARP table */ if(uip_arp_update(BUF->dipaddr, &broadcast_ethaddr)) { /* If the destination address was not in our ARP table, * we send out an ARP request for the same */ memset(BUF->ethhdr.dest.addr, 0xff, 6); BUF->opcode = HTONS(ARP_REQUEST); /* The other ARP fields of incoming hint are * supposed to be same as ARP broadcast except * the opcode field */ uip_len = sizeof(struct arp_hdr); } } break; case HTONS(ARP_REQUEST): /* ARP request. If it asked for our address, we send out a reply. */ if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { /* First, we register the one who made the request in our ARP table, since it is likely that we will do more communication with this host in the future. */ uip_arp_update(BUF->sipaddr, &BUF->shwaddr); BUF->opcode = HTONS(ARP_REPLY); memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); BUF->dipaddr[0] = BUF->sipaddr[0]; BUF->dipaddr[1] = BUF->sipaddr[1]; BUF->sipaddr[0] = uip_hostaddr[0]; BUF->sipaddr[1] = uip_hostaddr[1]; BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); uip_len = sizeof(struct arp_hdr); } break; case HTONS(ARP_REPLY): /* ARP reply. We insert or update the ARP table if it was meant for us. */ if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { uip_arp_update(BUF->sipaddr, &BUF->shwaddr); vmm_completion_complete(&uip_arp_prefetch_done); } break; } return; }
PROCESS_THREAD(cc2420_process, ev, data) { PROCESS_BEGIN(); process_start(&cc2420_retransmit_process, NULL); while (1) { unsigned len; int s; PROCESS_YIELD(); len = rx_fifo_remaining_bytes; if (len > 0) { /* Read payload and two bytes of footer */ if ((len - 2) > (UIP_BUFSIZE - UIP_LLH_LEN) || len < 2) { PRINTF("cc2420_process too big len=%d\n", len); s = splhigh(); FASTSPI_READ_FIFO_GARBAGE(len); rx_fifo_remaining_bytes = 0; /* RX FIFO emptied! */ splx(s); len = 0; } else { u8_t footer[2]; uip_len = 0; s = splhigh(); if (len > 2) FASTSPI_READ_FIFO_NO_WAIT(&uip_buf[UIP_LLH_LEN], len - 2); FASTSPI_READ_FIFO_NO_WAIT(footer, 2); rx_fifo_remaining_bytes = 0; /* RX FIFO emptied! */ splx(s); if (footer[1] & FOOTER1_CRC_OK) { cc2420_last_rssi = footer[0]; cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; if ((h.fc0 & FC0_TYPE_MASK) == FC0_TYPE_DATA) uip_len = len - 2; } } } if (len == 2) PRINTF("recv data_ack\n"); /* Clean up in case of FIFO overflow! This happens for every full * length frame and is signaled by FIFOP = 1 and FIFO = 0. */ if (FIFOP_IS_1 && !FIFO_IS_1) { cc2420_strobe(CC2420_SFLUSHRX); cc2420_strobe(CC2420_SFLUSHRX); } if (FIFOP_IS_1) { s = splhigh(); __cc2420_intr(); /* Fake interrupt! */ splx(s); } if (len == 2) { /* A DATA ACK packet. */ if (last_dst == h.src) cc2420_ack_received = 1; neigbour_update(h.src, 0); } else if (len > 2 && uip_len > 0 && uip_len == (((u16_t)(BUF->len[0]) << 8) + BUF->len[1])) { /* * If we are the unique receiver send DATA ACK. */ if (h.dst == 0xffff && uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr)) cc2420_send_data_ack(h.src); leds_toggle(LEDS_GREEN); cc2420_is_input = 1; tcpip_input(); cc2420_is_input = 0; leds_toggle(LEDS_GREEN); } } PROCESS_END(); }
/*-----------------------------------------------------------------------------------*/ uint8_t uip_arp_out(void) { #ifdef MDNS_SD_SUPPORT uip_ipaddr_t mdns_address = {0x00e0, 0xfb00}; #endif /* Find the destination IP address in the ARP table and construct the Ethernet header. If the destination IP addres isn't on the local network, we use the default router's IP address instead. If not ARP table entry is found, we overwrite the original IP packet with an ARP request for the IP address. */ /* First check if destination is a local broadcast. */ if(((const uint8_t *)IPBUF->destipaddr)[0] >= 224 && ((const uint8_t *)IPBUF->destipaddr)[0] <= 239) { /* packet is addressed to multicast ip range, generate the associated mac address for it. */ IPBUF->ethhdr.dest.addr[0] = 0x01; IPBUF->ethhdr.dest.addr[1] = 0x00; IPBUF->ethhdr.dest.addr[2] = 0x5e; IPBUF->ethhdr.dest.addr[3] = ((const uint8_t *)IPBUF->destipaddr)[1] & 0x7f; IPBUF->ethhdr.dest.addr[4] = ((const uint8_t *)IPBUF->destipaddr)[2]; IPBUF->ethhdr.dest.addr[5] = ((const uint8_t *)IPBUF->destipaddr)[3]; } else if((IPBUF->destipaddr[0] == (uip_hostaddr[0] | ~uip_netmask[0]) && IPBUF->destipaddr[1] == (uip_hostaddr[1] | ~uip_netmask[1])) || (uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr))) { memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); #ifdef MDNS_SD_SUPPORT /* If the ip is the mdns mulicast ip, we answer to the mac who asked */ } else if (uip_ipaddr_cmp(IPBUF->destipaddr, mdns_address)) { memcpy(IPBUF->ethhdr.dest.addr, &((struct uip_eth_hdr *) uip_buf)->dest, 6); #endif } else { /* Check if the destination address is on the local network. */ if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { /* Destination address was not on the local network, so we need to use the default router's IP address instead of the destination address when determining the MAC address. */ uip_ipaddr_copy(ipaddr, uip_draddr); } else { /* Else, we use the destination IP address. */ uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); } struct arp_entry *tabptr = uip_arp_lookup (ipaddr); if(!tabptr) { /* The destination address was not in our ARP table, so we overwrite the IP packet with an ARP request. */ memset(BUF->ethhdr.dest.addr, 0xff, 6); memset(BUF->dhwaddr.addr, 0x00, 6); memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); uip_ipaddr_copy(BUF->dipaddr, ipaddr); uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ BUF->hwtype = HTONS(ARP_HWTYPE_ETH); BUF->protocol = HTONS(UIP_ETHTYPE_IP); BUF->hwlen = 6; BUF->protolen = 4; BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); /* FIXME uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; */ uip_len = sizeof(struct arp_hdr); return 1; } /* Build an ethernet header. */ memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); } memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); uip_len += sizeof(struct uip_eth_hdr); return 0; }
/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) { rpl_dag_t *dag; rpl_instance_t *instance; uint8_t version; int i; #if CETIC_6LBR version = nvm_data.rpl_version_id; uint8_t new_version = version; RPL_LOLLIPOP_INCREMENT(new_version); nvm_data.rpl_version_id = new_version; store_nvm_config(); #else version = RPL_LOLLIPOP_INIT; #endif instance = rpl_get_instance(instance_id); if(instance != NULL) { for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) { dag = &instance->dag_table[i]; if(dag->used) { if(uip_ipaddr_cmp(&dag->dag_id, dag_id)) { version = dag->version; RPL_LOLLIPOP_INCREMENT(version); #if CETIC_6LBR nvm_data.rpl_version_id = version; store_nvm_config(); #endif } if(dag == dag->instance->current_dag) { PRINTF("RPL: Dropping a joined DAG when setting this node as root"); dag->instance->current_dag = NULL; } else { PRINTF("RPL: Dropping a DAG when setting this node as root"); } rpl_free_dag(dag); } } } dag = rpl_alloc_dag(instance_id, dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG\n"); return NULL; } instance = dag->instance; dag->version = version; dag->joined = 1; dag->grounded = RPL_GROUNDED; dag->preference = RPL_PREFERENCE; instance->mop = RPL_MOP_DEFAULT; instance->of = &RPL_OF; rpl_set_preferred_parent(dag, NULL); memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS; instance->dio_intmin = RPL_DIO_INTERVAL_MIN; /* The current interval must differ from the minimum interval in order to trigger a DIO timer reset. */ instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN + RPL_DIO_INTERVAL_DOUBLINGS; instance->dio_redundancy = RPL_DIO_REDUNDANCY; instance->max_rankinc = RPL_MAX_RANKINC; instance->min_hoprankinc = RPL_MIN_HOPRANKINC; instance->default_lifetime = RPL_DEFAULT_LIFETIME; instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; dag->rank = ROOT_RANK(instance); if(instance->current_dag != dag && instance->current_dag != NULL) { /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_dag); instance->current_dag->joined = 0; } instance->current_dag = dag; instance->dtsn_out = RPL_LOLLIPOP_INIT; instance->of->update_metric_container(instance); default_instance = instance; PRINTF("RPL: Node set to be a DAG root with DAG ID "); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); ANNOTATE("#A root=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_reset_dio_timer(instance); return dag; }
/*------------------------------------------------------------------------------*/ u8_t uip_fw_forward(void) { struct fwcache_entry *fw; /* First check if the packet is destined for ourselves and return 0 to indicate that the packet should be processed locally. */ if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr)) { return UIP_FW_LOCAL; } #ifdef AODV_COMPLIANCE #define udp ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) if(udp->proto == UIP_PROTO_UDP && udp->destport == UIP_HTONS(UAODV_UDPPORT)) { return UIP_FW_LOCAL; } #endif /* If we use ping IP address configuration, and our IP address is not yet configured, we should intercept all ICMP echo packets. */ #if UIP_PINGADDRCONF if(uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr) && BUF->proto == UIP_PROTO_ICMP && ICMPBUF->type == ICMP_ECHO) { return UIP_FW_LOCAL; } #endif /* UIP_PINGADDRCONF */ /* Check if the packet is in the forwarding cache already, and if so we drop it. */ for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { if(fw->timer != 0 && #if UIP_REASSEMBLY > 0 fw->len == BUF->len && fw->offset == BUF->ipoffset && #endif fw->ipid == BUF->ipid && uip_ipaddr_cmp(&fw->srcipaddr, &BUF->srcipaddr) && uip_ipaddr_cmp(&fw->destipaddr, &BUF->destipaddr) && #if notdef fw->payload[0] == BUF->srcport && fw->payload[1] == BUF->destport && #endif fw->proto == BUF->proto) { /* Drop packet. */ return UIP_FW_FORWARDED; } } /* If the TTL reaches zero we produce an ICMP time exceeded message in the uip_buf buffer and forward that packet back to the sender of the packet. */ if(BUF->ttl <= 1) { /* No time exceeded for broadcasts and multicasts! */ if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr)) { return UIP_FW_LOCAL; } time_exceeded(); } /* Decrement the TTL (time-to-live) value in the IP header */ BUF->ttl = BUF->ttl - 1; /* Update the IP checksum. */ if(BUF->ipchksum >= UIP_HTONS(0xffff - 0x0100)) { BUF->ipchksum = BUF->ipchksum + UIP_HTONS(0x0100) + 1; } else { BUF->ipchksum = BUF->ipchksum + UIP_HTONS(0x0100); } if(uip_len > 0) { uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]; uip_fw_output(); } #if UIP_BROADCAST if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr)) { return UIP_FW_LOCAL; } #endif /* UIP_BROADCAST */ /* Return non-zero to indicate that the packet was forwarded and that no other processing should be made. */ return UIP_FW_FORWARDED; }
/*---------------------------------------------------------------------------*/ static void handle_incoming_rreq(void) { struct uaodv_msg_rreq *rm = (struct uaodv_msg_rreq *)uip_appdata; uip_ipaddr_t dest_addr, orig_addr; struct uaodv_rt_entry *rt, *fw = NULL; print_debug("RREQ %d.%d.%d.%d -> %d.%d.%d.%d ttl=%u" " orig=%d.%d.%d.%d seq=%lu hops=%u dest=%d.%d.%d.%d seq=%lu\n", uip_ipaddr_to_quad(&BUF->srcipaddr), uip_ipaddr_to_quad(&BUF->destipaddr), BUF->ttl, uip_ipaddr_to_quad(&rm->orig_addr), uip_ntohl(rm->orig_seqno), rm->hop_count, uip_ipaddr_to_quad(&rm->dest_addr), uip_ntohl(rm->dest_seqno)); if(uip_ipaddr_cmp(&rm->orig_addr, &uip_hostaddr)) { return; /* RREQ looped back! */ } #ifdef CC2420_RADIO { int ret = cc2420_check_remote(uip_udp_sender()->u16[1]); if(ret == REMOTE_YES) { print_debug("RREQ drop is remote\n"); return; } else if (ret == REMOTE_NO) { /* Is neigbour, accept it. */ } else if(cc2420_last_rssi < RSSI_THRESHOLD) { print_debug("RREQ drop %d %d\n", cc2420_last_rssi, cc2420_last_correlation); return; } } #endif #ifdef AODV_BAD_HOP_EXTENSION if(uip_len > (sizeof(*rm) + 2)) { struct uaodv_bad_hop_ext *ext = (void *)(uip_appdata + sizeof(*rm)); uint8_t *end = uip_appdata + uip_len; for(; (uint8_t *)ext < end; ext = (void *)((uint8_t *)ext + ext->length + 2)) { uint8_t *eend = (uint8_t *)ext + ext->length; if(eend > end) eend = end; if(ext->type == RREQ_BAD_HOP_EXT) { uip_ipaddr_t *a; for(a = ext->addrs; (uint8_t *)a < eend; a++) { if(uip_ipaddr_cmp(a, &uip_hostaddr)) { print_debug("BAD_HOP drop\n"); return; } } } } } #endif /* AODV_BAD_HOP_EXTENSION */ /* New reverse route? */ rt = uaodv_rt_lookup(&rm->orig_addr); if(rt == NULL || (SCMP32(uip_ntohl(rm->orig_seqno), rt->hseqno) > 0) /* New route. */ || (SCMP32(uip_ntohl(rm->orig_seqno), rt->hseqno) == 0 && rm->hop_count < rt->hop_count)) { /* Better route. */ print_debug("Inserting1\n"); rt = uaodv_rt_add(&rm->orig_addr, uip_udp_sender(), rm->hop_count, &rm->orig_seqno); } /* Check if it is for our address or a fresh route. */ if(uip_ipaddr_cmp(&rm->dest_addr, &uip_hostaddr) || rm->flags & UAODV_RREQ_DESTONLY) { fw = NULL; } else { fw = uaodv_rt_lookup(&rm->dest_addr); if(!(rm->flags & UAODV_RREQ_UNKSEQNO) && fw != NULL && SCMP32(fw->hseqno, uip_ntohl(rm->dest_seqno)) <= 0) { fw = NULL; } } if (fw != NULL) { uint32_t net_seqno; print_debug("RREQ for known route\n"); uip_ipaddr_copy(&dest_addr, &rm->dest_addr); uip_ipaddr_copy(&orig_addr, &rm->orig_addr); net_seqno = uip_htonl(fw->hseqno); send_rrep(&dest_addr, &rt->nexthop, &orig_addr, &net_seqno, fw->hop_count + 1); } else if(uip_ipaddr_cmp(&rm->dest_addr, &uip_hostaddr)) { uint32_t net_seqno; print_debug("RREQ for our address\n"); uip_ipaddr_copy(&dest_addr, &rm->dest_addr); uip_ipaddr_copy(&orig_addr, &rm->orig_addr); my_hseqno++; if(!(rm->flags & UAODV_RREQ_UNKSEQNO) && SCMP32(my_hseqno, uip_ntohl(rm->dest_seqno)) < 0) { print_debug("New my_hseqno %lu\n", my_hseqno); /* We have rebooted. */ my_hseqno = uip_ntohl(rm->dest_seqno) + 1; } net_seqno = uip_htonl(my_hseqno); send_rrep(&dest_addr, &rt->nexthop, &orig_addr, &net_seqno, 0); } else if(BUF->ttl > 1) { int len; /* Have we seen this RREQ before? */ if(fwc_lookup(&rm->orig_addr, &rm->rreq_id)) { print_debug("RREQ cached, not fwd\n"); return; } fwc_add(&rm->orig_addr, &rm->rreq_id); print_debug("RREQ fwd\n"); rm->hop_count++; bcastconn->ttl = BUF->ttl - 1; len = sizeof(struct uaodv_msg_rreq); len += add_rreq_extensions(rm + 1); uip_udp_packet_send(bcastconn, rm, len); } }
/** * @brief * @note * @param * @retval */ bool UIPDebug::uip_debug_printcon(struct uip_conn* lhs, struct uip_conn* rhs) { bool changed = false; if(!uip_ipaddr_cmp(lhs->ripaddr, rhs->ripaddr)) { pc.printf(" ripaddr: "); uip_debug_printbytes((const uint8_t*)lhs->ripaddr, 4); pc.printf(" -> "); uip_debug_printbytes((const uint8_t*)rhs->ripaddr, 4); pc.printf("\n"); uip_ipaddr_copy(lhs->ripaddr, rhs->ripaddr); changed = true; } if(lhs->lport != rhs->lport) { pc.printf(" lport: "); pc.printf("%d", htons(lhs->lport)); pc.printf(" -> "); pc.printf("%d\n", htons(rhs->lport)); lhs->lport = rhs->lport; changed = true; } if(lhs->rport != rhs->rport) { pc.printf(" rport: "); pc.printf("%d", htons(lhs->rport)); pc.printf(" -> "); pc.printf("%d\n", htons(rhs->rport)); lhs->rport = rhs->rport; changed = true; } if((uint32_t) lhs->rcv_nxt[0] != (uint32_t) rhs->rcv_nxt[0]) { pc.printf(" rcv_nxt: "); uip_debug_printbytes(lhs->rcv_nxt, 4); pc.printf(" -> "); uip_debug_printbytes(rhs->rcv_nxt, 4); *((uint32_t*) &lhs->rcv_nxt[0]) = (uint32_t) rhs->rcv_nxt[0]; pc.printf("\n"); changed = true; } if((uint32_t) lhs->snd_nxt[0] != (uint32_t) rhs->snd_nxt[0]) { pc.printf(" snd_nxt: "); uip_debug_printbytes(lhs->snd_nxt, 4); pc.printf(" -> "); uip_debug_printbytes(rhs->snd_nxt, 4); *((uint32_t*) &lhs->snd_nxt[0]) = (uint32_t) rhs->snd_nxt[0]; pc.printf("\n"); changed = true; } if(lhs->len != rhs->len) { pc.printf(" len: "); pc.printf("%d", lhs->len); pc.printf(" -> "); pc.printf("%d\n", rhs->len); lhs->len = rhs->len; changed = true; } if(lhs->mss != rhs->mss) { pc.printf(" mss: "); pc.printf("%d", lhs->mss); pc.printf(" -> "); pc.printf("%d\n", rhs->mss); lhs->mss = rhs->mss; changed = true; } if(lhs->initialmss != rhs->initialmss) { pc.printf(" initialmss: "); pc.printf("%d", lhs->initialmss); pc.printf(" -> "); pc.printf("%d\n", rhs->initialmss); lhs->initialmss = rhs->initialmss; changed = true; } if(lhs->sa != rhs->sa) { pc.printf(" sa: "); pc.printf("%d", lhs->sa); pc.printf(" -> "); pc.printf("%d", rhs->sa); lhs->sa = rhs->sa; changed = true; } if(lhs->sv != rhs->sv) { pc.printf(" sv: "); pc.printf("%d", lhs->sv); pc.printf(" -> "); pc.printf("%d\n", rhs->sv); lhs->sv = rhs->sv; changed = true; } if(lhs->rto != rhs->rto) { pc.printf(" rto: "); pc.printf("%d", lhs->rto); pc.printf(" -> "); pc.printf("%d\n", rhs->rto); lhs->rto = rhs->rto; changed = true; } if(lhs->tcpstateflags != rhs->tcpstateflags) { pc.printf(" tcpstateflags: "); pc.printf("%d", lhs->tcpstateflags); pc.printf(" -> "); pc.printf("%d\n", rhs->tcpstateflags); lhs->tcpstateflags = rhs->tcpstateflags; changed = true; } if(lhs->timer != rhs->timer) { pc.printf(" timer: "); pc.printf("%d", lhs->timer); pc.printf(" -> "); pc.printf("%d\n", rhs->timer); lhs->timer = rhs->timer; changed = true; } if(lhs->nrtx != rhs->nrtx) { pc.printf(" nrtx: "); pc.printf("%d", lhs->nrtx); pc.printf(" -> "); pc.printf("%d\n", rhs->nrtx); lhs->nrtx = rhs->nrtx; changed = true; } return changed; }
static CC_INLINE int fwc_lookup(const uip_ipaddr_t *orig, const uint32_t *id) { unsigned n = (orig->u8[2] + orig->u8[3]) % NFWCACHE; return fwcache[n].id == *id && uip_ipaddr_cmp(&fwcache[n].orig, orig); }
/*---------------------------------------------------------------------------*/ void uip_ds6_route_rm(uip_ds6_route_t *route) { struct uip_ds6_route_neighbor_route *neighbor_route; #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ if(route != NULL && route->neighbor_routes != NULL) { PRINTF("uip_ds6_route_rm: removing route: "); PRINT6ADDR(&route->ipaddr); PRINTF("\n"); /* Remove the neighbor from the route list */ list_remove(routelist, route); /* Find the corresponding neighbor_route and remove it. */ for(neighbor_route = list_head(route->neighbor_routes->route_list); neighbor_route != NULL && neighbor_route->route != route; neighbor_route = list_item_next(neighbor_route)); if(neighbor_route == NULL) { PRINTF("uip_ds6_route_rm: neighbor_route was NULL for "); uip_debug_ipaddr_print(&route->ipaddr); PRINTF("\n"); } list_remove(route->neighbor_routes->route_list, neighbor_route); if(list_head(route->neighbor_routes->route_list) == NULL) { /* If this was the only route using this neighbor, remove the neibhor from the table */ PRINTF("uip_ds6_route_rm: removing neighbor too\n"); nbr_table_remove(nbr_routes, route->neighbor_routes->route_list); } memb_free(&routememb, route); memb_free(&neighborroutememb, neighbor_route); num_routes--; PRINTF("uip_ds6_route_rm num %d\n", num_routes); #if UIP_DS6_NOTIFICATIONS call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM, &route->ipaddr, uip_ds6_route_nexthop(route)); #endif #if 0 //(DEBUG & DEBUG_ANNOTATE) == DEBUG_ANNOTATE /* we need to check if this was the last route towards "nexthop" */ /* if so - remove that link (annotation) */ uip_ds6_route_t *r; for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) { uip_ipaddr_t *nextr, *nextroute; nextr = uip_ds6_route_nexthop(r); nextroute = uip_ds6_route_nexthop(route); if(nextr != NULL && nextroute != NULL && uip_ipaddr_cmp(nextr, nextroute)) { /* we found another link using the specific nexthop, so keep the #L */ return; } } ANNOTATE("#L %u 0\n", uip_ds6_route_nexthop(route)->u8[sizeof(uip_ipaddr_t) - 1]); #endif } #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ return; }
/*-----------------------------------------------------------------------------------*/ static void uip_arp_update(uip_ipaddr_t *ipaddr, struct uip_eth_addr *ethaddr) { register struct arp_entry *tabptr = arp_table; /* Walk through the ARP mapping table and try to find an entry to update. If none is found, the IP -> MAC address mapping is inserted in the ARP table. */ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { tabptr = &arp_table[i]; /* Only check those entries that are actually in use. */ if(!uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) { /* Check if the source IP address of the incoming packet matches the IP address in this ARP table entry. */ if(uip_ipaddr_cmp(ipaddr, &tabptr->ipaddr)) { /* An old entry found, update this and return. */ memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); tabptr->time = arptime; return; } } tabptr++; } /* If we get here, no existing ARP table entry was found, so we create one. */ /* First, we try to find an unused entry in the ARP table. */ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { tabptr = &arp_table[i]; if(uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) { break; } } /* If no unused entry is found, we try to find the oldest entry and throw it away. */ if(i == UIP_ARPTAB_SIZE) { tmpage = 0; c = 0; for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { tabptr = &arp_table[i]; if(arptime - tabptr->time > tmpage) { tmpage = arptime - tabptr->time; c = i; } } i = c; tabptr = &arp_table[i]; } /* Now, i is the ARP table entry which we will fill with the new information. */ uip_ipaddr_copy(&tabptr->ipaddr, ipaddr); memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); tabptr->time = arptime; }
/*-----------------------------------------------------------------------------------*/ void uip_arp_out(struct net_buf *buf) { struct arp_entry *tabptr = arp_table; /* Find the destination IP address in the ARP table and construct the Ethernet header. If the destination IP addres isn't on the local network, we use the default router's IP address instead. If not ARP table entry is found, we overwrite the original IP packet with an ARP request for the IP address. */ /* First check if destination is a local broadcast. */ if(uip_ipaddr_cmp(&IPBUF(buf)->destipaddr, &uip_broadcast_addr)) { memcpy(IPBUF(buf)->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); } else if(IPBUF(buf)->destipaddr.u8[0] == 224) { /* Multicast. */ IPBUF(buf)->ethhdr.dest.addr[0] = 0x01; IPBUF(buf)->ethhdr.dest.addr[1] = 0x00; IPBUF(buf)->ethhdr.dest.addr[2] = 0x5e; IPBUF(buf)->ethhdr.dest.addr[3] = IPBUF(buf)->destipaddr.u8[1]; IPBUF(buf)->ethhdr.dest.addr[4] = IPBUF(buf)->destipaddr.u8[2]; IPBUF(buf)->ethhdr.dest.addr[5] = IPBUF(buf)->destipaddr.u8[3]; } else { /* Check if the destination address is on the local network. */ if(!uip_ipaddr_maskcmp(&IPBUF(buf)->destipaddr, &uip_hostaddr, &uip_netmask)) { /* Destination address was not on the local network, so we need to use the default router's IP address instead of the destination address when determining the MAC address. */ uip_ipaddr_copy(&ipaddr, &uip_draddr); } else { /* Else, we use the destination IP address. */ uip_ipaddr_copy(&ipaddr, &IPBUF(buf)->destipaddr); } for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { if(uip_ipaddr_cmp(&ipaddr, &tabptr->ipaddr)) { break; } tabptr++; } if(i == UIP_ARPTAB_SIZE) { /* The destination address was not in our ARP table, so we overwrite the IP packet with an ARP request. */ memset(BUF(buf)->ethhdr.dest.addr, 0xff, 6); memset(BUF(buf)->dhwaddr.addr, 0x00, 6); memcpy(BUF(buf)->ethhdr.src.addr, uip_lladdr.addr, 6); memcpy(BUF(buf)->shwaddr.addr, uip_lladdr.addr, 6); uip_ipaddr_copy(&BUF(buf)->dipaddr, &ipaddr); uip_ipaddr_copy(&BUF(buf)->sipaddr, &uip_hostaddr); BUF(buf)->opcode = UIP_HTONS(ARP_REQUEST); /* ARP request. */ BUF(buf)->hwtype = UIP_HTONS(ARP_HWTYPE_ETH); BUF(buf)->protocol = UIP_HTONS(UIP_ETHTYPE_IP); BUF(buf)->hwlen = 6; BUF(buf)->protolen = 4; BUF(buf)->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_ARP); uip_appdata(buf) = &uip_buf(buf)[UIP_TCPIP_HLEN + UIP_LLH_LEN]; uip_len(buf) = sizeof(struct arp_hdr); return; } /* Build an ethernet header. */ memcpy(IPBUF(buf)->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); } memcpy(IPBUF(buf)->ethhdr.src.addr, uip_lladdr.addr, 6); IPBUF(buf)->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_IP); uip_len(buf) += sizeof(struct uip_eth_hdr); }