/*------------------------------------------------------------------------ * udp_send - send a UDP packet *------------------------------------------------------------------------ */ status udp_send ( uint32 remip, /* remote IP address or IP_BCAST*/ /* for a local broadcast */ uint16 remport, /* remote UDP protocol port */ uint32 locip, /* local IP address */ uint16 locport, /* local UDP protocol port */ char *buff, /* buffer of UDP data */ int32 len /* length of data in buffer */ ) { struct eth_packet pkt; /* ptr to packet being read */ struct ipv4_packet *ippkt = (struct ipv4_packet *)(pkt.net_ethdata); struct udp_packet *udppkt = (struct udp_packet *)(ippkt->net_ipdata); int32 pktlen; /* total packet length */ static uint16 ident = 1; /* datagram IDENT field */ char *udataptr; /* pointer to UDP data */ byte ethbcast[] = {0xff,0xff,0xff,0xff,0xff,0xff}; /* Compute packet length as UDP data size + fixed header size */ pktlen = ((char *)(udppkt->net_udpdata) - (char *)&pkt) + len; /* Create UDP packet in pkt */ memcpy(pkt.net_ethsrc, NetData.ethaddr, ETH_ADDR_LEN); pkt.net_ethtype = 0x0800; /* Type is IP */ ippkt->net_ipvh = 0x45; /* IP version and hdr length */ ippkt->net_iptos = 0x00; /* Type of service */ ippkt->net_iplen= pktlen - ETH_HDR_LEN;/* total IP datagram length */ ippkt->net_ipid = ident++; /* datagram gets next IDENT */ ippkt->net_ipfrag = 0x0000; /* IP flags & fragment offset */ ippkt->net_ipttl = 0xff; /* IP time-to-live */ ippkt->net_ipproto = IP_UDP; /* datagram carries UDP */ ippkt->net_ipcksum = 0x0000; /* initial checksum */ ippkt->net_ipsrc = locip; /* IP source address */ ippkt->net_ipdst = remip; /* IP destination address */ udppkt->net_udpsport = locport; /* local UDP protocol port */ udppkt->net_udpdport = remport; /* remote UDP protocol port */ udppkt->net_udplen = (uint16)(UDP_HDR_LEN+len); /* UDP length */ udppkt->net_udpcksum = 0x0000; /* ignore UDP checksum */ udataptr = (char *) udppkt->net_udpdata; for (; len>0; len--) { *udataptr++ = *buff++; } /* Set MAC address in packet, using ARP if needed */ //kprintf("Udp_send called with ip : %x\r\n", remip); if (remip == IP_BCAST) { /* set mac address to b-cast */ memcpy(pkt.net_ethdst, ethbcast, ETH_ADDR_LEN); /* If destination isn't on the same subnet, send to router */ } else if ((locip & NetData.addrmask) != (remip & NetData.addrmask)) { //kprintf("localip [%08x] NetData.addrmask [%08x] remote ip [%08x] 12 [%08x] 23 [%08x]\r\n", //locip, NetData.addrmask, remip, locip&NetData.addrmask, remip & NetData.addrmask); if (arp_resolve(NetData.routeraddr, pkt.net_ethdst)!=OK) { kprintf("udp_send: cannot resolve router %08x\n\r", NetData.routeraddr); return SYSERR; } } else { /* Destination is on local subnet - get MAC address */ //kprintf("UDP_Send trying to resolve address : %x\r\n", remip); if (arp_resolve(remip, pkt.net_ethdst) != OK) { kprintf("udp_send: cannot resolve %08x\n\r",remip); return SYSERR; } } /* Convert IP and UDP header fields from net to host byte order */ udp_hton(udppkt); ip_hton(ippkt); eth_hton(&pkt); //kprintf("Cleared conversion of header fields\r\n"); /* Compute IP header checksum */ ippkt->net_ipcksum = 0xffff & ipcksum(ippkt); //kprintf("Writing to ethernet device\r\n"); write(ETHER0, (char *)&pkt, pktlen); return OK; }
/*------------------------------------------------------------------------ * arp_resolve - Use ARP to resolve an IP address to an Ethernet address *------------------------------------------------------------------------ */ status arp_resolve ( uint32 nxthop, /* Next-hop address to resolve */ byte mac[ETH_ADDR_LEN] /* Array into which Ethernet */ ) /* address should be placed */ { intmask mask; /* Saved interrupt mask */ struct arppacket apkt; /* Local packet buffer */ int32 i; /* Index into arpcache */ int32 slot; /* ARP table slot to use */ struct arpentry *arptr; /* Ptr to ARP cache entry */ int32 msg; /* Message returned by recvtime */ /* Use MAC broadcast address for IP limited broadcast */ if (nxthop == IP_BCAST) { memcpy(mac, NetData.ethbcast, ETH_ADDR_LEN); return OK; } /* Use MAC broadcast address for IP network broadcast */ if (nxthop == NetData.ipbcast) { memcpy(mac, NetData.ethbcast, ETH_ADDR_LEN); return OK; } /* Ensure only one process uses ARP at a time */ mask = disable(); /* See if next hop address is already present in ARP cache */ for (i=0; i<ARP_SIZ; i++) { arptr = &arpcache[i]; if (arptr->arstate == AR_FREE) { continue; } if (arptr->arpaddr == nxthop) { /* Adddress is in cache */ break; } } if (i < ARP_SIZ) { /* Entry was found */ /* If entry is resolved - handle and return */ if (arptr->arstate == AR_RESOLVED) { memcpy(mac, arptr->arhaddr, ARP_HALEN); restore(mask); return OK; } /* Entry is already pending - return error because */ /* only one process can be waiting at a time */ if (arptr->arstate == AR_PENDING) { restore(mask); return SYSERR; } } /* IP address not in cache - allocate a new cache entry and */ /* send an ARP request to obtain the answer */ slot = arp_alloc(); if (slot == SYSERR) { restore(mask); return SYSERR; } arptr = &arpcache[slot]; arptr->arstate = AR_PENDING; arptr->arpaddr = nxthop; arptr->arpid = currpid; /* Hand-craft an ARP Request packet */ memcpy(apkt.arp_ethdst, NetData.ethbcast, ETH_ADDR_LEN); memcpy(apkt.arp_ethsrc, NetData.ethucast, ETH_ADDR_LEN); apkt.arp_ethtype = ETH_ARP; /* Packet type is ARP */ apkt.arp_htype = ARP_HTYPE; /* Hardware type is Ethernet */ apkt.arp_ptype = ARP_PTYPE; /* Protocol type is IP */ apkt.arp_hlen = 0xff & ARP_HALEN; /* Ethernet MAC size in bytes */ apkt.arp_plen = 0xff & ARP_PALEN; /* IP address size in bytes */ apkt.arp_op = 0xffff & ARP_OP_REQ;/* ARP type is Request */ memcpy(apkt.arp_sndha, NetData.ethucast, ARP_HALEN); apkt.arp_sndpa = NetData.ipucast; /* IP address of interface */ memset(apkt.arp_tarha, '\0', ARP_HALEN); /* Target HA is unknown*/ apkt.arp_tarpa = nxthop; /* Target protocol address */ /* Convert ARP packet from host to net byte order */ arp_hton(&apkt); /* Convert Ethernet header from host to net byte order */ eth_hton((struct netpacket *)&apkt); /* Send the packet ARP_RETRY times and await response */ msg = recvclr(); for (i=0; i<ARP_RETRY; i++) { write(ETHER0, (char *)&apkt, sizeof(struct arppacket)); msg = recvtime(ARP_TIMEOUT); if (msg == TIMEOUT) { continue; } else if (msg == SYSERR) { restore(mask); return SYSERR; } else { /* entry is resolved */ break; } } /* If no response, return TIMEOUT */ if (msg == TIMEOUT) { arptr->arstate = AR_FREE; /* Invalidate cache entry */ restore(mask); return TIMEOUT; } /* Return hardware address */ memcpy(mac, arptr->arhaddr, ARP_HALEN); restore(mask); return OK; }
status rpl_send_with_ip(char * node_phy_addr, char *src_node, byte msg_type, char *msg, uint32 msg_len, uint32 remip){ struct eth_packet pkt; struct rpl_sim_packet *rpl_sim_pkt = NULL; byte ethbcast[] = {0xff,0xff,0xff,0xff,0xff,0xff}; #ifdef DEBUG kprintf("Simulator is : %04x dest : %04x source : %04x my addr : %04x\r\n", remip, *((uint32*)node_phy_addr), *((uint32*)src_node), NetData.ipaddr); #endif if ( ! NetData.ipvalid){ getlocalip(); } if(msg_len > 1500-ETH_HDR_LEN-RPL_SIM_HDR_LEN){ kprintf("WARN : Simulator : Message too big \r\n"); return SYSERR; } memcpy(pkt.net_ethsrc, NetData.ethaddr, ETH_ADDR_LEN); /* FIXME : Needs to be changed to something that is valid */ pkt.net_ethtype = 0x1000; if (remip == IP_BCAST) { /* set mac address to b-cast */ memcpy(pkt.net_ethdst, ethbcast, ETH_ADDR_LEN); /* If destination isn't on the same subnet, send to router */ } else if ((NetData.ipaddr & NetData.addrmask) != (remip & NetData.addrmask)) { if (arp_resolve(NetData.routeraddr, pkt.net_ethdst)!=OK) { kprintf("rpl_send: cannot resolve router %08x\n\r", NetData.routeraddr); return SYSERR; } } else { /* Destination is on local subnet - get MAC address */ if (arp_resolve(remip, pkt.net_ethdst) != OK) { kprintf("rpl_send: cannot resolve %08x\n\r",remip); return SYSERR; } } rpl_sim_pkt = (struct rpl_sim_packet *)pkt.net_ethdata; memcpy((char *)rpl_sim_pkt->dest_node, (char *)node_phy_addr, RPL_NODE_PHY_ADDR_LEN); /* * FIXME Change this to my_phsical_address which is 64 bits */ memcpy((char *)rpl_sim_pkt->src_node, (char *)(src_node), RPL_NODE_PHY_ADDR_LEN); rpl_sim_pkt->msg_type = msg_type; rpl_sim_pkt->msg_len = msg_len; memcpy(rpl_sim_pkt->data, msg, msg_len); /* * FIXME : Perform host to network order translations */ #ifdef DEBUG kprintf("The packet is destined for : %06x with length : %d\r\n", *(pkt.net_ethdst+4), msg_len); #endif eth_hton(&pkt); write(ETHER0, (char *)&pkt, ETH_HDR_LEN + RPL_SIM_HDR_LEN + msg_len); return OK; }
/*------------------------------------------------------------------------ * arp_in - Handle an incoming ARP packet *------------------------------------------------------------------------ */ void arp_in ( struct arppacket *pktptr /* Ptr to incoming packet */ ) { intmask mask; /* Saved interrupt mask */ struct arppacket apkt; /* Local packet buffer */ int32 slot; /* Slot in cache */ struct arpentry *arptr; /* Ptr to ARP cache entry */ bool8 found; /* Is the sender's address in */ /* the cache? */ /* Convert packet from network order to host order */ arp_ntoh(pktptr); /* Verify ARP is for IPv4 and Ethernet */ if ( (pktptr->arp_htype != ARP_HTYPE) || (pktptr->arp_ptype != ARP_PTYPE) ) { freebuf((char *)pktptr); return; } /* Ensure only one process uses ARP at a time */ mask = disable(); /* Search cache for sender's IP address */ found = FALSE; for (slot=0; slot < ARP_SIZ; slot++) { arptr = &arpcache[slot]; /* Skip table entries that are unused */ if (arptr->arstate == AR_FREE) { continue; } /* If sender's address matches, we've found it */ if (arptr->arpaddr == pktptr->arp_sndpa) { found = TRUE; break; } } if (found) { /* Update sender's hardware address */ memcpy(arptr->arhaddr, pktptr->arp_sndha, ARP_HALEN); /* If a process was waiting, inform the process */ if (arptr->arstate == AR_PENDING) { /* Mark resolved and notify waiting process */ arptr->arstate = AR_RESOLVED; arptr->time = clktime; send(arptr->arpid, OK); } } /* For an ARP reply, processing is complete */ if (pktptr->arp_op == ARP_OP_RPLY) { freebuf((char *)pktptr); restore(mask); return; } /* The following is for an ARP request packet: if the local */ /* machine is not the target or the local IP address is not */ /* yet known, ignore the request (i.e., processing is complete)*/ if ((!NetData.ipvalid) || (pktptr->arp_tarpa != NetData.ipucast)) { freebuf((char *)pktptr); restore(mask); return; } /* Request has been sent to the local machine's address. So, */ /* add sender's info to cache, if not already present */ if (!found) { slot = arp_alloc(); if (slot == SYSERR) { /* Cache is full */ kprintf("ARP cache overflow on interface\n"); freebuf((char *)pktptr); restore(mask); return; } arptr = &arpcache[slot]; arptr->arpaddr = pktptr->arp_sndpa; memcpy(arptr->arhaddr, pktptr->arp_sndha, ARP_HALEN); arptr->arstate = AR_RESOLVED; } /* Hand-craft an ARP reply packet and send back to requester */ memcpy(apkt.arp_ethdst, pktptr->arp_sndha, ARP_HALEN); memcpy(apkt.arp_ethsrc, NetData.ethucast, ARP_HALEN); apkt.arp_ethtype= ETH_ARP; /* Frame carries ARP */ apkt.arp_htype = ARP_HTYPE; /* Hardware is Ethernet */ apkt.arp_ptype = ARP_PTYPE; /* Protocol is IP */ apkt.arp_hlen = ARP_HALEN; /* Ethernet address size*/ apkt.arp_plen = ARP_PALEN; /* IP address size */ apkt.arp_op = ARP_OP_RPLY; /* Type is Reply */ /* Insert local Ethernet and IP address in sender fields */ memcpy(apkt.arp_sndha, NetData.ethucast, ARP_HALEN); apkt.arp_sndpa = NetData.ipucast; /* Copy target Ethernet and IP addresses from request packet */ memcpy(apkt.arp_tarha, pktptr->arp_sndha, ARP_HALEN); apkt.arp_tarpa = pktptr->arp_sndpa; /* Convert ARP packet from host to network byte order */ arp_hton(&apkt); /* Convert the Ethernet header to network byte order */ eth_hton((struct netpacket *)&apkt); /* Send the reply */ write(ETHER0, (char *)&apkt, sizeof(struct arppacket)); freebuf((char *)pktptr); restore(mask); return; }