NCI2.0 Ordering of Routing Table

As per NCI 2.0 routing table shall be in the following order
All AID-based Routing Entries (if any)
All APDU Pattern-based Routing Entries (if any)
All System Code-based Routing Entries (if any)
All Protocol-based Routing Entries (if any)
All Technology-based Routing Entries (if any)

Test: compiles.
Change-Id: I997dd2ec294febd8a162426ae317aab6bfa2554f
diff --git a/src/nfa/ee/nfa_ee_act.c b/src/nfa/ee/nfa_ee_act.c
index 53f9c39..f7f62e8 100644
--- a/src/nfa/ee/nfa_ee_act.c
+++ b/src/nfa/ee/nfa_ee_act.c
@@ -52,6 +52,30 @@
 /* the following 2 tables convert the protocol mask in API and control block to
  * the command for NFCC */
 #define NFA_EE_NUM_PROTO 5
+
+static void add_route_tech_proto_tlv(uint8_t* pp, uint8_t tlv_type,
+                                     uint8_t nfcee_id, uint8_t pwr_cfg,
+                                     uint8_t tech_proto) {
+  *pp++ = tlv_type;
+  *pp++ = 3;
+  *pp++ = nfcee_id;
+  *pp++ = pwr_cfg;
+  *pp++ = tech_proto;
+}
+
+static void add_route_aid_tlv(uint8_t* pp, uint8_t* pa, uint8_t nfcee_id,
+                              uint8_t pwr_cfg) {
+  pa++;                /* EMV tag */
+  uint8_t len = *pa++; /* aid_len */
+  *pp++ = (uint8_t)NFC_ROUTE_TAG_AID;
+  *pp++ = len + 2;
+  *pp++ = nfcee_id;
+  *pp++ = pwr_cfg;
+  /* copy the AID */
+  memcpy(pp, pa, len);
+  pp += len;
+}
+
 const uint8_t nfa_ee_proto_mask_list[NFA_EE_NUM_PROTO] = {
     NFA_PROTOCOL_MASK_T1T, NFA_PROTOCOL_MASK_T2T, NFA_PROTOCOL_MASK_T3T,
     NFA_PROTOCOL_MASK_ISO_DEP, NFA_PROTOCOL_MASK_NFC_DEP};
@@ -62,6 +86,8 @@
 
 static void nfa_ee_report_discover_req_evt(void);
 static void nfa_ee_build_discover_req_evt(tNFA_EE_DISCOVER_REQ* p_evt_data);
+void nfa_ee_check_set_routing(uint16_t new_size, int* p_max_len, uint8_t* p,
+                              int* p_cur_offset);
 /*******************************************************************************
 **
 ** Function         nfa_ee_trace_aid
@@ -200,6 +226,116 @@
   return lmrt_size;
 }
 
+static void nfa_ee_add_tech_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
+                                         uint8_t* p, uint8_t* ps,
+                                         int* p_cur_offset) {
+  uint8_t num_tlv = *ps;
+
+  /* add the Technology based routing */
+  for (int xx = 0; xx < NFA_EE_NUM_TECH; xx++) {
+    uint8_t power_cfg = 0;
+    if (p_cb->tech_switch_on & nfa_ee_tech_mask_list[xx])
+      power_cfg |= NCI_ROUTE_PWR_STATE_ON;
+    if (p_cb->tech_switch_off & nfa_ee_tech_mask_list[xx])
+      power_cfg |= NCI_ROUTE_PWR_STATE_SWITCH_OFF;
+    if (p_cb->tech_battery_off & nfa_ee_tech_mask_list[xx])
+      power_cfg |= NCI_ROUTE_PWR_STATE_BATT_OFF;
+    if (power_cfg) {
+      add_route_tech_proto_tlv(pp, NFC_ROUTE_TAG_TECH, p_cb->nfcee_id,
+                               power_cfg, nfa_ee_tech_list[xx]);
+      num_tlv++;
+      if (power_cfg != NCI_ROUTE_PWR_STATE_ON)
+        nfa_ee_cb.ee_cfged |= NFA_EE_CFGED_OFF_ROUTING;
+    }
+  }
+
+  /* update the num_tlv and current offset */
+  uint8_t entry_size = (uint8_t)(pp - p);
+  *p_cur_offset += entry_size;
+  *ps = num_tlv;
+}
+
+static void nfa_ee_add_proto_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
+                                          uint8_t* p, uint8_t* ps,
+                                          int* p_cur_offset) {
+  uint8_t num_tlv = *ps;
+
+  /* add the Protocol based routing */
+  for (int xx = 0; xx < NFA_EE_NUM_PROTO; xx++) {
+    uint8_t power_cfg = 0;
+    if (p_cb->proto_switch_on & nfa_ee_proto_mask_list[xx])
+      power_cfg |= NCI_ROUTE_PWR_STATE_ON;
+    if (p_cb->proto_switch_off & nfa_ee_proto_mask_list[xx])
+      power_cfg |= NCI_ROUTE_PWR_STATE_SWITCH_OFF;
+    if (p_cb->proto_battery_off & nfa_ee_proto_mask_list[xx])
+      power_cfg |= NCI_ROUTE_PWR_STATE_BATT_OFF;
+    if (power_cfg) {
+      add_route_tech_proto_tlv(pp, NFC_ROUTE_TAG_PROTO, p_cb->nfcee_id,
+                               power_cfg, nfa_ee_proto_list[xx]);
+      num_tlv++;
+      if (power_cfg != NCI_ROUTE_PWR_STATE_ON)
+        nfa_ee_cb.ee_cfged |= NFA_EE_CFGED_OFF_ROUTING;
+    }
+  }
+
+  /* add NFC-DEP routing to HOST */
+  if (p_cb->nfcee_id == NFC_DH_ID) {
+    add_route_tech_proto_tlv(pp, NFC_ROUTE_TAG_PROTO, NFC_DH_ID,
+                             NCI_ROUTE_PWR_STATE_ON, NFC_PROTOCOL_NFC_DEP);
+
+    num_tlv++;
+    NFA_TRACE_DEBUG1(
+        "%s - NFC DEP added for "
+        "DH!!!",
+        __FUNCTION__);
+  }
+  /* update the num_tlv and current offset */
+  uint8_t entry_size = (uint8_t)(pp - p);
+  *p_cur_offset += entry_size;
+  *ps = num_tlv;
+}
+
+static void nfa_ee_add_aid_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
+                                        uint8_t* p, uint8_t* ps,
+                                        int* p_cur_offset, int* p_max_len) {
+  uint8_t num_tlv = *ps;
+
+  /* add the AID routing */
+  if (p_cb->aid_entries) {
+    int start_offset = 0;
+    for (int xx = 0; xx < p_cb->aid_entries; xx++) {
+      /* remember the beginning of this AID routing entry, just in case we
+       * need to put it in next command */
+      uint8_t* p_start = pp;
+      /* add one AID entry */
+      if (p_cb->aid_rt_info[xx] & NFA_EE_AE_ROUTE) {
+        num_tlv++;
+        uint8_t* pa = &p_cb->aid_cfg[start_offset];
+        add_route_aid_tlv(pp, pa, p_cb->nfcee_id, p_cb->aid_pwr_cfg[xx]);
+      }
+      start_offset += p_cb->aid_len[xx];
+      uint8_t new_size = (uint8_t)(pp - p_start);
+      nfa_ee_check_set_routing(new_size, p_max_len, ps, p_cur_offset);
+      if (*ps == 0) {
+        /* just sent routing command, update local */
+        *ps = 1;
+        num_tlv = *ps;
+        *p_cur_offset = new_size;
+        pp = ps + 1;
+        p = pp;
+        memcpy(p, p_start, new_size);
+        pp += new_size;
+      } else {
+        /* add the new entry */
+        *ps = num_tlv;
+        *p_cur_offset += new_size;
+      }
+    }
+  } else {
+    NFA_TRACE_DEBUG1("%s - No AID entries available", __func__);
+  }
+}
+
 /*******************************************************************************
 **
 ** Function         nfa_ee_conn_cback
@@ -1896,6 +2032,84 @@
 
   return status;
 }
+/*******************************************************************************
+**
+** Function         nfa_ee_route_add_one_ecb_order
+**
+** Description      Add the routing entries for NFCEE/DH in order defined
+**
+** Returns          NFA_STATUS_OK, if ok to continue
+**
+*******************************************************************************/
+void nfa_ee_route_add_one_ecb_by_route_order(tNFA_EE_ECB* p_cb, int rout_type,
+                                             int* p_max_len, bool more,
+                                             uint8_t* ps, int* p_cur_offset) {
+  nfa_ee_check_set_routing(p_cb->size_mask, p_max_len, ps, p_cur_offset);
+
+  /* use the first byte of the buffer (ps) to keep the num_tlv */
+  uint8_t num_tlv = *ps;
+  NFA_TRACE_DEBUG6(
+      "%s - max_len:%d, cur_offset:%d, more:%d, num_tlv:%d,rout_type:- %d",
+      __FUNCTION__, *p_max_len, *p_cur_offset, more, num_tlv, rout_type);
+  uint8_t* pp = ps + 1 + *p_cur_offset;
+  uint8_t* p = pp;
+  uint16_t tlv_size = (uint8_t)*p_cur_offset;
+
+  switch (rout_type) {
+    case NCI_ROUTE_ORDER_TECHNOLOGY: {
+      nfa_ee_add_tech_route_to_ecb(p_cb, pp, p, ps, p_cur_offset);
+    } break;
+
+    case NCI_ROUTE_ORDER_PROTOCOL: {
+      nfa_ee_add_proto_route_to_ecb(p_cb, pp, p, ps, p_cur_offset);
+    } break;
+    case NCI_ROUTE_ORDER_AID: {
+      nfa_ee_add_aid_route_to_ecb(p_cb, pp, p, ps, p_cur_offset, p_max_len);
+    } break;
+    default: {
+      NFA_TRACE_DEBUG2("%s -  Route type - NA:- %d", __FUNCTION__, rout_type);
+    }
+  }
+
+  /* update the total number of entries */
+  num_tlv = *ps;
+
+  tlv_size = nfa_ee_total_lmrt_size();
+  if (tlv_size) {
+    nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
+  }
+  if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_ROUTING) {
+    nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_CHANGED_ROUTING;
+  }
+  NFA_TRACE_DEBUG2("ee_cfg_sts:0x%02x lmrt_size:%d", nfa_ee_cb.ee_cfg_sts,
+                   tlv_size);
+
+  if (more == false) {
+    /* last entry. update routing table now */
+    if (nfa_ee_cb.ee_cfg_sts & NFA_EE_STS_CHANGED_ROUTING) {
+      if (tlv_size) {
+        nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_PREV_ROUTING;
+      } else {
+        nfa_ee_cb.ee_cfg_sts &= ~NFA_EE_STS_PREV_ROUTING;
+      }
+      NFA_TRACE_DEBUG3("%s : set routing num_tlv:%d tlv_size:%d", __FUNCTION__,
+                       num_tlv, tlv_size);
+      if (NFC_SetRouting(more, num_tlv, (uint8_t)(*p_cur_offset), ps + 1) ==
+          NFA_STATUS_OK) {
+        nfa_ee_cb.wait_rsp++;
+      }
+    } else if (nfa_ee_cb.ee_cfg_sts & NFA_EE_STS_PREV_ROUTING) {
+      if (tlv_size == 0) {
+        nfa_ee_cb.ee_cfg_sts &= ~NFA_EE_STS_PREV_ROUTING;
+        /* indicated routing is configured to NFCC */
+        nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_CHANGED_ROUTING;
+        if (NFC_SetRouting(more, 0, 0, ps + 1) == NFA_STATUS_OK) {
+          nfa_ee_cb.wait_rsp++;
+        }
+      }
+    }
+  }
+}
 
 /*******************************************************************************
 **
@@ -2020,8 +2234,9 @@
   tNFA_EE_ECB* p_cb;
   uint8_t* p = NULL;
   bool more = true;
+  bool check = true;
   uint8_t last_active = NFA_EE_INVALID;
-  int max_len, len;
+  int max_len;
   tNFA_STATUS status = NFA_STATUS_FAILED;
   int cur_offset;
   uint8_t max_tlv;
@@ -2046,11 +2261,9 @@
     }
   }
   if (last_active == NFA_EE_INVALID) {
-    more = false;
+    check = false;
   }
 
-  /* add the routing for DH first */
-  status = NFA_STATUS_OK;
   max_len = NFC_GetLmrtSize();
   max_tlv =
       (uint8_t)((max_len > NFA_EE_ROUT_MAX_TLV_SIZE) ? NFA_EE_ROUT_MAX_TLV_SIZE
@@ -2058,30 +2271,23 @@
   cur_offset = 0;
   /* use the first byte of the buffer (p) to keep the num_tlv */
   *p = 0;
-  status = nfa_ee_route_add_one_ecb(&nfa_ee_cb.ecb[NFA_EE_CB_4_DH], &max_len,
-                                    more, p, &cur_offset);
-
-  /* add only what is supported by NFCC. report overflow */
-  if (status == NFA_STATUS_OK) {
-    /* add the routing for NFCEEs */
+  for (int rt = NCI_ROUTE_ORDER_AID; rt <= NCI_ROUTE_ORDER_TECHNOLOGY; rt++) {
+    /* add the routing entries for NFCEEs */
     p_cb = &nfa_ee_cb.ecb[0];
-    for (xx = 0; (xx < nfa_ee_cb.cur_ee) && more; xx++, p_cb++) {
-      len = 0;
+    for (xx = 0; (xx < nfa_ee_cb.cur_ee) && check; xx++, p_cb++) {
       if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE) {
-        NFA_TRACE_DEBUG2("nfcee_id:0x%x, last_active: 0x%x", p_cb->nfcee_id,
-                         last_active);
-        if (last_active == p_cb->nfcee_id) more = false;
-        status = nfa_ee_route_add_one_ecb(p_cb, &max_len, more, p, &cur_offset);
-        if (status != NFA_STATUS_OK) {
-          more = false;
-        }
+        NFA_TRACE_DEBUG1("%s --add the routing for NFCEEs!!", __func__);
+        nfa_ee_route_add_one_ecb_by_route_order(p_cb, rt, &max_len, more, p,
+                                                &cur_offset);
       }
     }
+    if (rt == NCI_ROUTE_ORDER_TECHNOLOGY) more = false;
+    /* add the routing entries for DH */
+    NFA_TRACE_DEBUG1("%s --add the routing for DH!!", __func__);
+    nfa_ee_route_add_one_ecb_by_route_order(&nfa_ee_cb.ecb[NFA_EE_CB_4_DH], rt,
+                                            &max_len, more, p, &cur_offset);
   }
-  if (status != NFA_STATUS_OK) {
-    nfa_ee_report_event(NULL, NFA_EE_ROUT_ERR_EVT,
-                        (tNFA_EE_CBACK_DATA*)&status);
-  }
+
   GKI_freebuf(p);
 }
 
diff --git a/src/nfa/int/nfa_ee_int.h b/src/nfa/int/nfa_ee_int.h
index 5017195..61d4a52 100644
--- a/src/nfa/int/nfa_ee_int.h
+++ b/src/nfa/int/nfa_ee_int.h
@@ -427,6 +427,13 @@
   tNFA_EE_FLAGS ee_flags;    /* flags                            */
 } tNFA_EE_CB;
 
+/* Order of Routing entries in Routing Table */
+#define NCI_ROUTE_ORDER_AID 0x01        /* AID routing order */
+#define NCI_ROUTE_ORDER_PATTERN 0x02    /* Pattern routing order*/
+#define NCI_ROUTE_ORDER_SYS_CODE 0x03   /* System Code routing order*/
+#define NCI_ROUTE_ORDER_PROTOCOL 0x04   /* Protocol routing order*/
+#define NCI_ROUTE_ORDER_TECHNOLOGY 0x05 /* Technology routing order*/
+
 /*****************************************************************************
 **  External variables
 *****************************************************************************/