+#ifdef CENTRALIZED_ROUTING
+ cmpr_ip6_addr_t nextHop_Flow(struct f_entry *fEntry) {
+ if (IS_VALID_ENTRY(*fEntry)) {
+ if (IS_HOP_TYPE(*fEntry)) return fEntry->nextHop;
+ return fEntry->pathE->path[0];
+ }
+ return T_INVAL_NEIGH;
+ }
+
+ struct flow_path *getNewFlowPath() {
+ uint8_t i;
+ for (i = 0; i < N_FULL_PATH_ENTRIES; i++) {
+ if (full_path_entries[i].path_len == 0)
+ return &(full_path_entries[i]);
+ }
+ return NULL;
+ }
+
+ error_t freeFullPath(struct flow_path* path) {
+ path->path_len = 0;
+ return SUCCESS;
+ }
+
+ void reverseFlowMatch(struct rinstall_header *orig,
+ struct flow_match *reverse,
+ struct ip6_hdr *iph) {
+
+ printfUART("reverseFlowMatch: %i %i\n", ntohs(iph->ip6_dst.s6_addr16[7]),
+ ntohs(iph->ip6_src.s6_addr16[7]));
+
+ if (orig->match.src == htons(T_INVAL_NEIGH))
+ reverse->src = htons(T_INVAL_NEIGH);
+ else
+ reverse->src = iph->ip6_src.s6_addr16[7];
+
+ if (orig->match.dest == htons(T_INVAL_NEIGH)) // Shouldn't happen
+ reverse->dest = htons(T_INVAL_NEIGH);
+ else
+ reverse->dest = iph->ip6_dst.s6_addr16[7];
+ }
+
+ /*
+ * Function takes the set of choices within a single flow_entry slot and arranges
+ * them in order of addition/modification.
+ *
+ * @entry_index - The index of the entry that is being uninstalled, or moved to
+ * the top of the stack. (Set this to N_FLOW_CHOICES to indicate that a new
+ * entry is being installed).
+ * @install - Whether an entry is being installed or moved to the top of the stack
+ *
+ * TODO: Implement explicit flow entry removal
+ */
+ void sortFlowEntries(struct flow_entry *target, uint8_t entry_index, bool install) {
+ struct f_entry f_temp;
+ uint8_t i;
+
+ dbg("IPRouting", "sortFlowEntries: Index: 0x%x, Install: 0x%x\n", entry_index, install);
+
+ if (install && (entry_index < N_FLOW_CHOICES)) {
+ ip_memcpy(&f_temp, &(target->entries[entry_index]), sizeof(struct f_entry));
+ }
+
+ for (i = ((entry_index < N_FLOW_CHOICES)? (entry_index):(N_FLOW_CHOICES - 1)); i > 0; i--) {
+ ip_memcpy(&(target->entries[i]), &(target->entries[i-1]), sizeof(struct f_entry));
+ }
+
+ if (install && (entry_index < N_FLOW_CHOICES))
+ ip_memcpy(&(target->entries[0]), &f_temp, sizeof(struct f_entry));
+ else
+ ip_memclr((uint8_t *)(&(target->entries[0])), sizeof(struct f_entry));
+ }
+
+ void updateFlowCounts(struct flow_entry *target) {
+ uint8_t i;
+ if (target == NULL) return;
+ dbg("IPRouting", "updateFlowCounts\n");
+
+ // Just used or installed something
+ if (IS_VALID_SLOT(target)) {
+ for(i = 0; i < N_FLOW_ENT; i++) {
+ if (!(IS_VALID_SLOT(&(flow_table[i])))) continue;
+ if (flow_table[i].count < target->count) flow_table[i].count++;
+ }
+ target->count = 0;
+ } else {
+ for (i = 0; i < N_FLOW_ENT; i++) {
+ if (!(IS_VALID_SLOT(&(flow_table[i])))) continue;
+ if (flow_table[i].count > target->count) flow_table[i].count--;
+ }
+ target->count = N_FLOW_ENT;
+ }
+ }
+
+ // Helper Functions
+ error_t installEntry(struct ip6_hdr *iph, struct rinstall_header *rih, struct ip6_route *route) {
+ struct flow_entry *entry;
+ struct flow_match reverse_match;
+ uint16_t current, path_len,
+ reverse = 0,
+ fullPath = (rih->flags & HYDRO_INSTALL_METHOD_MASK) == HYDRO_METHOD_SOURCE;
+ cmpr_ip6_addr_t *path;
+ uint8_t i;
+
+ // if this is a METHOD_SOURCE install, and the path is carried in
+ // the routing header we must be on the far end of the install,
+ // and so need to reverse everything.
+
+
+ if (fullPath && rih->path_len == 0) reverse = 1;
+ if (!fullPath) {
+ printfUART("not fp, route: %p rip: %i\n", route, rih->path_len);
+ reverse = rih->flags & HYDRO_INSTALL_REVERSE;
+ if (!reverse && route && route->segs_remain == 0 && rih->path_len == 0) return SUCCESS;
+ if (reverse && rih->path_len > 0) return SUCCESS;
+ }
+
+ printfUART("install rev: %i fp: %i\n", reverse, fullPath)
+
+ if (rih->path_len == 0) {
+ if (route == NULL) return FAIL;
+ current = ROUTE_NENTRIES(route) - route->segs_remain;
+ path = route->hops;
+ path_len = ROUTE_NENTRIES(route);
+ } else {
+ current = reverse ? rih->path_len - 1 : 0;
+ path = rih->path;
+ path_len = rih->path_len;
+ }
+
+ dbg("Install", "installEntry: flags: 0x%x\n", rih->flags);
+
+ if (!reverse &&
+ ((entry = getFlowEntry_Match(&(rih->match))) == NULL) &&
+ ((entry = getNewEntry(&(rih->match))) == NULL)) {
+ dbg("Install", "installEntry: forward path has no match and no room in flow table\n");
+ return FAIL;
+ } else if (reverse) {
+ reverseFlowMatch(rih, &reverse_match, iph);
+ if (((entry = getFlowEntry_Match(&(reverse_match))) == NULL) &&
+ ((entry = getNewEntry(&(reverse_match))) == NULL)) {
+ dbg("Install", "installEntry: reverse path has no match and no room in flow table\n");
+ return FAIL;
+ }
+ }
+
+ //Inefficient duplicate detection
+ for (i = 0; i < N_FLOW_CHOICES; i++) {
+ printfUART("checking dup %i %i\n", nextHop_Flow(&entry->entries[i]),
+ ntohs(path[reverse ? (current - 1) : current]));
+ if (IS_VALID_ENTRY(entry->entries[i]) &&
+ (nextHop_Flow(&entry->entries[i]) ==
+ ntohs(path[reverse ? (current - 1) : current])) &&
+ !fullPath) {
+ dbg("Install", "This choice already exists in flow table!\n");
+ // Since order indicates order of arrival, need to move this one up higher
+ if (i != 0) {
+ sortFlowEntries(entry, i, TRUE);
+ }
+ return SUCCESS;
+ }
+ if (IS_VALID_ENTRY(entry->entries[i]) && IS_FULL_TYPE(entry->entries[i])) {
+ dbg("Install", "Removing exiting source choice\n");
+ entry->entries[0].pathE->path_len = 0;
+ SET_INVALID_ENTRY(entry->entries[0]);
+ }
+ }
+
+
+ if (IS_VALID_ENTRY(entry->entries[0]))
+ sortFlowEntries(entry, N_FLOW_CHOICES, TRUE);
+ if (fullPath) {
+ if ((entry->entries[0].pathE = getNewFlowPath()) == NULL) {
+ dbg("Install", "No room available for new full path entry\n");
+ return FAIL;
+ }
+ for (i = 0; i < path_len; i++) {
+ entry->entries[0].pathE->path[i] = ntohs(path[(reverse ? (path_len - i - 1): i)]);
+ dbg("Install", "Put node 0x%x as hop [%u]\n", entry->entries[0].pathE->path[i], (i));
+ }
+ entry->entries[0].pathE->path_len = path_len;
+ } else {
+ entry->entries[0].nextHop = ntohs(path[(reverse? (current - 1) : current)]);
+ dbg("Install", "Put node 0x%x as next hop\n", entry->entries[0].nextHop);
+ }
+ SET_VALID_ENTRY((entry->entries[0]));
+ SET_VALID_SLOT(entry);
+ (fullPath? (SET_FULL_TYPE(entry->entries[0])) : (SET_HOP_TYPE(entry->entries[0])));
+
+ updateFlowCounts(entry);
+ printTable();
+ return SUCCESS;
+ }
+
+ error_t uninstallEntry(struct rinstall_header *rih) {
+ struct flow_entry *entry;
+ //struct neigh_entry *neigh;
+ uint8_t i;
+
+ // don't support reverse install
+ if (rih->flags & HYDRO_INSTALL_REVERSE) return FAIL;
+ // only work for source installs
+ if ((rih->flags & HYDRO_INSTALL_METHOD_MASK) != HYDRO_METHOD_SOURCE) return FAIL;
+ if ((entry = getFlowEntry_Match(&(rih->match))) == NULL)
+ return FAIL;
+
+ for (i = 0; i < N_FLOW_CHOICES; i++) {
+ if (IS_VALID_ENTRY(entry->entries[i])) {
+ SET_INVALID_ENTRY(entry->entries[i]);
+ SET_INVALID_SLOT(entry);
+ freeFullPath(entry->entries[i].pathE);
+ }
+ }
+ return SUCCESS;
+ }
+#endif
+
+
+ event void IPExtensions.handleExtensions(uint8_t label,
+ struct ip6_hdr *iph,
+ struct ip6_ext *hop,
+ struct ip6_ext *dst,
+ struct ip6_route *route,
+ uint8_t nxt_hdr) {
+#ifdef CENTRALIZED_ROUTING
+ struct tlv_hdr *tlv = NULL;
+ struct rinstall_header *rih;
+ uint8_t method;
+ bool forMe = call IPRouting.isForMe(iph), isHop = FALSE;
+
+ printfUART("handling extension header!\n");
+
+ if (dst != NULL) tlv = call IPExtensions.findTlv(dst, TLV_TYPE_INSTALL);
+ if (tlv == NULL && hop != NULL) { tlv = call IPExtensions.findTlv(hop, TLV_TYPE_INSTALL); isHop = TRUE; }
+ if (tlv == NULL) return;
+ rih = (struct rinstall_header *)(tlv + 1);
+ // first, install the entry if it's for me
+ method = (rih->flags & HYDRO_INSTALL_METHOD_MASK);
+
+
+ if (!forMe) {
+ if (method == HYDRO_METHOD_HOP && !isHop) return;
+ if (method == HYDRO_METHOD_SOURCE) return;
+ }
+ if (!(rih->flags & HYDRO_INSTALL_UNINSTALL_MASK)) {
+ installEntry(iph, rih, route);
+ } else {
+ // uninstall only returns
+ uninstallEntry(rih);
+ return;
+ }
+
+ if (method == HYDRO_METHOD_HOP && (rih->flags & HYDRO_INSTALL_REVERSE)) {
+ // a little clunky, perhaps, but this is sort of how
+ // installEntry expects things to work.
+ rih->flags &= ~HYDRO_INSTALL_REVERSE;
+ installEntry(iph, rih, route);
+ rih->flags |= HYDRO_INSTALL_REVERSE;
+ }