summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Kuntz <rkuntz@us.toyota-itc.com>2011-10-16 23:52:03 (GMT)
committerRomain Kuntz <rkuntz@us.toyota-itc.com>2011-10-16 23:52:03 (GMT)
commit16ff7bdeba974d15e9d9152bd0f147918804883e (patch)
tree34a9ce38307af7b3e7f4c22b22691477e274cd9a
downloadumip-pmipv6-patches-master.zip
umip-pmipv6-patches-master.tar.gz
umip-pmipv6-patches-master.tar.bz2
new repository for PMIPv6 patches for umip. Base patch created by HajimeHEADmaster
Tazaki <tazaki@sfc.wide.ad.jp>
-rw-r--r--series1
-rw-r--r--umip-pmipv6-base.patch3923
2 files changed, 3924 insertions, 0 deletions
diff --git a/series b/series
new file mode 100644
index 0000000..02a762f
--- /dev/null
+++ b/series
@@ -0,0 +1 @@
+umip-pmipv6-base.patch
diff --git a/umip-pmipv6-base.patch b/umip-pmipv6-base.patch
new file mode 100644
index 0000000..dd8e2fc
--- /dev/null
+++ b/umip-pmipv6-base.patch
@@ -0,0 +1,3923 @@
+diff --git a/README b/README
+index a8f7bb8..08727aa 100644
+--- a/README
++++ b/README
+@@ -4,7 +4,7 @@ MIPL Mobile IPv6 for Linux
+ Support in IP version 6 (RFC 3775).
+
+ It also supports Network Mobility with the NEMO Basic Support
+- implementation (RFC 3963).
++ implementation (RFC 3963) and Proxy Mobile IPv6 (RFC5213).
+
+ This user space part works together with Mobile IPv6 enabled Linux
+ kernels. See INSTALL and any other documents referred there for
+diff --git a/configure.ac b/configure.ac
+index 9e3ed90..d862b23 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -130,6 +130,17 @@ AC_CACHE_CHECK([whether to enable debug virtual terminal],
+ [ac_cv_enable_vt], [ac_cv_enable_vt=no])
+ AM_CONDITIONAL(ENABLE_VT, test x$enable_vt = xyes)
+
++dnl Option --enable-pmipv6
++AC_ARG_ENABLE(pmipv6,
++ AC_HELP_STRING([--enable-pmipv6],[enable Proxy Mobile IPv6 build]),
++ [ac_cv_enable_pmipv6=$enableval], [ac_cv_enable_pmipv6=no])
++if test x$ac_cv_enable_pmipv6 = xyes; then
++ AC_DEFINE([ENABLE_PMIPV6], [1], [Enable PMIPV6])
++fi
++AC_CACHE_CHECK([whether to enable debug virtual terminal],
++ [ac_cv_enable_vt], [ac_cv_enable_vt=no])
++AM_CONDITIONAL(ENABLE_VT, test x$enable_vt = xyes)
++
+ dnl Check Advanced IPv6 Socket API destination options header function availability
+ AC_MSG_NOTICE([*** checking inet6_opt for RFC3542: Advanced IPv6 Socket API support])
+ AC_REPLACE_FUNCS(inet6_opt_find)
+@@ -215,6 +226,7 @@ AC_PACKAGE_NAME version AC_PACKAGE_VERSION
+ Use OpenSSL crypto library: ..... $ac_cv_lib_crypto_HMAC_Init
+ Enable debugging mode: .......... $ac_cv_enable_debug
+ Enable virtual debug terminal: .. $ac_cv_enable_vt
++ Enable Proxy Mobile IPv6 build: . $ac_cv_enable_pmipv6
+
+ Build target: $host
+ CPPFLAGS: $CPPFLAGS
+diff --git a/include/netinet/ip6mh.h b/include/netinet/ip6mh.h
+index 9236e61..93e6106 100644
+--- a/include/netinet/ip6mh.h
++++ b/include/netinet/ip6mh.h
+@@ -70,6 +70,7 @@ struct ip6_mh_binding_update {
+ #define IP6_MH_BU_KEYM 0x1000 /* Key management mobility */
+ #define IP6_MH_BU_MAP 0x0800 /* HMIPv6 MAP Registration */
+ #define IP6_MH_BU_MR 0x0400 /* NEMO MR Registration */
++#define IP6_MH_BU_PREG 0x0200 /* PMIP Proxy registration */
+ #else /* BYTE_ORDER == LITTLE_ENDIAN */
+ #define IP6_MH_BU_ACK 0x0080 /* Request a binding ack */
+ #define IP6_MH_BU_HOME 0x0040 /* Home Registration */
+@@ -77,6 +78,7 @@ struct ip6_mh_binding_update {
+ #define IP6_MH_BU_KEYM 0x0010 /* Key management mobility */
+ #define IP6_MH_BU_MAP 0x0008 /* HMIPv6 MAP Registration */
+ #define IP6_MH_BU_MR 0x0004 /* NEMO MR Registration */
++#define IP6_MH_BU_PREG 0x0002 /* PMIP Proxy registration */
+ #endif
+
+ struct ip6_mh_binding_ack {
+@@ -91,6 +93,7 @@ struct ip6_mh_binding_ack {
+ /* ip6mhba_flags */
+ #define IP6_MH_BA_KEYM 0x80 /* Key management mobility */
+ #define IP6_MH_BA_MR 0x40 /* NEMO MR registration */
++#define IP6_MH_BA_PREG 0x20 /* Proxy registration */
+
+ struct ip6_mh_binding_error {
+ struct ip6_mh ip6mhbe_hdr;
+@@ -145,6 +148,54 @@ struct ip6_mh_opt_mob_net_prefix {
+ struct in6_addr ip6mnp_prefix;
+ } __attribute__ ((packed));
+
++struct ip6_mh_opt_hom_net_prefix {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ uint8_t ip6mnp_reserved;
++ uint8_t ip6mnp_prefix_len;
++ struct in6_addr ip6mnp_prefix;
++} __attribute__ ((packed)); /* PMIP Home Network Prefix */
++
++struct ip6_mh_opt_handoff_indic {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ uint8_t ip6mnp_reserved;
++ uint8_t ip6mnp_handoff_indic;
++} __attribute__ ((packed)); /* PMIP Handoff Indicator */
++
++struct ip6_mh_opt_access_tech_type {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ uint8_t ip6mnp_reserved;
++ uint8_t ip6mnp_access_tech_type;
++} __attribute__ ((packed)); /* PMIP Access technology type */
++
++struct ip6_mh_opt_timestamp {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ uint64_t ip6mnp_timestamp;
++} __attribute__ ((packed)); /* PMIP timestamp */
++
++struct ip6_mh_opt_link_layer_id {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ uint16_t ip6mnp_reserved;
++ uint8_t ip6mnp_link_layer_addr[6];
++} __attribute__ ((packed)); /* PMIP link layer address: MAC of the interface */
++
++struct ip6_mh_opt_link_local_addr {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ struct in6_addr ip6mnp_link_local_addr;
++} __attribute__ ((packed)); /* PMIP link local address of the MAG */
++
++struct ip6_mh_opt_mobile_node_id {
++ uint8_t ip6mnp_type;
++ uint8_t ip6mnp_len;
++ uint8_t ip6mnp_subtype;
++ uint8_t ip6mnp_mnid[6];
++} __attribute__ ((packed)); /* PMIP Mobile Node Identifier: MAC address */
++
+ /*
+ * Mobility Header Message Types
+ */
+@@ -168,6 +219,19 @@ struct ip6_mh_opt_mob_net_prefix {
+ #define IP6_MHOPT_BAUTH 0x05 /* Binding Auth Data */
+ #define IP6_MHOPT_MOB_NET_PRFX 0x06 /* Mobile Network Prefix */
+
++/* *** PMIP new options types *** */
++#define IP6_MHOPT_MN_ID 0x10 /* Mobile Node Identifier */
++#define IP6_MHOPT_HOM_NET_PRFX 0x26 /* Mobile Network Prefix */
++#define IP6_MHOPT_HANDOFF_INDIC 0x27 /* Mobile Node handoff indicator */
++#define IP6_MHOPT_ACCESS_TECH_TYPE 0x30 /* Access technology type */
++#define IP6_MHOPT_LINK_LAYER_ID 0x31 /* Link layer identifier */
++#define IP6_MHOPT_LINK_LOCAL_ADD 0x32 /* Link local address */
++#define IP6_MHOPT_TIMESTAMP 0x33 /* Timestamp */
++
++/* Subtype for Mobile Node Identifier option */
++#define IP6_MNID_MHOPT_SUB_NAI 0x01 /* MN ID = NAI */
++#define IP6_MNID_MHOPT_SUB_MAC 0x02 /* MN ID = MAC address (no IANA number...)*/
++
+ /*
+ * Status values accompanied with Mobility Binding Acknowledgement
+ */
+@@ -191,6 +255,20 @@ struct ip6_mh_opt_mob_net_prefix {
+ #define IP6_MH_BAS_INVAL_PRFX 141 /* Invalid Prefix */
+ #define IP6_MH_BAS_NOT_AUTH_FOR_PRFX 142 /* Not Authorized for Prefix */
+ #define IP6_MH_BAS_FWDING_FAILED 143 /* Forwarding Setup failed */
++
++/* *** PMIP status *** */
++#define IP6_MH_BAS_PROXY_REG_NOT_ENABLED 152 /* Proxy registration not enabled for the mobile node */
++#define IP6_MH_BAS_NOT_LMA_FOR_THIS_MOBILE_NODE 153 /* Not local mobility anchor for this mobile node */
++#define IP6_MH_BAS_MAG_NOT_AUTHORIZED_FOR_PROXY_REG 154 /* The mobile access gateway is not authorized to send PBU */
++#define IP6_MH_BAS_NOT_AUTHORIZED_FOR_HOME_NETWORK_PREFIX 155 /* The mobile node is not authorized for one or more of the requesting home network prefixes */
++#define IP6_MH_BAS_TIMESTAMP_MISMATCH 156 /* Invalid timestamp value (clocks are out of sync) */
++#define IP6_MH_BAS_TIMESTAMP_LOWER_THAN_PREV_ACCEPTED 157 /* Invalid timestamp value (lower than previously accepted) */
++#define IP6_MH_BAS_MISSING_HOME_NETWORK_PREFIX_OPTION 158 /* Mising home network prefix option */
++#define IP6_MH_BAS_BCE_PBU_PREFIX_SET_DO_NOT_MATCH 159 /* The Home network prefixes listed in the BCE do not match all of the received PBU */
++#define IP6_MH_BAS_MISSING_MN_IDENTIFIER_OPTION 160 /* Mising mobile node identifier option */
++#define IP6_MH_BAS_MISSING_HANDOFF_INDICATOR_OPTION 161 /* Mising handoff indicator option */
++#define IP6_MH_BAS_MISSING_ACCESS_TECH_TYPE_OPTION 158 /* Mising access technology type option */
++
+ /*
+ * Status values for the Binding Error mobility messages
+ */
+diff --git a/src/bcache.c b/src/bcache.c
+index 41a36fe..3d147a1 100644
+--- a/src/bcache.c
++++ b/src/bcache.c
+@@ -45,8 +45,21 @@
+
+ static struct hash bc_hash;
+
++static int bcache_count = 0;
++
+ pthread_rwlock_t bc_lock; /* Protects binding cache */
+
++/**
++ * get_bcache_count - returns number of home and cache entries
++ * @type: HOMEREGENTRY, CACHEENTRY or ANY
++ **/
++int get_bcache_count(int type)
++{
++ if (!type)
++ return bcache_count;
++ return 0;
++}
++
+ void dump_bce(void *bce, void *os)
+ {
+ struct bcentry *e = (struct bcentry *)bce;
+@@ -133,6 +146,7 @@ static void _expire(struct tq_elem *tqe)
+ return;
+ }
+ pthread_rwlock_unlock(&e->lock);
++ dbg("Deleting Binding Cache because of expiration\n");
+ bce_delete(e, 0);
+ }
+ pthread_rwlock_unlock(&bc_lock);
+@@ -201,14 +215,14 @@ struct bcentry *bcache_get(const struct in6_addr *our_addr,
+ assert(peer_addr && our_addr);
+
+ pthread_rwlock_rdlock(&bc_lock);
+-
++ dbg("getting binding cache!\n");
+ bce = hash_get(&bc_hash, our_addr, peer_addr);
+-
+- if (bce)
++ dbg("Got bce or not?\n");
++ if (bce)
+ pthread_rwlock_wrlock(&bce->lock);
+ else
+ pthread_rwlock_unlock(&bc_lock);
+-
++ dbg("got binding cache\n");
+ return bce;
+ }
+
+@@ -254,6 +268,7 @@ static int __bcache_insert(struct bcentry *bce)
+ if (ret)
+ return ret;
+
++ bcache_count++;
+ return 0;
+ }
+
+@@ -398,6 +413,7 @@ static void bce_delete(struct bcentry *bce, int flush)
+ return;
+ }
+ }
++ bcache_count--;
+ hash_delete(&bc_hash, &bce->our_addr, &bce->peer_addr);
+ pthread_rwlock_unlock(&bce->lock);
+ bcache_free(bce);
+diff --git a/src/bcache.h b/src/bcache.h
+index b166ce6..4c51ba8 100644
+--- a/src/bcache.h
++++ b/src/bcache.h
+@@ -7,7 +7,7 @@
+ #include "hash.h"
+
+ struct bcentry {
+- struct in6_addr our_addr; /* Address to which we got BU */
++ struct in6_addr our_addr; /* Address to which we got BU *//*PMIP: MNid is stored in this addr */
+ struct in6_addr peer_addr; /* MN home address */
+ struct in6_addr old_coa; /* Previous care-of address */
+ struct in6_addr coa; /* MN care-of address */
+@@ -36,6 +36,16 @@ struct bcentry {
+ void (*cleanup)(struct bcentry *bce); /* Clean up bce data */
+
+ struct list_head mob_net_prefixes;
++
++ /* PMIP BCE extension */
++ int proxyReg; /* Flag for proxy registration */
++ uint8_t mnIdentifier[6]; /* MN Identifier */
++ uint8_t linkLayerID[6]; /* Link Layer Identifier */
++ struct in6_addr magLinkLocalAddress; /* link local address of the mobile access gateway */
++ struct AdvPrefix *prefix; /* Home Network prefixes assigned to the mobile node's connected interface */
++ int tunnelIfID; /* Tunnel interface Identifier - Internal to LMA */
++ uint8_t accTechType; /* Access technology type */
++ struct timespec timestamp; /* Timestamp of the most recently accepted PBU */
+ };
+
+ #define BCE_NONCE_BLOCK 0
+@@ -84,6 +94,8 @@ static inline int bce_exists(const struct in6_addr *our_addr,
+
+ void dump_bce(void *bce, void *os);
+
++int get_bcache_count(int type);
++
+ extern pthread_rwlock_t bc_lock; /* Protects binding cache */
+
+ #endif
+diff --git a/src/bul.c b/src/bul.c
+index 4e7b6fd..933ec27 100644
+--- a/src/bul.c
++++ b/src/bul.c
+@@ -65,9 +65,23 @@ struct bulentry *create_bule(const struct in6_addr *hoa,
+ bule->peer_addr = *cn_addr;
+ INIT_LIST_HEAD(&bule->tqe.list);
+ bule->seq = random();
++ bule->delForwarding = 0;
+ }
+ return bule;
+ }
++//
++//struct bulentry *create_bule_pmip(const uint8_t *mnID)
++//{
++// struct bulentry *bule;
++// if ((bule = malloc(sizeof(*bule))) != NULL) {
++// memset(bule, 0, sizeof(*bule));
++// strncpy(bule->mnIdentifier, mnID, 32);
++// INIT_LIST_HEAD(&bule->tqe.list);
++// bule->seq = random();
++// bule->handoffIndicator = 4;//by default, state unknown
++// }
++// return bule;
++//}
+
+ void free_bule(struct bulentry *bule)
+ {
+@@ -79,7 +93,7 @@ void dump_bule(void *bule, void *os)
+ {
+ struct bulentry *e = (struct bulentry *)bule;
+ FILE *out = (FILE *)os;
+-
++ //Now dumping PMIP informations
+ if (e->type == BUL_ENTRY)
+ fprintf(out, "== BUL_ENTRY ==\n");
+ else if (e->type == NON_MIP_CN_ENTRY)
+@@ -95,6 +109,16 @@ void dump_bule(void *bule, void *os)
+ NIP6ADDR(&e->coa));
+ fprintf(out, "CN address %x:%x:%x:%x:%x:%x:%x:%x\n",
+ NIP6ADDR(&e->peer_addr));
++ fprintf(out, "MN Identifier %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", (e->mnIdentifier[0]&0xFF), (e->mnIdentifier[1]&0xFF),
++ (e->mnIdentifier[2]&0xFF), (e->mnIdentifier[3]&0xFF) ,(e->mnIdentifier[4]&0xFF), (e->mnIdentifier[5]&0xFF));
++ struct AdvPrefix *tempo = NULL;
++ tempo = e->prefix;
++ while(tempo)
++ {
++ fprintf(out, "Home Network prefix %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(&tempo->Prefix));
++ tempo = tempo->next;
++ }
+ fprintf(out, " lifetime = %ld, ", e->lifetime.tv_sec);
+ fprintf(out, " delay = %ld\n", tstomsec(e->delay));
+ fprintf(out, " flags: ");
+@@ -108,6 +132,9 @@ void dump_bule(void *bule, void *os)
+ fprintf(out, "IP6_MH_BU_KEYM ");
+ if (e->flags & IP6_MH_BU_MR)
+ fprintf(out, "IP6_MH_BU_MR");
++ if (e->flags & IP6_MH_BU_PREG)
++ fprintf(out, "IP6_MH_BU_PREG");
++ //maybe add lma and mag address depending on the current profile
+
+ fprintf(out, "\n");
+ fflush(out);
+@@ -136,6 +163,41 @@ struct bulentry *bul_get(struct home_addr_info *hinfo,
+ return bule;
+ }
+
++/* functions to store the MN Id in an IPv6 addr;
++ * Here the MN Id is considered to be a MAC address of 48bits (6 bytes)
++ * The purpose is to use the already existing architecture of the bule
++ */
++struct in6_addr *transf_mnID_ip6addr (uint8_t *mnID)
++{
++ if (mnID == NULL){
++ dbg("mnID is NULL\n");
++ return NULL;
++ }
++ struct in6_addr *addr;
++ addr = malloc(sizeof(struct in6_addr));
++ memset(addr, 0, sizeof(struct in6_addr));
++ for (int i = 0; i< 6; i++){
++ addr->s6_addr[i]=mnID[i];
++ }
++ return addr;
++}
++
++uint8_t *trans_ip6addr_mnID (struct in6_addr *addr)
++{
++ uint8_t *mnID;
++ mnID = malloc(6 * sizeof(uint8_t));
++ for (int i = 0; i<6; i++){
++ mnID[i]=addr->s6_addr[i];
++ }
++ return mnID;
++}
++
++struct bulentry *bul_get_pmip(uint8_t *mnID)
++{
++ struct bulentry *bule;
++ return bule;
++}
++
+ /*
+ * need to be separated into two phase:
+ * phase 1: before sending BU
+@@ -169,6 +231,7 @@ void bul_update_expire(struct bulentry *bule)
+ Caller must fill all non-private fields of bule */
+ int bul_add(struct bulentry *bule)
+ {
++ /* !!! PMIP modification: use only one hash and no xfrm rules added */
+ int ret = 0;
+ struct timespec timer_expire;
+ struct home_addr_info *hai = bule->home;
+@@ -177,10 +240,13 @@ int bul_add(struct bulentry *bule)
+
+ if ((ret = hash_add(&bul_hash, bule, &bule->hoa, &bule->peer_addr)) < 0)
+ return ret;
++#ifndef ENABLE_PMIPV6
+ if ((ret = hash_add(&hai->bul, bule, NULL, &bule->peer_addr)) < 0)
+ goto bul_free;
++#endif /* ENABLE_PMIPV6 */
+
+ clock_gettime(CLOCK_REALTIME, &bule->lastsent);
++#ifndef ENABLE_PMIPV6
+ if (bule->type == BUL_ENTRY) {
+ if ((ret = pre_bu_bul_update(bule)) < 0)
+ goto home_bul_free;
+@@ -191,6 +257,7 @@ int bul_add(struct bulentry *bule)
+ goto home_bul_free;
+ }
+ }
++#endif
+ tsadd(bule->delay, bule->lastsent, timer_expire);
+ dbg("Adding bule\n");
+ dbg_func(bule, dump_bule);
+@@ -207,16 +274,24 @@ bul_free:
+ void bul_delete(struct bulentry *bule)
+ {
+ struct home_addr_info *hai = bule->home;
++#ifdef ENABLE_PMIPV6
++ /* PMIP modification: use only one hash and no XFRM rules */
++ if (bule->delForwarding == 1)
++ dereg_mn_forwarding(bule);
++#endif /* ENABLE_PMIPV6 */
+
+ del_task(&bule->tqe);
+ hash_delete(&bul_hash, &bule->hoa, &bule->peer_addr);
++#ifndef ENABLE_PMIPV6
+ hash_delete(&hai->bul, NULL, &bule->peer_addr);
++#endif /* ENABLE_PMIPV6 */
+
+ if (!IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa)) {
+ bule->last_coa = bule->coa;
+ bule->coa = bule->hoa;
+ bule->coa_changed = 1;
+ }
++#ifndef ENABLE_PMIPV6
+ if (bule->type == BUL_ENTRY) {
+ xfrm_del_bule(bule);
+ if (!(bule->flags & IP6_MH_BU_HOME))
+@@ -240,10 +315,12 @@ void bul_delete(struct bulentry *bule)
+ xfrm_unblock_fwd(hai);
+ }
+ }
++#endif /* ENABLE_PMIPV6 */
+ while (bule->ext_cleanup)
+ bule->ext_cleanup(bule);
+ dbg("Deleting bule\n");
+ dbg_func(bule, dump_bule);
++ free(bule->prefix);
+ free_bule(bule);
+ }
+
+diff --git a/src/bul.h b/src/bul.h
+index 75f7af6..aeec059 100644
+--- a/src/bul.h
++++ b/src/bul.h
+@@ -9,6 +9,7 @@
+ #include "tqueue.h"
+ #include "hash.h"
+ #include "list.h"
++#include "ndisc.h"
+
+ struct home_addr_info;
+
+@@ -54,7 +55,26 @@ struct bulentry {
+
+ void (* callback)(struct tq_elem *);
+ void (*ext_cleanup)(struct bulentry *);
+-};
++
++ /* Proxy MIP */
++ int proxyReg; /* Flag for proxy registration */
++ uint8_t mnIdentifier[6]; /* MN Identifier */
++ uint8_t linkLayerID[6]; /* Link Layer Identifier */
++ struct in6_addr magLinkLocalAddress; /* link local address of the mobile access gateway */
++ struct AdvPrefix *prefix; /* Home Network prefixes assigned to the mobile node's connected interface */
++ int tunnelIfID; /* Tunnel interface Identifier - Internal to LMA */
++ uint8_t accTechType; /* Access technology type */
++ struct timespec timestamp; /* Timestamp of the most recently accepted PBU */
++ uint8_t handoffIndicator; /* handoff indicator */
++
++ struct in6_addr lmaIpAddr; /* IPv6 address of the LMA */
++ int ifId; /* Interface identifier of the point to point link between mag and mn */
++ struct in6_addr magGlobalEgressAddress;
++ struct in6_addr mnLinkLocalAddress;
++ int firstReg; /* First registration */
++ int delForwarding;
++
++};
+
+
+
+@@ -104,5 +124,7 @@ void dump_bule(void *bule, void *os);
+ struct bulentry *create_bule(const struct in6_addr *hoa,
+ const struct in6_addr *cn_addr);
+ void free_bule(struct bulentry *bule);
++uint8_t *trans_ip6addr_mnID (struct in6_addr *addr);
++struct in6_addr *transf_mnID_ip6addr (uint8_t *mnID);
+
+ #endif
+diff --git a/src/conf.c b/src/conf.c
+index 5c29b48..b15b16e 100644
+--- a/src/conf.c
++++ b/src/conf.c
+@@ -226,6 +226,26 @@ static void conf_default(struct mip6_config *c)
+
+ /* CN bindings */
+ c->DoRouteOptimizationCN = 1;
++
++ /* PMIP options */
++ //TODO add PMIP default options
++ /* common options */
++ c->TimestampBasedApproachInUse = 1; /* 1 for use of timestamp consideration; 0 for no use of timestamp */
++ c->MobileNodeGeneratedTimestampInUse = 0; /* 0 for not using the MN generated timestamp mecanism */
++ //&c->FixedMAGLinkLocalAddressOnAllAccessLinks = IN6ADDR_ANY_INIT; /* TODO: correct the default value (IN6ADDR_ANY_INIT) and decide the format */
++ //&c->FixedMAGLinkLayerAddressOnAllAccessLinks = IN6ADDR_ANY_INIT; /* TODO: IDEM */
++
++ /* LMA options */
++ tssetsec(c->MinDelayBeforeBCEDelete, 10); /* seconds */
++ tssetdsec(c->MaxDelayBeforeNewBCEAssign, 1.5); /* seconds */
++ tssetdsec(c->TimestampValidityWindow, 0.3); /* seconds */
++
++ /* MAG options */
++ c->EnableMAGLocalRouting = 0;
++ tssetsec(c->PBUlifetime, 420); /* seconds */
++
++ /* MN profile storage */
++ INIT_LIST_HEAD(&c->pmipMobileNodes);
+ }
+
+ int conf_parse(struct mip6_config *c, int argc, char **argv)
+@@ -321,4 +341,46 @@ void conf_show(struct mip6_config *c)
+ /* CN options */
+ dbg("DoRouteOptimizationCN = %s\n",
+ CONF_BOOL_STR(c->DoRouteOptimizationCN));
++
++ /* PMIP options */
++ dbg("TimestampBasedApproachInUse = %u\n", c->TimestampBasedApproachInUse);
++ dbg("MobileNodeGeneratedTimestampInUse = %u\n", c->MobileNodeGeneratedTimestampInUse);
++ dbg("FixedMAGLinkLocalAddressOnAllAccessLinks = %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&c->FixedMAGLinkLocalAddressOnAllAccessLinks)); /* TODO define the format and the tostring function */
++ //dbg("address %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&c->FixedMAGLinkLocalAddressOnAllAccessLinks));
++ dbg("FixedMAGLinkLayerAddressOnAllAccessLinks = %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&c->FixedMAGLinkLayerAddressOnAllAccessLinks)); /* TODO define the format and the tostring function */
++
++ /* LMA options */
++ dbg("MinDelayBeforeBCEDelete = %f\n", tstodsec(c->MinDelayBeforeBCEDelete));
++ dbg("MaxDelayBeforeNewBCEAssign = %f\n", tstodsec(c->MaxDelayBeforeNewBCEAssign));
++ dbg("TimestampValidityWindow = %f\n", tstodsec(c->TimestampValidityWindow));
++
++ /* MAG options */
++ dbg("EnableMAGLocalRouting = %u\n", c->EnableMAGLocalRouting);
++ dbg("PBULifetime = %f\n", tstodsec(c->PBUlifetime));
++
++ /* MN policys profils */
++ //dbg("Test passage debut liste\n");
++ struct list_head *l;
++ list_for_each(l, &c->pmipMobileNodes) {
++ dbg("***** Mobile Nodes PMIP policy *****\n");
++ struct pmipMobileNodeEntry *npmipmnentry;
++ npmipmnentry = list_entry(l, struct pmipMobileNodeEntry, list);
++ if (npmipmnentry != NULL) {
++ //dbg("Mobile Node Identifier = %s\n", npmipmnentry->mnIdentifier);
++ dbg("MN ID: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n",(npmipmnentry->mnIdentifier[0]&0xFF), (npmipmnentry->mnIdentifier[1]&0xFF), (npmipmnentry->mnIdentifier[2]&0xFF), (npmipmnentry->mnIdentifier[3]&0xFF), (npmipmnentry->mnIdentifier[4]&0xFF), (npmipmnentry->mnIdentifier[5]&0xFF));
++ dbg("PMIP enabled = %d\n", npmipmnentry->pmip_enabled);
++ //if (npmipmnentry->mn_address_supported_conf_mode >= 0)
++ dbg("Supported Address Configuration Mode = %d\n", npmipmnentry->mn_address_supported_conf_mode);
++ if (tstodsec(npmipmnentry->homeNetworkPrefixLifetime) >= 0)
++ dbg("Home Network Prefix Lifetime = %f\n", tstodsec(npmipmnentry->homeNetworkPrefixLifetime));
++ if (!IN6_IS_ADDR_UNSPECIFIED(&npmipmnentry->home_network_prefix1))
++ dbg("Home Network Prefix = %x:%x:%x:%x:%x:%x:%x:%x for the interface identified by %s\n", NIP6ADDR(&npmipmnentry->home_network_prefix1), npmipmnentry->pmip_interface1);
++ if (!IN6_IS_ADDR_UNSPECIFIED(&npmipmnentry->home_network_prefix2))
++ dbg("Home Network Prefix = %x:%x:%x:%x:%x:%x:%x:%x for the interface identified by %s\n", NIP6ADDR(&npmipmnentry->home_network_prefix2), npmipmnentry->pmip_interface2);
++ if (!IN6_IS_ADDR_UNSPECIFIED(&npmipmnentry->home_network_prefix3))
++ dbg("Home Network Prefix = %x:%x:%x:%x:%x:%x:%x:%x for the interface identified by %s\n", NIP6ADDR(&npmipmnentry->home_network_prefix3), npmipmnentry->pmip_interface3);
++ }
++ }
++ dbg("***** End of Mobile Nodes PMIP policy *****\n");
++ //dbg("Test passage fin liste\n");
+ }
+diff --git a/src/conf.h b/src/conf.h
+index fc34dd6..3b8b8f1 100644
+--- a/src/conf.h
++++ b/src/conf.h
+@@ -57,6 +57,48 @@ struct mip6_config {
+
+ /* CN options */
+ char DoRouteOptimizationCN;
++
++ /* PMIP options */
++ /* Common options */
++ unsigned int TimestampBasedApproachInUse;
++ unsigned int MobileNodeGeneratedTimestampInUse;
++ struct in6_addr FixedMAGLinkLocalAddressOnAllAccessLinks;
++ struct in6_addr FixedMAGLinkLayerAddressOnAllAccessLinks;
++
++ /* LMA options */
++ struct timespec MinDelayBeforeBCEDelete;
++ struct timespec MaxDelayBeforeNewBCEAssign;
++ struct timespec TimestampValidityWindow;
++ int LMAHomeInterfaceIndex;
++
++ /* MAG options */
++ unsigned int EnableMAGLocalRouting;
++ struct in6_addr MAGEgressGlobalAddress;
++ int MAGEgressInterfaceIndex;
++ struct timespec PBUlifetime;
++
++ /* MN profile storage */
++ /* TODO create a new structure to store the profiles of the nodes */
++ struct list_head pmipMobileNodes;
++
++};
++
++struct pmipMobileNodeEntry {
++ struct list_head list; /* ??? needed?-> oui pour les listes */
++ uint8_t mnIdentifier[32]; /* address mac used for MN Identifier TODO: check the length */
++ int pmip_enabled;
++ struct timespec homeNetworkPrefixLifetime;
++ int mn_address_supported_conf_mode;
++ struct in6_addr lma_address;
++ uint8_t pmip_interface1[32];
++ uint8_t pmip_interface2[32];
++ uint8_t pmip_interface3[32];
++ struct in6_addr home_network_prefix1;
++ struct in6_addr home_network_prefix2;
++ struct in6_addr home_network_prefix3;
++ int home_network_plen1;
++ int home_network_plen2;
++ int home_network_plen3;
+ };
+
+ struct net_iface {
+@@ -69,12 +111,20 @@ struct net_iface {
+ int is_tunnel;
+ };
+
++struct hnprefix {
++ struct in6_addr prefix;
++ uint8_t plen;
++};
++
+ extern struct mip6_config conf;
+
+ #define MIP6_ENTITY_NO -1
+ #define MIP6_ENTITY_CN 0
+ #define MIP6_ENTITY_MN 1
+ #define MIP6_ENTITY_HA 2
++#define STATELESS_CONFIGURATION 0
++#define STATEFUL_CONFIGURATION 1
++#define STATELESS_AND_STATEFUL_CONFIGURATION 2
+
+ static inline int is_cn(void)
+ {
+diff --git a/src/gram.y b/src/gram.y
+index 9fd63c7..43b9ca3 100644
+--- a/src/gram.y
++++ b/src/gram.y
+@@ -53,6 +53,14 @@ struct net_iface ni = {
+ .mn_if_preference = POL_MN_IF_DEF_PREFERENCE,
+ .is_tunnel = 0,
+ };
++
++struct pmipMobileNodeEntry pmipmnentry = {
++ .mn_address_supported_conf_mode = STATELESS_CONFIGURATION,
++ .homeNetworkPrefixLifetime.tv_sec = -1,
++ .home_network_prefix1 = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } },
++ .home_network_prefix2 = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } },
++ .home_network_prefix3 = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } },
++};
+
+ struct home_addr_info hai = {
+ .ro_policies = LIST_HEAD_INIT(hai.ro_policies),
+@@ -191,6 +199,31 @@ static void uerror(const char *fmt, ...) {
+ %token ISMOBRTR
+ %token HASERVEDPREFIX
+ %token MOBRTRUSEEXPLICITMODE
++%token TIMESTAMPBASEDAPPROACHINUSE
++%token MOBILENODEGENERATEDTIMESTAMPINUSE
++%token FIXEDMAGLINKLOCALADDRESSONALLACCESSLINKS
++%token FIXEDMAGLINKLAYERADDRESSONALLACCESSLINKS
++%token MINDELAYBEFOREBCEDELETE
++%token MAXDELAYBEFORENEWBCEASSIGNE
++%token TIMESTAMPVALIDITYWINDOW
++%token ENABLEMAGLOCALROUTING
++%token PMIPENABLED
++%token HOMEPREFIXLIFETIME
++%token LINKLAYERIDENTIFIER
++%token MNIDENTIFIER
++%token LMAADDRESS
++%token SUPPORTEDCONFIGURATIONMODE
++%token HOMENETWORKPREFIX1
++%token HOMENETWORKPREFIX2
++%token HOMENETWORKPREFIX3
++%token PMIPINTERFACE1
++%token PMIPINTERFACE2
++%token PMIPINTERFACE3
++%token MAGLINKLMA
++%token MAGINTERFACELMA
++%token LMAINTERFACEMAG
++%token MAGEGRESSGLOBALADDRESS
++%token PBULIFETIME
+
+ %token INV_TOKEN
+
+@@ -230,6 +263,28 @@ topdef : MIP6ENTITY mip6entity ';'
+ conf.NonVolatileBindingCache = $2;
+ }
+ | INTERFACE ifacedef
++ | MAGINTERFACELMA QSTRING ';'
++ {
++ conf.MAGEgressInterfaceIndex = if_nametoindex($2);
++ free($2);
++ if (conf.MAGEgressInterfaceIndex <= 0) {
++ uerror("invalid interface");
++ return -1;
++ }
++ }
++ | LMAINTERFACEMAG QSTRING ';'
++ {
++ conf.LMAHomeInterfaceIndex = if_nametoindex($2);
++ free($2);
++ if (conf.LMAHomeInterfaceIndex <= 0) {
++ uerror("invalid interface");
++ return -1;
++ }
++ }
++ | MAGEGRESSGLOBALADDRESS ADDR ';'
++ {
++ memcpy(&conf.MAGEgressGlobalAddress, &$2, sizeof(struct in6_addr));
++ }
+ | SENDMOBPFXSOLS BOOL ';'
+ {
+ conf.SendMobPfxSols = $2;
+@@ -351,6 +406,43 @@ topdef : MIP6ENTITY mip6entity ';'
+ {
+ conf.OptimisticHandoff = $2;
+ }
++ | ENABLEMAGLOCALROUTING NUMBER ';'
++ {
++ conf.EnableMAGLocalRouting = $2;
++ }
++ | TIMESTAMPBASEDAPPROACHINUSE NUMBER ';'
++ {
++ conf.TimestampBasedApproachInUse = $2;
++ }
++ | MOBILENODEGENERATEDTIMESTAMPINUSE NUMBER ';'
++ {
++ conf.MobileNodeGeneratedTimestampInUse = $2;
++ }
++ | MINDELAYBEFOREBCEDELETE DECIMAL ';'
++ {
++ tssetdsec(conf.MinDelayBeforeBCEDelete, $2);
++ }
++ | MAXDELAYBEFORENEWBCEASSIGNE DECIMAL ';'
++ {
++ tssetdsec(conf.MaxDelayBeforeNewBCEAssign, $2);
++ }
++ | TIMESTAMPVALIDITYWINDOW DECIMAL ';'
++ {
++ tssetdsec(conf.TimestampValidityWindow, $2);
++ }
++ | FIXEDMAGLINKLOCALADDRESSONALLACCESSLINKS ADDR ';'
++ {
++ memcpy(&conf.FixedMAGLinkLocalAddressOnAllAccessLinks, &$2, sizeof(struct in6_addr));
++ }
++ | FIXEDMAGLINKLAYERADDRESSONALLACCESSLINKS ADDR ';'
++ {
++ memcpy(&conf.FixedMAGLinkLayerAddressOnAllAccessLinks, &$2, sizeof(struct in6_addr));
++ }
++ | MNIDENTIFIER pmipnode
++ | PBULIFETIME DECIMAL ';'
++ {
++ tssetdsec(conf.PBUlifetime, $2);
++ }
+ ;
+
+ mip6entity : MIP6CN { $$ = MIP6_ENTITY_CN; }
+@@ -478,6 +570,85 @@ linksub : QSTRING '{' linkdefs '}'
+ }
+ ;
+
++pmipnode : QSTRING '{' pmipdefs '}'
++ {
++ struct pmipMobileNodeEntry *npmipentry;
++ char tmp[32];
++ strncpy(tmp, $1, 32);
++ sscanf(tmp,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &pmipmnentry.mnIdentifier[0], &pmipmnentry.mnIdentifier[1],
++ &pmipmnentry.mnIdentifier[2], &pmipmnentry.mnIdentifier[3],
++ &pmipmnentry.mnIdentifier[4], &pmipmnentry.mnIdentifier[5]);
++ if (IN6_IS_ADDR_UNSPECIFIED(&pmipmnentry.lma_address)) {
++ uerror("No LMA addresses defined"
++ "for MN %s", pmipmnentry.mnIdentifier);
++ return -1;
++ }
++ /* TODO: check of the length of the MN-Identifier... and the uniqueness of the Home Network prefixes */
++ npmipentry = malloc(sizeof(struct pmipMobileNodeEntry));
++ if (npmipentry == NULL) {
++ uerror("out of memory");
++ return -1;
++ }
++ memcpy(npmipentry, &pmipmnentry, sizeof(struct pmipMobileNodeEntry));
++ list_add_tail(&npmipentry->list, &conf.pmipMobileNodes);
++
++ memset(&pmipmnentry, 0, sizeof(struct pmipMobileNodeEntry));
++ pmipmnentry.mn_address_supported_conf_mode = STATELESS_CONFIGURATION;
++ pmipmnentry.homeNetworkPrefixLifetime.tv_sec = -1;
++ pmipmnentry.home_network_prefix1 = in6addr_any;
++ pmipmnentry.home_network_prefix2 = in6addr_any;
++ pmipmnentry.home_network_prefix3 = in6addr_any;
++ }
++ ;
++pmipdefs : pmipdef
++ | pmipdefs pmipdef
++ ;
++
++pmipdef : PMIPENABLED NUMBER ';'
++ {
++ pmipmnentry.pmip_enabled = $2;
++ }
++ | LMAADDRESS ADDR ';'
++ {
++ memcpy(&pmipmnentry.lma_address, &$2, sizeof(struct in6_addr));
++ }
++ | SUPPORTEDCONFIGURATIONMODE NUMBER ';'
++ {
++ pmipmnentry.mn_address_supported_conf_mode = $2;
++ }
++ | HOMENETWORKPREFIX1 ADDR '/' prefixlen ';'
++ {
++ memcpy(&pmipmnentry.home_network_prefix1, &$2, sizeof(struct in6_addr));
++ pmipmnentry.home_network_plen1 = $4;
++ }
++ | HOMENETWORKPREFIX2 ADDR '/' prefixlen ';'
++ {
++ memcpy(&pmipmnentry.home_network_prefix2, &$2, sizeof(struct in6_addr));
++ pmipmnentry.home_network_plen2 = $4;
++ }
++ | HOMENETWORKPREFIX3 ADDR '/' prefixlen ';'
++ {
++ memcpy(&pmipmnentry.home_network_prefix3, &$2, sizeof(struct in6_addr));
++ pmipmnentry.home_network_plen3 = $4;
++ }
++ | PMIPINTERFACE1 QSTRING ';'
++ {
++ strncpy(pmipmnentry.pmip_interface1, $2, 32);
++ }
++ | PMIPINTERFACE2 QSTRING ';'
++ {
++ strncpy(pmipmnentry.pmip_interface2, $2, 32);
++ }
++ | PMIPINTERFACE3 QSTRING ';'
++ {
++ strncpy(pmipmnentry.pmip_interface3, $2, 32);
++ }
++ | HOMEPREFIXLIFETIME DECIMAL ';'
++ {
++ tssetdsec(pmipmnentry.homeNetworkPrefixLifetime, $2);
++ }
++ ;
++
+ linkdefs : linkdef
+ | linkdefs linkdef
+ ;
+diff --git a/src/ha.c b/src/ha.c
+index fbdcff0..4e22858 100644
+--- a/src/ha.c
++++ b/src/ha.c
+@@ -66,6 +66,7 @@ static volatile unsigned long bu_worker_count = 0;
+ static pthread_cond_t cond;
+
+ LIST_HEAD(bu_worker_list);
++LIST_HEAD(pbu_worker_list);
+ LIST_HEAD(ha_interfaces);
+
+ static void ha_recv_ra(const struct icmp6_hdr *ih, ssize_t len,
+@@ -572,6 +573,9 @@ static int nemo_ha_add_mnp_routes(struct list_head *old_mnps,
+ list_for_each(list, new_mnps) {
+ struct prefix_list_entry *p;
+ p = list_entry(list, struct prefix_list_entry, list);
++ /* XXX */
++ if (!p)
++ return 0;
+ if (!all &&
+ prefix_list_find(old_mnps, &p->ple_prefix, p->ple_plen))
+ continue;
+@@ -592,10 +596,17 @@ struct home_tnl_ops_parm {
+ static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ {
+ const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
++ uint8_t plen = 128;
+ struct list_head *mnp;
+
+ assert(old_if);
+
++ if (&p->bce->proxyReg){
++ peer_addr = &p->bce->prefix->Prefix; /* Tunnel is already created, here we just update the routes, so the prefix is the peer address, not the MAG address */
++ plen = p->bce->prefix->PrefixLen;
++ }
++ else
++ peer_addr = &p->bce->peer_addr;
+ our_addr = &p->bce->our_addr;
+ peer_addr = &p->bce->peer_addr;
+ coa = &p->bce->peer_addr;
+@@ -611,7 +622,7 @@ static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ }
+ /* delete HoA route */
+ route_del(old_if, RT6_TABLE_MAIN,
+- IP6_RT_PRIO_MIP6_FWD, NULL, 0, peer_addr, 128, NULL);
++ IP6_RT_PRIO_MIP6_FWD, NULL, 0, peer_addr, plen, NULL);
+
+ /* delete MNP routes */
+ nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
+@@ -625,10 +636,19 @@ static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ {
+ const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
++ uint8_t plen = 128;
+ struct list_head *mnp;
+
+ assert(new_if);
+
++#ifdef ENABLE_PMIPV6
++ if (&p->bce->proxyReg){
++ peer_addr = &p->bce->prefix->Prefix;
++ plen = p->bce->prefix->PrefixLen;
++ }
++ else
++ peer_addr = &p->bce->peer_addr;
++#endif /* ENABLE_PMIPV6 */
+ our_addr = &p->bce->our_addr;
+ peer_addr = &p->bce->peer_addr;
+ coa = &p->bce->coa;
+@@ -636,6 +656,8 @@ static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ &p->bce->peer_addr : &p->bce->old_coa;
+ mnp = &p->mob_net_prefixes;
+
++ dbg("Peer address for tunnel: %x:%x:%x:%x:%x:%x:%x:%x/%u\n",
++ NIP6ADDR(peer_addr), plen);
+ /* update tunnel interface */
+ p->bce->tunnel = new_if;
+
+@@ -649,14 +671,17 @@ static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ goto err;
+ }
+ /* add HoA route */
++ dbg("route creation: new_if = %d\n",new_if );
+ if (route_add(new_if, RT6_TABLE_MAIN,
+ RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
+- NULL, 0, peer_addr, 128, NULL) < 0) {
++ NULL, 0, peer_addr, plen, NULL) < 0) {
+ p->ba_status = IP6_MH_BAS_INSUFFICIENT;
+ goto err;
+ }
+- /* add SP entry */
++ dbg("route created!\n");
++ /* add SP entry */
+ if (conf.UseMnHaIPsec) {
++ dbg("Using IPsec!\n");
+ if (ha_ipsec_tnl_pol_add(our_addr, peer_addr,
+ p->bce->tunnel, mnp) < 0) {
+ p->ba_status = IP6_MH_BAS_INSUFFICIENT;
+@@ -691,6 +716,10 @@ static int home_tnl_chg(int old_if, int new_if, struct home_tnl_ops_parm *p)
+ const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+ struct list_head *mnp;
+
++ if (&p->bce->proxyReg)
++ peer_addr = &p->bce->prefix->Prefix;
++ else
++ peer_addr = &p->bce->peer_addr;
+ our_addr = &p->bce->our_addr;
+ peer_addr = &p->bce->peer_addr;
+ coa = &p->bce->coa;
+@@ -770,7 +799,7 @@ static void home_cleanup(struct bcentry *bce)
+
+ if (bce->link > 0) {
+ route_del(bce->link, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT,
+- &bce->our_addr, 128, &bce->peer_addr, 128, NULL);
++ &bce->our_addr, 128, &bce->peer_addr, bce->prefix->PrefixLen, NULL);
+ proxy_nd_stop(bce->link, &bce->peer_addr, bce->flags);
+ }
+ if (bce->tunnel > 0) {
+@@ -1227,6 +1256,354 @@ int ha_recv_home_bu(const struct ip6_mh *mh, ssize_t len,
+ return 0;
+ }
+
++/* PMIP PBU recveiver worker */
++static void *lma_recv_pbu_worker(void *varg)
++{
++ struct ha_recv_pbu_args *arg = varg;
++ struct in6_addr_bundle out;
++ struct bcentry *bce;
++ struct timespec lft, tmp, now, tmp2, tmp3;
++ int iif, status, new, home_ifindex;
++ uint16_t bu_flags, seqno;
++ uint8_t ba_flags;
++ struct home_tnl_ops_parm p;
++
++ pthread_dbg("thread started");
++ dbg("cream");
++restart:
++ clock_gettime(CLOCK_REALTIME, &now);
++ home_ifindex = 0;
++ new = 0;
++ ba_flags = IP6_MH_BA_PREG;
++ lft = arg->lft;
++ iif = arg->iif;
++ bu_flags = arg->bu->ip6mhbu_flags;
++ seqno = ntohs(arg->bu->ip6mhbu_seqno);
++ out.src = &arg->src;
++ out.dst = &arg->dst;
++ if (!IN6_IS_ADDR_UNSPECIFIED(&arg->remote_coa))
++ out.remote_coa = &arg->remote_coa;
++ else
++ out.remote_coa = NULL; /* Will be NULL in case of PMIP */
++ if (!IN6_IS_ADDR_UNSPECIFIED(&arg->dst))
++ out.bind_coa = &arg->dst; /* PMIP case -> the COA is the address of the MAG (proxy COA) */
++ else
++ out.bind_coa = NULL;
++ out.local_coa = NULL;
++
++ /* We consider only one prefix */
++ dbg("Prefix assigned: %x:%x:%x:%x:%x:%x:%x:%x/%u\n",
++ NIP6ADDR(&arg->prefix->Prefix), arg->prefix->PrefixLen);
++ clock_gettime(CLOCK_REALTIME, &tmp3);
++ bce = bcache_get(out.src, &arg->prefix->Prefix); /* BCE: our_addr = LMA IP addr; peer_addr = prefix for MN */
++ clock_gettime(CLOCK_REALTIME, &tmp2);
++ tssub(tmp2, tmp3, tmp2);
++ dbg("time for getting BCE... %d'%d\n", tmp2.tv_sec, tmp2.tv_nsec);
++ if (bce) {
++ if (bce->type != BCE_NONCE_BLOCK) {
++ /* Check the MN Id */
++ dbg("BCE already existing, checking the options\n");
++ int comp = 0;
++ for (int i = 0; i<6; i++){
++ if (bce->mnIdentifier[i] != arg->mnId[i]){
++ comp = 1;
++ break;
++ }
++ }
++ if (comp == 1){
++ status = IP6_MH_BAS_NOT_AUTHORIZED_FOR_HOME_NETWORK_PREFIX;
++ goto send_nack;
++ }
++ if (!(bce->flags & IP6_MH_BU_HOME)) {
++ /* H-bit mismatch, flags changed */
++ bcache_release_entry(bce);
++ bce = NULL;
++ status = IP6_MH_BAS_REG_NOT_ALLOWED;
++ goto send_nack;
++ }
++ if (bce->type == BCE_DAD) {
++ dbg("BCE_DAD...\n");
++ bcache_release_entry(bce);
++ pthread_mutex_lock(&bu_worker_mutex);
++ list_add_tail(&arg->list, &pbu_worker_list);
++ bu_worker_count--;
++ /* with BCE_DAD we should have at least one
++ active worker */
++ assert(bu_worker_count > 0);
++ *(arg->statusp) = -EBUSY;
++ pthread_mutex_unlock(&bu_worker_mutex);
++ pthread_exit(NULL);
++ }
++ /* Check timestamp option */
++ if (arg->timestamp){
++ /* Use of the timestamp instead of the sequence number */
++ dbg("Using timestamp approach\n");
++ struct timespec now;
++ clock_gettime(CLOCK_REALTIME, &now);
++ if (tsbefore(bce->timestamp, *arg->timestamp)){
++ /* timestamp older than previously received */
++ *arg->timestamp = now;
++ status = IP6_MH_BAS_TIMESTAMP_LOWER_THAN_PREV_ACCEPTED;
++ goto send_nack;
++ }
++ } /* If no timestamp, use of the sequence number */
++ else if (!MIP6_SEQ_GT(seqno, bce->seqno)) {
++ if (arg->flags & HA_BU_F_PASSIVE_SEQ) {
++ /* always use valid sequence */
++ seqno = bce->seqno + 1;
++ } else {
++ /* sequence number expired */
++ status = IP6_MH_BAS_SEQNO_BAD;
++ seqno = bce->seqno;
++ bcache_release_entry(bce);
++ bce = NULL;
++ goto send_nack;
++ }
++ }
++ /* Check the different conditions to update the bce */
++ int cond = 0;
++ /* Check the link layer identifier option */
++ if (arg->linkLayerId && bce->linkLayerID){
++ int j = 0;
++ for (int i = 0; i<6; i++){
++ if (arg->linkLayerId[i] != bce->linkLayerID[i])
++ j=1;
++ }
++ if (j == 0){
++ cond = 1;
++ }
++ }
++ if (arg->handoffIndicator == 2){
++ cond = 1;
++ }
++ if (!arg->linkLayerId && !bce->linkLayerID && arg->techType == bce->accTechType && arg->handoffIndicator ==3){
++ cond = 1;
++ }
++ if (IN6_ARE_ADDR_EQUAL(&arg->src, &bce->coa) && bce->accTechType == arg->techType){
++ cond = 1;
++ }
++ /* The request is considered as for a new mobility session */
++ if (cond == 0){
++ bcache_release_entry(bce);
++ bce = NULL;
++ dbg("The pbu is considered as a new BCE\n");
++ }
++ } else {
++ bcache_release_entry(bce);
++ bce = NULL;
++ /* don't let MN deregister BCE_NONCE_BLOCK entry */
++ if (!tsisset(lft)) {
++ status = IP6_MH_BAS_UNSPECIFIED;
++ goto send_nack;
++ }
++ /* else get rid of it */
++ bcache_delete(out.src, &arg->prefix->Prefix);
++ }
++ } else if (!tsisset(lft)) {
++ status = IP6_MH_BAS_NOT_HA;
++ goto send_nack;
++ }
++/* the status is determined by the following check (prefix are in the subnet..., in PMIP the status can only be 0 */
++// if ((status = mpd_prefix_check(out.src, out.dst,
++// &lft, &home_ifindex, new)) < 0) {
++// /* not home agent for this subnet */
++// status = IP6_MH_BAS_NOT_HOME_SUBNET;
++// goto send_nack;
++// }
++ home_ifindex = conf.LMAHomeInterfaceIndex;
++ dbg("home_ifindex = %d\n", home_ifindex);
++ /* Need to check the attributed HNPrefix, the LMA must be able tu use them-> configuration variable? */
++ status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
++ out.src, arg->bu, arg->len);/* will return the default binding acl policy : accepted -> status = 0 */
++ if (status >= IP6_MH_BAS_UNSPECIFIED)
++ goto send_nack;
++ /* lifetime may be further decreased by local policy */
++ if (conf.pmgr.max_binding_life(out.dst, out.bind_coa, out.src,
++ arg->bu, arg->len, &lft, &tmp)) {
++ if (tsbefore(lft, tmp))
++ lft = tmp;
++ }
++ mpd_sanitize_lft(&lft);
++ if (!bce) {
++ dbg("Creating new BCE\n");
++ bce = bcache_alloc(BCE_HOMEREG);
++ if (!bce) {
++ status = IP6_MH_BAS_INSUFFICIENT;
++ goto send_nack;
++ }
++ bce->our_addr = *out.src;
++ bce->peer_addr = arg->prefix->Prefix;
++ bce->coa = *out.bind_coa;
++ bce->seqno = seqno;
++ bce->flags = bu_flags;
++ bce->type = BCE_DAD;
++ bce->cleanup = NULL;
++ bce->link = home_ifindex;
++ bce->proxyReg = 1;
++ bce->accTechType = arg->techType;
++ bce->magLinkLocalAddress = *out.dst;
++ bce->prefix = malloc(sizeof(struct AdvPrefix));
++ memset(bce->prefix, 0, sizeof(struct AdvPrefix));
++ bce->prefix->Prefix = arg->prefix->Prefix;
++ bce->prefix->PrefixLen = arg->prefix->PrefixLen;
++ /* TODO: add LinkLayer ID */
++ for (int i = 0; i<6; i++)
++ bce->mnIdentifier[i] = arg->mnId[i];
++ tscpy(bce->timestamp, *(arg->timestamp));
++ if (arg->linkLocalAddr)
++ bce->magLinkLocalAddress = *arg->linkLocalAddr;
++ if (bcache_add_homereg(bce) < 0) {
++ free(bce);
++ bce = NULL;
++ status = IP6_MH_BAS_INSUFFICIENT;
++ goto send_nack;
++ }
++// if (!(arg->flags & HA_BU_F_SKIP_DAD)) {
++// /* Do DAD for home address */
++// dbg("Doing DAD for the attributed prefix\n");
++// if (ndisc_do_dad(home_ifindex, &arg->prefix->Prefix,
++// bu_flags & IP6_MH_BU_LLOCAL) < 0) {
++// bcache_delete(out.src, &arg->prefix->Prefix);
++// bce = NULL;
++// status = IP6_MH_BAS_DAD_FAILED;
++// goto send_nack;
++// }
++// }
++ bce = bcache_get(out.src, &arg->prefix->Prefix);
++ if (!bce) {
++ BUG("BCE deleted before DAD completed!");
++ status = IP6_MH_BAS_UNSPECIFIED;
++ goto send_nack;
++ }
++ new = 1;
++ }
++ p.bce = bce;
++ p.ba_status = status;
++ bce->seqno = seqno;
++ bce->flags = bu_flags;
++ bce->lifetime = lft;
++ if (new) {
++
++ clock_gettime(CLOCK_REALTIME, &tmp3);
++ if ((bce->tunnelIfID = is_tnl_existing(out.src, out.dst)) == 0){/* Tunnel is already created with the MAG? */
++ if ((bce->tunnelIfID = tunnel_add(out.src, out.bind_coa, 0,
++ home_tnl_ops, &p)) < 0) {
++ if (p.ba_status >= IP6_MH_BAS_UNSPECIFIED)
++ status = p.ba_status;
++ else
++ status = IP6_MH_BAS_INSUFFICIENT;
++ dbg("Not enough resources for tunnel creation!\n");
++ goto send_nack;
++ }
++ }
++
++ bce->cleanup = home_cleanup;
++ dbg("Creating route: link = %d from %x:%x:%x:%x:%x:%x:%x:%x "
++ "to %x:%x:%x:%x:%x:%x:%x:%x/%u \n", bce->link, NIP6ADDR(&bce->our_addr), NIP6ADDR(&arg->prefix->Prefix), arg->prefix->PrefixLen);
++ if (route_add(bce->link, RT6_TABLE_MIP6,
++ RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_OUT,
++ &bce->our_addr, 128, &arg->prefix->Prefix, arg->prefix->PrefixLen,
++ NULL) < 0) {/* Use of gateway? address of MAG? */
++ status = IP6_MH_BAS_INSUFFICIENT;
++ dbg("Not enough resources for route creation!\n");
++ goto send_nack;
++ }
++
++ /* Is it still needed? Think not */
++// if (proxy_nd_start(bce->link, out.dst, out.src,
++// bu_flags) < 0) {
++// status = IP6_MH_BAS_INSUFFICIENT;
++// goto send_nack;
++// }
++ clock_gettime(CLOCK_REALTIME, &tmp2);
++ tssub(tmp2, tmp3, tmp2);
++ dbg("time for generating tunnels and route... %d'%d\n", tmp2.tv_sec, tmp2.tv_nsec);
++ bce->type = BCE_HOMEREG;
++ bcache_complete_homereg(bce);/* XFRM policies: check if related to the MAG or the node -> node but not very sure... */
++ bcache_release_entry(bce);
++ } else if (!tsisset(lft)){
++ if (!IN6_ARE_ADDR_EQUAL(out.bind_coa, &bce->coa)){/* We ignore the PBU */
++ bcache_release_entry(bce);
++ goto out;
++ }
++ bcache_release_entry(bce);
++ bcache_delete(out.src, &arg->prefix->Prefix);
++ } else if (IN6_ARE_ADDR_EQUAL(out.bind_coa, &bce->coa)){
++ /* No handoff -> updating lifetime */
++ bcache_update_expire(bce);
++ bcache_release_entry(bce);
++ } else {
++ bce->old_coa = bce->coa;
++ bce->coa = *out.bind_coa; /* The new COA is the one from MAG */
++
++ /* Delete the old tunnel if not used by another MN...-> handled by tunnel_mod */
++
++ /* PMIP change function tunnel mod for handling the use of tunnel by different nodes! (already handled, kind of...) */
++ if (tunnel_mod(bce->tunnel, out.src, out.bind_coa, 0,
++ home_tnl_ops, &p) < 0) {/* modify the tunnel and the routes */
++ if (p.ba_status >= IP6_MH_BAS_UNSPECIFIED)
++ status = p.ba_status;
++ else
++ status = IP6_MH_BAS_INSUFFICIENT;
++ goto send_nack;
++ }
++ bcache_update_expire(bce);
++ bcache_release_entry(bce);
++ }
++
++
++ if ((bu_flags & IP6_MH_BU_KEYM) &&
++ conf.pmgr.use_keymgm(out.dst, out.src))
++ ba_flags |= IP6_MH_BA_KEYM;
++
++ if (ba_flags & IP6_MH_BA_KEYM) {
++ /* FUTURE */
++ /* Move the peer endpoint of the key management
++ * protocol connection, if any, to the new care-of
++ * address. For an IKE phase 1 connection, this means
++ * that any IKE packets sent to the peer are sent to
++ * this address, and packets from this address with
++ * the original ISAKMP cookies are accepted. */
++ } else {
++ /* FUTURE */
++ /* Discard key management connections, if any, to the
++ * old care-of address. If the mobile node did not
++ * have a binding before sending this Binding Update,
++ * discard the connections to the home address. */
++ }
++ if (!(arg->flags & HA_BU_F_SKIP_BA)){
++ clock_gettime(CLOCK_REALTIME, &tmp2);
++ tssub(tmp2, now, tmp2);
++ dbg("time for generating PBA... %d'%d\n", tmp2.tv_sec, tmp2.tv_nsec);
++ mh_send_pba(&out, status, ba_flags, seqno, &lft, NULL, iif, arg);
++ }
++ if (new && tsisset(lft))
++ mpd_start_mpa(&bce->our_addr, &bce->peer_addr);
++out:
++ free(arg);
++ pthread_mutex_lock(&bu_worker_mutex);
++ if (!list_empty(&pbu_worker_list)) {
++ struct list_head *l = pbu_worker_list.next;
++ list_del(l);
++ arg = list_entry(l, struct ha_recv_pbu_args, list);
++ pthread_mutex_unlock(&bu_worker_mutex);
++ goto restart;
++ }
++ if (--bu_worker_count == 0)
++ pthread_cond_signal(&cond);
++ *(arg->statusp) = status;
++ pthread_mutex_unlock(&bu_worker_mutex);
++ pthread_exit(NULL);
++send_nack:
++ if (bce) {
++ bcache_release_entry(bce);
++ bcache_delete(out.src, out.dst);
++ }
++ if (!(arg->flags & HA_BU_F_SKIP_BA))
++ mh_send_pba_err(&out, status, IP6_MH_BA_PREG, seqno, NULL, iif, arg);
++ goto out;
++}
++
+ static void ha_recv_bu(const struct ip6_mh *mh, ssize_t len,
+ const struct in6_addr_bundle *in, int iif)
+ {
+@@ -1238,8 +1615,93 @@ static void ha_recv_bu(const struct ip6_mh *mh, ssize_t len,
+ (void)cn_recv_bu(mh, len, in, iif);
+ }
+
++static void lma_recv_pbu(const struct ip6_mh *mh, ssize_t len, const struct in6_addr_bundle *in, int iif)
++{
++ struct ip6_mh_binding_update *bu;
++ struct mh_options mh_opts;
++ struct in6_addr_bundle out;
++ struct timespec lft, now, tmp;
++ struct ha_recv_pbu_args *arg;
++ uint32_t flags = 0;
++ int status = 0;
++ pthread_t worker;
++ clock_gettime(CLOCK_REALTIME, &now);
++ bu = (struct ip6_mh_binding_update *)mh;
++
++ dbg("cream: pbu receive\n");
++ arg = malloc(sizeof(struct ha_recv_pbu_args) + len);
++
++ status = mh_pbu_parse(bu, len, in, &out, &mh_opts, &lft, NULL, arg);
++ dbg("cream: status = %d\n", status);
++
++ if (status < 0){
++ dbg("Problems while parsing PBU...\n");
++ return;
++ }
++
++ if (status >= 128){
++ dbg("pbu rejected\n");
++ mh_send_pba_err(&out, status, IP6_MH_BA_PREG,
++ ntohs(bu->ip6mhbu_seqno), NULL, iif, arg); /* TODO: include the mandatory options */
++ }
++
++ if (!arg) {
++ if (bce_exists(out.src, out.dst))
++ bcache_delete(out.src, out.dst);
++
++ if (!(arg->flags & HA_BU_F_SKIP_BA))
++ mh_send_pba_err(&out, IP6_MH_BAS_INSUFFICIENT, IP6_MH_BA_PREG,
++ ntohs(bu->ip6mhbu_seqno), NULL, iif, arg);
++ return;
++ }
++ arg->src = *out.src;
++ arg->dst = *out.dst;
++ /* PMIP case: remote coa and bind coa and local coa are NULL because no HoA option or type 2 routing header */
++ if (out.remote_coa)
++ arg->remote_coa = *out.remote_coa;
++ else
++ arg->remote_coa = in6addr_any;
++ if (out.bind_coa)
++ arg->bind_coa = *out.bind_coa;
++ else
++ arg->bind_coa = in6addr_any;
++ arg->bu = (struct ip6_mh_binding_update *)(arg + 1);
++ arg->len = len;
++ arg->mh_opts = mh_opts;
++ arg->lft = lft;
++ arg->iif = iif;
++ memcpy(arg->bu, bu, len);
++ arg->flags = flags;
++ arg->statusp = &status;
++ clock_gettime(CLOCK_REALTIME, &tmp);
++ tssub(tmp, now, tmp);
++ dbg("time for generating PBA... %d'%d\n", tmp.tv_sec, tmp.tv_nsec);
++ pthread_mutex_lock(&bu_worker_mutex);
++ bu_worker_count++;
++ if (pthread_create(&worker, NULL, lma_recv_pbu_worker, arg)) {
++ free(arg);
++ if (--bu_worker_count == 0)
++ pthread_cond_signal(&cond);
++ } else {
++ if (!(arg->flags & HA_BU_F_THREAD_JOIN))
++ pthread_detach(worker);
++ }
++ pthread_mutex_unlock(&bu_worker_mutex);
++
++ if (arg->flags & HA_BU_F_THREAD_JOIN) {
++ pthread_join(worker, NULL);
++ return;
++ }
++
++
++}
++
+ static struct mh_handler ha_bu_handler = {
++#ifndef ENABLE_PMIPV6
+ .recv = ha_recv_bu,
++#else
++ .recv = lma_recv_pbu, /* PMIP HA = LMA */
++#endif /* ENABLE_PMIPV6 */
+ };
+
+ int ha_init(void)
+diff --git a/src/icmp6.c b/src/icmp6.c
+index 3695135..0602c05 100644
+--- a/src/icmp6.c
++++ b/src/icmp6.c
+@@ -46,6 +46,7 @@
+ enum {
+ ICMP6_DU = 0,
+ ICMP6_PP = 1,
++ ICMP6_RS = 2, /* ajout PMIP */
+ ICMP6_RA = 3,
+ ICMP6_NA = 4,
+ ICMP6_DRQ = 5,
+@@ -76,6 +77,8 @@ static inline int icmp6_type_map(uint8_t type)
+ return ICMP6_PP;
+ case ND_ROUTER_ADVERT:
+ return ICMP6_RA;
++ case ND_ROUTER_SOLICIT:
++ return ICMP6_RS;
+ case ND_NEIGHBOR_ADVERT:
+ return ICMP6_NA;
+ case MIP_HA_DISCOVERY_REQUEST:
+@@ -232,6 +235,8 @@ int icmp6_init(void)
+ ICMP6_FILTER_SETPASS(MIP_PREFIX_ADVERT, &filter);
+ ICMP6_FILTER_SETPASS(MIP_HA_DISCOVERY_REPLY, &filter);
+ ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
++ /* For PMIP: MAG is the MN */
++ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
+ }
+
+ if (setsockopt(icmp6_sock.fd, IPPROTO_ICMPV6, ICMP6_FILTER,
+diff --git a/src/mh.c b/src/mh.c
+index 60e345e..21916f8 100644
+--- a/src/mh.c
++++ b/src/mh.c
+@@ -44,6 +44,8 @@
+ #endif
+
+ #include "mipv6.h"
++#include "ha.h"
++#include "mn.h"
+ #include "xfrm.h"
+ #include "mh.h"
+ #include "util.h"
+@@ -53,6 +55,7 @@
+ #include "keygen.h"
+ #include "prefix.h"
+ #include "statistics.h"
++#include "ndisc.h"
+
+ #define MH_DEBUG_LEVEL 1
+
+@@ -78,6 +81,15 @@ int mh_opts_dup_ok[] = {
+ 0, /* Nonce Index */
+ 0, /* Binding Auth Data */
+ 1, /* Mobile Network Prefix */
++ 0,0,
++ 0, /* Mobile Node Identifier */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,
++ 1, /* Home Network Prefix option */
++ 0, /* Handoff Indicator option */
++ 0, /* Access Technology option */
++ 0, /* MN Link Layer Identifier option */
++ 0, /* Link Local Address option */
++ 0, /* Timestamp option */
+ };
+
+ #define __MH_SENTINEL (IP6_MH_TYPE_MAX + 1)
+@@ -374,6 +386,165 @@ int mh_create_opt_auth_data(struct iovec *iov)
+ return 0;
+ }
+
++int mh_create_opt_mn_identifier(struct iovec *iov, uint8_t *id)
++{
++ //TODO
++ struct ip6_mh_opt_mobile_node_id *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_mobile_node_id);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_mobile_node_id *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_MN_ID;
++ opt->ip6mnp_len = 7; // Envisager une taille variable, en fonction de la taille de l ID?
++ opt->ip6mnp_subtype = IP6_MNID_MHOPT_SUB_MAC;
++ for (int i = 0; i<6; i++)
++ {
++ opt->ip6mnp_mnid[i] = id[i];
++ // verifier si passage par un strcpy...
++ }
++ dbg("MN ID: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n",(opt->ip6mnp_mnid[0]&0xFF), (opt->ip6mnp_mnid[1]&0xFF), (opt->ip6mnp_mnid[2]&0xFF), (opt->ip6mnp_mnid[3]&0xFF), (opt->ip6mnp_mnid[4]&0xFF), (opt->ip6mnp_mnid[5]&0xFF));
++
++ return 0;
++}
++
++int mh_create_opt_home_prefix(struct iovec *iov, struct hnprefix *prefix)
++{
++ //TODO
++ struct ip6_mh_opt_hom_net_prefix *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_hom_net_prefix);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_hom_net_prefix *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_HOM_NET_PRFX;
++ opt->ip6mnp_len = 18;
++ opt->ip6mnp_prefix_len = prefix->plen;
++ opt->ip6mnp_prefix = prefix->prefix;
++
++ return 0;
++}
++
++int mh_create_opt_handoff_indicator(struct iovec *iov, uint8_t indicator)
++{
++ //TODO
++ struct ip6_mh_opt_handoff_indic *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_handoff_indic);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_handoff_indic *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_HANDOFF_INDIC;
++ opt->ip6mnp_len = 2;
++ opt->ip6mnp_handoff_indic = indicator;
++ return 0;
++}
++
++int mh_create_opt_timestamp(struct iovec *iov, struct timespec timestamp)
++{
++ //TODO: Problems with timestamp : clock_gettime(CLOCK_REALTIME, timestamp) to get a timestamp
++ struct ip6_mh_opt_timestamp *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_timestamp);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ MDBG("Timestamp len = (%d,%d), value = %ld, %ld \n ",
++ sizeof(timestamp.tv_sec),
++ sizeof(timestamp.tv_nsec),
++ timestamp.tv_sec, timestamp.tv_nsec);
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_timestamp *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_TIMESTAMP;
++ opt->ip6mnp_len = 8;
++ /* XXX: need to use fixed point format as RFC5213 said */
++ memcpy(&opt->ip6mnp_timestamp, &timestamp, 64);//maybe use a fonction...
++ return 0;
++}
++
++int mh_create_opt_link_layer_identifier(struct iovec *iov, uint8_t *llid)
++{
++ //TODO
++ struct ip6_mh_opt_link_layer_id *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_link_layer_id);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_link_layer_id *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_LINK_LAYER_ID;
++ opt->ip6mnp_len = 8; //2 + taille en octet de l identifiant
++ for (int i = 0; i<6; i++)
++ {
++ opt->ip6mnp_link_layer_addr[i] = llid[i];
++ }
++ return 0;
++}
++
++int mh_create_opt_access_tech_type(struct iovec *iov, uint8_t att)
++{
++ //TODO
++ struct ip6_mh_opt_access_tech_type *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_access_tech_type);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_access_tech_type *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_ACCESS_TECH_TYPE;
++ opt->ip6mnp_len = 2;
++ opt->ip6mnp_access_tech_type = att;
++ return 0;
++}
++
++int mh_create_opt_link_local_address(struct iovec *iov, struct in6_addr *addr)
++{
++ //TODO
++ struct ip6_mh_opt_link_local_addr *opt;
++ size_t optlen = sizeof(struct ip6_mh_opt_link_local_addr);
++
++ iov->iov_base = malloc(optlen);
++ iov->iov_len = optlen;
++
++ if (iov->iov_base == NULL)
++ return -ENOMEM;
++
++ memset(iov->iov_base, 0, iov->iov_len);
++ opt = (struct ip6_mh_opt_link_local_addr *)iov->iov_base;
++ opt->ip6mnp_type = IP6_MHOPT_LINK_LOCAL_ADD;
++ opt->ip6mnp_len = 16;
++ opt->ip6mnp_link_local_addr = *addr;
++
++ return 0;
++}
++
+ /* We can use these safely, since they are only read and never change */
+ static const uint8_t _pad1[1] = { 0x00 };
+ static const uint8_t _pad2[2] = { 0x01, 0x00 };
+@@ -490,6 +661,18 @@ static int mh_try_pad(const struct iovec *in, struct iovec *out, int count)
+ case IP6_MHOPT_MOB_NET_PRFX:
+ pad = optpad(8, 4, len); /* 8n+4 */
+ break;
++ case IP6_MHOPT_HOM_NET_PRFX:
++ pad = optpad(8, 4, len); /* 8n+4 */ /* Added PMIP options */
++ break;
++ case IP6_MHOPT_LINK_LAYER_ID:
++ pad = optpad(4, 6, len); /* 4n+6 TODO: check the value */
++ break;
++ case IP6_MHOPT_LINK_LOCAL_ADD:
++ pad = optpad(8, 4, len); /* 8n+6 */
++ break;
++ case IP6_MHOPT_TIMESTAMP:
++ pad = optpad(8, 2, len); /* 8n+2 */
++ break;
+ }
+ if (pad > 0) {
+ create_opt_pad(&out[n++], pad);
+@@ -745,6 +928,20 @@ static int mh_opt_len_chk(uint8_t type, int len)
+ return len != sizeof(struct ip6_mh_opt_auth_data);
+ case IP6_MHOPT_MOB_NET_PRFX:
+ return len != sizeof(struct ip6_mh_opt_mob_net_prefix);
++ case IP6_MHOPT_MN_ID:
++ return len != sizeof(struct ip6_mh_opt_mobile_node_id); /* Added PMIP options check */
++ case IP6_MHOPT_HOM_NET_PRFX:
++ return len != sizeof(struct ip6_mh_opt_hom_net_prefix);
++ case IP6_MHOPT_HANDOFF_INDIC:
++ return len != sizeof(struct ip6_mh_opt_handoff_indic);
++ case IP6_MHOPT_ACCESS_TECH_TYPE:
++ return len != sizeof(struct ip6_mh_opt_access_tech_type);
++ case IP6_MHOPT_LINK_LAYER_ID:
++ return len != sizeof(struct ip6_mh_opt_link_layer_id);
++ case IP6_MHOPT_LINK_LOCAL_ADD:
++ return len != sizeof(struct ip6_mh_opt_link_local_addr);
++ case IP6_MHOPT_TIMESTAMP:
++ return len != sizeof(struct ip6_mh_opt_timestamp);
+ case IP6_MHOPT_PADN:
+ default:
+ return 0;
+@@ -772,6 +969,7 @@ int mh_opt_parse(const struct ip6_mh *mh, ssize_t len, ssize_t offset,
+ ssize_t i = offset;
+ int ret = 0;
+ int bauth = 0;
++ mh_opts_dup_ok[38] = 1; /* Home Prefix: type = 26 = 0010 0110 = 38 in uint8_t */
+
+ memset(mh_opts, 0, sizeof(*mh_opts));
+ while (left > 0) {
+@@ -806,8 +1004,11 @@ int mh_opt_parse(const struct ip6_mh *mh, ssize_t len, ssize_t offset,
+ mh_opts->opts[op->ip6mhopt_type] = i;
+ else if (mh_opts_dup_ok[op->ip6mhopt_type])
+ mh_opts->opts_end[op->ip6mhopt_type] = i;
+- else
++ else {
++ dbg("Option type %d non allowed to be duplicated",op->ip6mhopt_type );
+ return -EINVAL;
++ }
++
+ ret++;
+ }
+ left -= op->ip6mhopt_len + 2;
+@@ -1027,6 +1228,343 @@ void mh_send_ba(const struct in6_addr_bundle *addrs, uint8_t status,
+ statistics_inc(&mipl_stat, MIPL_STATISTICS_OUT_BA);
+ }
+
++int mh_send_pba(const struct in6_addr_bundle *addrs, uint8_t status,
++ uint8_t flags, uint16_t sequence,
++ const struct timespec *lifetime, const uint8_t *key, int iif, struct ha_recv_pbu_args *arg)
++{
++ int iovlen = 1;
++ struct ip6_mh_binding_ack *ba;
++ struct iovec mh_vec[IP6_MHOPT_MAX];
++
++ MDBG("status %d\n", status);
++
++ ba = mh_create(mh_vec, IP6_MH_TYPE_BACK);
++ if (!ba)
++ return -1;
++
++ ba->ip6mhba_status = status;
++ ba->ip6mhba_flags = flags;
++ ba->ip6mhba_seqno = htons(sequence);
++ ba->ip6mhba_lifetime = htons(lifetime->tv_sec >> 2);
++
++ if (status < IP6_MH_BAS_UNSPECIFIED && !conf.NonVolatileBindingCache) {
++ struct timespec refresh;
++ tsclear(refresh);
++ if (conf.pmgr.use_bradv(addrs->dst, addrs->bind_coa,
++ addrs->src, lifetime, &refresh) &&
++ tsbefore(*lifetime, refresh))
++ mh_create_opt_refresh_advice(&mh_vec[iovlen++],
++ refresh.tv_sec);
++ }
++ if (key)
++ mh_create_opt_auth_data(&mh_vec[iovlen++]);
++
++ /* create the options for PMIP */
++ //First, adding MN id option
++ dbg("bule mnID option: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n",(arg->mnId[0]&0xFF), (arg->mnId[1]&0xFF), (arg->mnId[2]&0xFF), (arg->mnId[3]&0xFF), (arg->mnId[4]&0xFF), (arg->mnId[5]&0xFF));
++
++ if (mh_create_opt_mn_identifier(&mh_vec[iovlen++], arg->mnId)) {
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++
++ //Second, check if the pbu have prefix information
++ if (arg->prefix == NULL) {
++ //create option with the value 0
++ struct hnprefix home_prefix;
++ memset(&home_prefix, 0, sizeof(struct hnprefix));
++ if (mh_create_opt_home_prefix(&mh_vec[iovlen++], &home_prefix)){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++ }
++ else {
++ //create an option for each prefix
++ int i = 0;
++ struct hnprefix home_prefix;
++ while(arg->prefix)
++ {
++ if (!IN6_IS_ADDR_UNSPECIFIED(&(arg->prefix->Prefix))){
++ home_prefix.plen = arg->prefix->PrefixLen;
++ home_prefix.prefix = arg->prefix->Prefix;
++ if (mh_create_opt_home_prefix(&mh_vec[iovlen++], &home_prefix)){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++ dbg("create option for prefix: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&home_prefix.prefix));
++ i++;
++ }
++ arg->prefix = arg->prefix->next;
++ }
++ if (i == 0) {
++ memset(&home_prefix, 0, sizeof(struct hnprefix));
++ if (mh_create_opt_home_prefix(&mh_vec[iovlen++], &home_prefix)){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++ }
++ }
++
++ //Next, create the Hand Off indicator option, depending on the value of the indicator in the bule
++ if (mh_create_opt_handoff_indicator(&mh_vec[iovlen++], arg->handoffIndicator)){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++
++ //Create the access technology type option (mandatory)
++ if (mh_create_opt_access_tech_type(&mh_vec[iovlen++], arg->techType)){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++
++ //Timestamp option depending of the value of the configuration variable
++ if (arg->timestamp){
++ if (mh_create_opt_timestamp(&mh_vec[iovlen++], *arg->timestamp )){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++ }
++
++ //Link layer identifier if known
++ if ( !(arg->linkLayerId[0] == 0 && arg->linkLayerId[1] == 0 && arg->linkLayerId[2] == 0 && arg->linkLayerId[1] == 0
++ && arg->linkLayerId[3] == 0 && arg->linkLayerId[4] == 0 && arg->linkLayerId[5] == 0)){//TODO check the ALL_ZERO value
++ if (mh_create_opt_link_layer_identifier(&mh_vec[iovlen++], arg->linkLayerId )){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++ }
++
++ //Link local option if the configuration variable FixedMAGLinkLocalAddressOnAllAccessLinks is egal to AllZero
++ if (arg->linkLocalAddr != NULL){//TODO check the test method IN6_IS_ADDR_UNSPECIFIED(addr)
++ dbg("create Link Local Address option\n");
++ if (mh_create_opt_link_local_address(&mh_vec[iovlen++], arg->linkLocalAddr )){
++ free_iov_data(mh_vec, iovlen);
++ return -ENOMEM;
++ }
++ }
++
++ mh_send(addrs, mh_vec, iovlen, key, iif);
++ free_iov_data(mh_vec, iovlen);
++
++ return 1;
++}
++
++int mh_pbu_parse(struct ip6_mh_binding_update *bu, ssize_t len,
++ const struct in6_addr_bundle *in_addrs,
++ struct in6_addr_bundle *out_addrs,
++ struct mh_options *mh_opts,
++ struct timespec *lifetime, uint8_t *key, struct ha_recv_pbu_args *arg)
++{
++ struct in6_addr *our_addr, *peer_addr, *remote_coa;
++ struct ip6_mh_opt_altcoa *alt_coa;
++ struct ip6_mh_opt_mobile_node_id *mnID;
++ struct ip6_mh_opt_hom_net_prefix *homePrefix;
++ struct ip6_mh_opt_handoff_indic *handoffInd;
++ struct ip6_mh_opt_access_tech_type *accTech;
++ struct ip6_mh_opt_link_layer_id *llayerId;
++ struct ip6_mh_opt_link_local_addr *llocalAddr;
++ struct ip6_mh_opt_timestamp *timestamp;
++ struct ip6_mh_opt_nonce_index *non_ind;
++ struct ip6_mh_opt_auth_data *bauth;
++ uint16_t bu_flags;
++ int ret;
++
++ MDBG("Proxy Binding Update Received\n");
++ if (len < sizeof(struct ip6_mh_binding_update) ||
++ mh_opt_parse(&bu->ip6mhbu_hdr, len,
++ sizeof(struct ip6_mh_binding_update), mh_opts) < 0)
++ return -1;
++
++ peer_addr = in_addrs->src;
++ if (!in6_is_addr_routable_unicast(peer_addr))
++ return -1;
++
++ out_addrs->src = in_addrs->dst;
++ out_addrs->dst = in_addrs->src;
++ remote_coa = in_addrs->remote_coa;/* NULL with PMIP because no Home Address Option */
++ if (remote_coa && !IN6_ARE_ADDR_EQUAL(remote_coa, peer_addr))
++ out_addrs->remote_coa = remote_coa;
++ else
++ out_addrs->remote_coa = NULL;
++
++ alt_coa = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_ALTCOA);
++ if (alt_coa)
++ out_addrs->bind_coa = &alt_coa->ip6moa_addr;
++ else
++ out_addrs->bind_coa = in_addrs->remote_coa;
++
++ /* getting the MN Identifier of the MN */
++ mnID = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_MN_ID);
++ if (mnID == NULL || mnID->ip6mnp_subtype != IP6_MNID_MHOPT_SUB_MAC) /* Only ID as MAC address */
++ return IP6_MH_BAS_MISSING_MN_IDENTIFIER_OPTION;
++ else {
++ for (int i = 0; i<6; i++)
++ {
++ arg->mnId[i] = mnID->ip6mnp_mnid[i];
++ }
++ }
++
++
++ /* getting the home prefixes for the MN */
++ dbg("cream: getting the home prefixes\n");
++ homePrefix = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_HOM_NET_PRFX);
++ if (!homePrefix)
++ return IP6_MH_BAS_MISSING_HOME_NETWORK_PREFIX_OPTION;
++ /* getting other prefixes */
++ struct AdvPrefix *tempo;
++ arg->prefix = malloc(sizeof(struct AdvPrefix));
++ memset(arg->prefix, 0, sizeof(struct AdvPrefix));
++ tempo = arg->prefix;
++ int doPrefixAssignment = 0;
++ while (homePrefix)
++ {
++ /* TODO: do something with the prefixes */
++ if (IN6_IS_ADDR_UNSPECIFIED(&homePrefix->ip6mnp_prefix)){
++ free(tempo);
++ doPrefixAssignment = 1;
++ break;
++ }
++ tempo->Prefix = homePrefix->ip6mnp_prefix;
++ tempo->PrefixLen = homePrefix->ip6mnp_prefix_len;
++ tempo = tempo->next;
++ tempo = malloc(sizeof(struct AdvPrefix));
++ homePrefix = mh_opt_next(&bu->ip6mhbu_hdr, mh_opts, homePrefix);
++ }
++ if (doPrefixAssignment){
++ arg->prefix = getMNPrefix(arg->mnId); /* we get the prefix from the policy store */
++ if (!arg->prefix)
++ return IP6_MH_BAS_INSUFFICIENT;
++ }
++ dbg("Prefix assigned: %x:%x:%x:%x:%x:%x:%x:%x/%u\n",
++ NIP6ADDR(&arg->prefix->Prefix), arg->prefix->PrefixLen);
++ /* getting the HandOff indicator */
++ handoffInd = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_HANDOFF_INDIC);
++ if (!handoffInd) {
++ dbg("cream: No HandOff Indicator\n");
++ return IP6_MH_BAS_MISSING_HANDOFF_INDICATOR_OPTION;
++ }
++ arg->handoffIndicator = handoffInd->ip6mnp_handoff_indic;
++
++ /* getting the Access Technology type */
++ accTech = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_ACCESS_TECH_TYPE);
++ if (!accTech) {
++ dbg("cream: No Access Tech\n");
++ return IP6_MH_BAS_MISSING_ACCESS_TECH_TYPE_OPTION;
++ }
++ arg->techType = accTech->ip6mnp_access_tech_type;
++
++ /* getting the Link Layer Identifier */
++ llayerId = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_LINK_LAYER_ID);
++ if (llayerId){
++ dbg("cream: llayerId\n");
++ for ( int i = 0; i<6; i++){
++ arg->linkLayerId[i] = llayerId->ip6mnp_link_layer_addr[i];
++ }
++ }
++
++
++
++ /* getting the Link Local Address */
++ llocalAddr = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_LINK_LOCAL_ADD);
++ if (llocalAddr) {
++ dbg("cream: llocalAddr\n");
++ //*arg->linkLocalAddr = llocalAddr->ip6mnp_link_local_addr;
++ }
++ else {
++ dbg("cream: No llocalAddr\n");
++ arg->linkLocalAddr = NULL;
++ }
++ /* getting the timestamp */
++ timestamp = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_TIMESTAMP);
++ if (timestamp){
++ dbg("timestamp option: %d\n", timestamp->ip6mnp_timestamp);
++ if (arg->timestamp == NULL){
++ arg->timestamp = malloc(sizeof(struct timespec));
++ memset(arg->timestamp, 0, sizeof(struct timespec));
++ }
++
++ memcpy(arg->timestamp, &timestamp->ip6mnp_timestamp, sizeof(timestamp->ip6mnp_timestamp));
++ /* Check timestamp validity */
++ if (!conf.MobileNodeGeneratedTimestampInUse){
++ struct timespec now, tmp;
++ clock_gettime(CLOCK_REALTIME, &now);
++ tssub(now, conf.TimestampValidityWindow, tmp);
++ if (tsbefore(tmp, *arg->timestamp)){
++ /* tmp more recent than the timestamp of the pbu */
++ dbg("timestamp local: %d\nTimestamp validity window: %d\n",
++ tstodsec(now), tstodsec(conf.TimestampValidityWindow));
++ *arg->timestamp = now;
++ return IP6_MH_BAS_TIMESTAMP_MISMATCH;
++ }
++ }
++ }
++ else
++ arg->timestamp = NULL;
++
++
++
++ our_addr = in_addrs->dst;
++ dbg("lifetime du pbu: %d\n", ntohs(bu->ip6mhbu_lifetime));
++ dbg("cream lifetime du pbu");
++ tssetsec(*lifetime, ntohs(bu->ip6mhbu_lifetime) << 2);
++ dbg("lifetime: %d\n", tstodsec(*lifetime));
++ /* Not with PMIP, always a binding */
++// tsclear(*lifetime);
++// if (out_addrs->bind_coa) {
++// if (!in6_is_addr_routable_unicast(out_addrs->bind_coa))
++// return -1;
++// if (!IN6_ARE_ADDR_EQUAL(out_addrs->bind_coa, peer_addr)) {
++// /* check that there is no circular reference */
++// if (bce_exists(our_addr, out_addrs->bind_coa))
++// return -1;
++// tssetsec(*lifetime, ntohs(bu->ip6mhbu_lifetime) << 2);
++// }
++// }
++// dbg("lifetime: %d\n", tstodsec(*lifetime));
++ /* Use Home address of MN for calculating BU and BA auth data
++ * for deregs. */
++ if (!out_addrs->bind_coa)
++ out_addrs->bind_coa = in_addrs->src;
++
++ bu_flags = bu->ip6mhbu_flags;
++
++ out_addrs->local_coa = NULL;
++
++ non_ind = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_NONCEID);
++
++ if (bu_flags & IP6_MH_BU_HOME){
++ dbg("Parsing OK!\n");
++ return non_ind ? -1 : 0;
++ }
++
++ if (!non_ind)
++ return -1;
++
++ MDBG("src %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(peer_addr));
++ MDBG("coa %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(out_addrs->bind_coa));
++
++ if (tsisset(*lifetime))
++ ret = rr_cn_calc_Kbm(ntohs(non_ind->ip6moni_home_nonce),
++ ntohs(non_ind->ip6moni_coa_nonce),
++ peer_addr, out_addrs->bind_coa, key);
++ else /* Only use home nonce and address for dereg. */
++ ret = rr_cn_calc_Kbm(ntohs(non_ind->ip6moni_home_nonce), 0,
++ peer_addr, NULL, key);
++ if (ret)
++ return ret;
++
++ bauth = mh_opt(&bu->ip6mhbu_hdr, mh_opts, IP6_MHOPT_BAUTH);
++ if (!bauth)
++ return -1;
++ /* Authenticator is calculated with MH checksum set to 0 */
++ bu->ip6mhbu_hdr.ip6mh_cksum = 0;
++ if (mh_verify_auth_data(bu, len, bauth,
++ out_addrs->bind_coa, our_addr, key) < 0)
++ return -1;
++ return IP6_MH_BAS_ACCEPTED;
++}
++
+ /* Main BU parser, used by both HA (H flag set) and CN (H flag not set).
+ * Additional specific checks are performed for HA and CN via two
+ * specific helpers: ha_bu_check() (ha.c) and cn_bu_check() (cn.c). */
+diff --git a/src/mh.h b/src/mh.h
+index 8389329..64aab84 100644
+--- a/src/mh.h
++++ b/src/mh.h
+@@ -6,11 +6,13 @@
+ #include <netinet/in.h>
+ #include <netinet/ip6mh.h>
+
++#include "conf.h"
++
+ #define MIP6_SEQ_GT(x,y) ((short int)(((uint16_t)(x)) - ((uint16_t)(y))) > 0)
+
+ /* If new types or options appear, these should be updated. */
+ #define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR
+-#define IP6_MHOPT_MAX IP6_MHOPT_MOB_NET_PRFX
++#define IP6_MHOPT_MAX IP6_MHOPT_TIMESTAMP //PMIP update: before = IP6_MHOPT_BAUTH
+
+ struct in6_addr_bundle {
+ struct in6_addr *src;
+@@ -25,6 +27,30 @@ struct mh_options {
+ ssize_t opts_end[IP6_MHOPT_MAX + 1];
+ };
+
++struct ha_recv_pbu_args {
++ struct list_head list;
++ struct in6_addr src;
++ struct in6_addr dst;
++ struct in6_addr remote_coa;
++ struct in6_addr bind_coa;
++ struct ip6_mh_binding_update *bu;
++ ssize_t len;
++ struct mh_options mh_opts;
++ struct AdvPrefix *prefix;
++ struct timespec *timestamp;
++ int handoffIndicator;
++ int techType;
++ uint8_t mnId[6];
++ struct in6_addr *linkLocalAddr;
++ uint8_t linkLayerId[6];
++ struct timespec lft;
++ int iif;
++ int flags; /* HA_BU_F_XXX */
++ int *statusp; /* 0 or more than 0 is BA status, otherwise error */
++};
++
++
++
+ struct mh_handler {
+ struct mh_handler *next;
+ void (* recv)(const struct ip6_mh *mh, ssize_t len,
+@@ -53,6 +79,18 @@ static inline void mh_send_ba_err(const struct in6_addr_bundle *addrs,
+ mh_send_ba(addrs, status, flags, seqno, &zero, key, iif);
+ }
+
++int mh_send_pba(const struct in6_addr_bundle *addrs, uint8_t status,
++ uint8_t flags, uint16_t sequence,
++ const struct timespec *lifetime, const uint8_t *key, int iif, struct ha_recv_pbu_args *arg);
++
++static inline void mh_send_pba_err(const struct in6_addr_bundle *addrs,
++ uint8_t status, uint8_t flags,
++ uint16_t seqno, const uint8_t *key, int iif, struct ha_recv_pbu_args *arg)
++{
++ struct timespec zero = { 0, 0 };
++ mh_send_pba(addrs, status, flags, seqno, &zero, key, iif, arg);
++}
++
+ void mh_send_be(struct in6_addr *dst,
+ struct in6_addr *hoa,
+ struct in6_addr *src,
+@@ -78,6 +116,19 @@ struct list_head;
+
+ int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
+ struct list_head *mnps);
++int mh_create_opt_mn_identifier(struct iovec *iov, uint8_t *id);
++
++int mh_create_opt_home_prefix(struct iovec *iov, struct hnprefix *prefix);
++
++int mh_create_opt_handoff_indicator(struct iovec *iov, uint8_t indicator);
++
++int mh_create_opt_timestamp(struct iovec *iov, struct timespec timestamp);
++
++int mh_create_opt_link_layer_identifier(struct iovec *iov, uint8_t *llid);
++
++int mh_create_opt_access_tech_type(struct iovec *iov, uint8_t att);
++
++int mh_create_opt_link_local_address(struct iovec *iov, struct in6_addr *addr);
+
+ static inline void *mh_opt(const struct ip6_mh *mh,
+ const struct mh_options *mh_opts, uint8_t type)
+@@ -125,6 +176,12 @@ int mh_bu_parse(struct ip6_mh_binding_update *bu, ssize_t len,
+ struct mh_options *mh_opts,
+ struct timespec *lifetime);
+
++int mh_pbu_parse(struct ip6_mh_binding_update *bu, ssize_t len,
++ const struct in6_addr_bundle *in_addrs,
++ struct in6_addr_bundle *out_addrs,
++ struct mh_options *mh_opts,
++ struct timespec *lifetime, uint8_t *key, struct ha_recv_pbu_args *arg);
++
+ void mh_handler_reg(uint8_t type, struct mh_handler *handler);
+ void mh_handler_dereg(uint8_t type, struct mh_handler *handler);
+
+diff --git a/src/mn.c b/src/mn.c
+index 092cfcb..160a7be 100644
+--- a/src/mn.c
++++ b/src/mn.c
+@@ -34,7 +34,8 @@
+ #include <syslog.h>
+ #include <errno.h>
+ #include <time.h>
+-#include <unistd.h>
++#include <unistd.h>
++#include <arpa/inet.h>
+
+ #include <netinet/icmp6.h>
+ #include <netinet/ip6mh.h>
+@@ -64,9 +65,10 @@
+ #include "keygen.h"
+ #include "dhaad_mn.h"
+ #include "ipsec.h"
++#include "bul.h"
+ #include "statistics.h"
+
+-#define MN_DEBUG_LEVEL 1
++#define MN_DEBUG_LEVEL 2
+
+ #if MN_DEBUG_LEVEL >= 1
+ #define MDBG dbg
+@@ -98,7 +100,12 @@ const struct timespec min_valid_bu_lifetime_ts =
+ static int pending_bas = 0;
+
+ static void mn_send_home_bu(struct home_addr_info *hai);
++static int mag_send_pbu_msg(struct bulentry *bule);
+ static int mn_ext_tunnel_ops(int request, int old_if, int new_if, void *data);
++static int process_first_home_pbu(struct bulentry *bule,
++ struct home_addr_info *hai,
++ struct timespec *lifetime, struct AdvPrefix *prefix, uint8_t *mnID);
++static void pbu_resend(struct tq_elem *tqe);
+
+ static int mn_block_rule_del(struct home_addr_info *hai)
+ {
+@@ -119,6 +126,26 @@ static int mn_block_rule_del(struct home_addr_info *hai)
+ return ret;
+ }
+
++struct pmipMobileNodeEntry *getMNProfile (uint8_t *mnID)
++{
++ struct list_head *l;
++ int j;
++ list_for_each(l, &conf.pmipMobileNodes) {
++ struct pmipMobileNodeEntry *npmipmnentry;
++ npmipmnentry = list_entry(l, struct pmipMobileNodeEntry, list);
++ if (!npmipmnentry)
++ continue;
++ j = 0;
++ for ( int i = 0; i<6 ; i++){
++ if (npmipmnentry->mnIdentifier[i] != mnID[i])
++ j = 1;
++ }
++ if (j == 0)
++ return npmipmnentry;
++ }
++ return NULL;
++}
++
+ static int mn_block_rule_add(struct home_addr_info *hai)
+ {
+ int ret = -1;
+@@ -234,6 +261,234 @@ static void mn_rr_check_entry(struct tq_elem *tqe)
+ pthread_rwlock_unlock(&mn_lock);
+ }
+
++static int addHomePrefix (struct AdvPrefix *prefixList, struct in6_addr *prefix, uint8_t plen)
++{
++ memset(prefixList ,0 , sizeof(struct AdvPrefix));
++// prefixList->next = malloc(sizeof(struct AdvPrefix));;
++ dbg("Prefix added: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(prefix));
++ prefixList->Prefix = *prefix;
++ prefixList->PrefixLen = plen;
++ return 0;
++}
++
++static struct AdvPrefix *getHomePrefixesFromProfile (struct pmipMobileNodeEntry *mnProfil)
++{
++ struct AdvPrefix *prefix;
++ struct AdvPrefix *tempo;
++ int count = 0;
++
++ if (!IN6_IS_ADDR_UNSPECIFIED(&mnProfil->home_network_prefix1)){
++ prefix = malloc(sizeof(struct AdvPrefix));
++ tempo = prefix;
++ addHomePrefix (tempo, &mnProfil->home_network_prefix1, (uint8_t) mnProfil->home_network_plen1);
++ tempo = tempo->next;
++ count++;
++ }
++ if (!IN6_IS_ADDR_UNSPECIFIED(&mnProfil->home_network_prefix2)){
++ if (count == 0){
++ prefix = malloc(sizeof(struct AdvPrefix));
++ tempo = prefix;
++ }
++ else {
++ tempo = malloc(sizeof(struct AdvPrefix));
++ }
++ addHomePrefix (tempo, &mnProfil->home_network_prefix2, (uint8_t) mnProfil->home_network_plen2);
++ tempo = tempo->next;
++ count++;
++ }
++ if (!IN6_IS_ADDR_UNSPECIFIED(&mnProfil->home_network_prefix3)){
++ if (count == 0){
++ prefix = malloc(sizeof(struct AdvPrefix));
++ tempo = prefix;
++ }
++ else {
++ tempo = malloc(sizeof(struct AdvPrefix));
++ }
++ tempo = malloc(sizeof(struct AdvPrefix));
++ addHomePrefix (tempo, &mnProfil->home_network_prefix3, (uint8_t) mnProfil->home_network_plen3);
++ tempo = tempo->next;
++ count++;
++ }
++ tempo = NULL;
++ if (!count)
++ return NULL;
++
++ return prefix;
++}
++
++struct AdvPrefix *getMNPrefix (uint8_t *mnID)
++{
++ struct pmipMobileNodeEntry *profil;
++ profil = getMNProfile(mnID);
++ if (!profil){
++ return NULL;
++ }
++ return getHomePrefixesFromProfile(profil);
++
++}
++
++/* adding PMIP handler for router sollicitation -> MAG */
++static void mag_recv_router_sol(const struct icmp6_hdr *ih, ssize_t len,
++ const struct in6_addr *src,
++ const struct in6_addr *dst,
++ int iif, int hoplimit)
++{
++#ifndef ENABLE_PMIPV6
++ return;
++#endif /* ENABLE_PMIPV6 */
++ dbg("Receiving Router solicitation from %x:%x:%x:%x:%x:%x:%x:%x to %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(src), NIP6ADDR(dst));
++ /*
++ * TODO:
++ * 1. Identify the node
++ * 2. Check if the node is allowed for PMIP
++ * 3. Create a BULE for the MN if one doesn't already exists
++ * 4. Send PBU
++ */
++ struct nd_router_solicit *rs = (struct nd_router_solicit *)ih;
++ int optlen;
++ uint8_t *opt;
++ uint8_t mnID[6];
++ struct bulentry *e = NULL;
++
++ /* validity checks */
++ if (hoplimit < 255 || !IN6_IS_ADDR_LINKLOCAL(src) ||
++ ih->icmp6_code != 0 || len < sizeof(struct nd_router_solicit))
++ return;
++
++ MDBG2("received RS from %x:%x:%x:%x:%x:%x:%x:%x on iface %d\n",
++ NIP6ADDR(src), iif);
++
++ optlen = len - sizeof(struct nd_router_solicit);
++ opt = (uint8_t *)(rs + 1);
++ /*We take the MN Identifier from the source link layer option */
++ while (optlen > 1) {
++ int olen = opt[1] << 3;
++
++ if (olen > optlen || olen == 0)
++ break;
++
++ if (opt[0] == ND_OPT_SOURCE_LINKADDR) {
++ memset(mnID, 0, 6);
++ for (int i = 2; i< olen;i++){
++ mnID[i-2] = opt[i];
++ }
++ break;
++ }
++ optlen -= olen;
++ opt += olen;
++ }
++ if (mnID == NULL){
++ return;
++ }
++ dbg("mnID requesting PMIP: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", (mnID[0]&0xFF), (mnID[1]&0xFF),
++ (mnID[2]&0xFF), (mnID[3]&0xFF) ,(mnID[4]&0xFF), (mnID[5]&0xFF));
++ /* search in the policy store the MN identifier */
++ struct pmipMobileNodeEntry *mnProfil;
++ mnProfil = getMNProfile(mnID);
++ if (mnProfil == NULL){
++ dbg("MN with MN Identifier %s not authorized for PMIP (pas de profil)\n", mnID);
++ return;
++ }
++
++ if (!mnProfil->pmip_enabled){
++ dbg("MN with MN Identifier %s not authorized for PMIP (PMIP disabled)\n", mnID);
++ return;
++ }
++
++ struct home_addr_info *hai;
++ hai = malloc(sizeof(struct home_addr_info));
++
++ hai->if_home = iif;
++ hai->ha_addr = mnProfil->lma_address;
++ /* TODO: Initialiser les informations concernant le MAG:
++ * hoa = addresse locale de la MAG sur le lien MN/MAG
++ * COA = global address and iif of the egress interface (link LMA/MAG)
++ */
++ struct timespec lifetime;
++ if (tsisset(mnProfil->homeNetworkPrefixLifetime)){
++ struct timespec maxBindingLft;
++ tsset(maxBindingLft, MAX_BINDING_LIFETIME, 0);
++ lifetime = tsafter(mnProfil->homeNetworkPrefixLifetime, maxBindingLft) ? mnProfil->homeNetworkPrefixLifetime : maxBindingLft;
++ }
++ else
++ tsset(lifetime, 420, 0);/*temporary, need to be fixed to a better value, dynamicaly assigned... */
++ dbg("lifetime value: %d", lifetime.tv_sec);
++ /* Get the Home prefixes in policy store */
++ struct AdvPrefix *prefix = NULL;
++ prefix = getHomePrefixesFromProfile(mnProfil);
++
++ /* addresse source et interface source pour envoyer le pbu */
++ hai->primary_coa.addr = conf.MAGEgressGlobalAddress;
++ hai->primary_coa.iif = conf.MAGEgressInterfaceIndex;
++
++ /* MN is allowed to use PMIP */
++ /* Check the existence of a BULE */
++ e = bul_get(NULL, &prefix->Prefix, &mnProfil->lma_address);/* assuming there is one prefix... and we use only the first one... */
++ if (e == NULL)
++ {
++ /* No existing BULE, creation of a new one */
++ e = create_bule(&prefix->Prefix, &mnProfil->lma_address);
++ if (e == NULL)
++ return;
++ if (process_first_home_pbu(e, hai, &lifetime, prefix, mnID) < 0)
++ {
++ bul_delete(e);
++ return;
++ }
++ if (!IN6_IS_ADDR_UNSPECIFIED(src))
++ e->mnLinkLocalAddress = *src;
++ else {
++ char src_addr[50];
++ memset(src_addr, 0, 50);
++ strncpy(src_addr, "ff02::1",50);
++ inet_pton(AF_INET6, src_addr, &e->mnLinkLocalAddress);/* all-nodes multicast address, for sending the RA */
++ }
++
++ if(bul_add(e) < 0) {
++ bul_delete(e);
++ return;
++ }
++ }
++ else {
++ /* Update the existing BULE */
++ e->delay = conf.InitialBindackTimeoutReReg_ts;
++ e->callback = pbu_resend;
++ clock_gettime(CLOCK_REALTIME, &e->lastsent);
++ e->lifetime = lifetime;
++ e->seq++;
++ }
++ /* Creation of the Bule */
++// struct in6_addr *mnIDip;
++// mnIDip = transf_mnID_ip6addr(mnProfil->mnIdentifier);
++// dbg("mnID IPv6 format: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(mnIDip));
++// e = create_bule(mnIDip, &mnProfil->lma_address);
++// if (e == NULL)
++// return;
++// if (process_first_home_pbu(e, hai, &lifetime, prefix) < 0 ||
++// bul_add(e) < 0) {
++// bul_delete(e);
++// return;
++// }
++
++ /* Sending PBU */
++ e->do_send_bu = 1;
++ mag_send_pbu_msg(e);
++ bul_update_timer(e);
++
++
++}
++
++static struct icmp6_handler mag_router_sol_handler = {
++ .recv = mag_recv_router_sol,
++};
++
++/* PMIP function for getting the MN Identifier */
++static uint8_t getMNIdentifier (void){
++ //TODO
++}
++
++
+ static void mn_recv_param_prob(const struct icmp6_hdr *ih, ssize_t len,
+ __attribute__ ((unused)) const struct in6_addr *src,
+ const struct in6_addr *dst,
+@@ -307,6 +562,152 @@ static struct icmp6_handler mn_param_prob_handler = {
+ .recv = mn_recv_param_prob,
+ };
+
++static int mag_send_pbu_msg(struct bulentry *bule)
++{
++ /*TODO Create the Proxy Binding Update
++ * Need the following options:
++ * 1. Mobile Node Identifier option
++ * 2. Home Network prefix option
++ * 3. Hand Off Indicator option
++ * 4. Timestamp opiton
++ * 5. Link Layer Identifier option
++ * 6. Access technology type option
++ * 7. Link local address option if conf.FixedMAGLinkLocalAddressOnAllAccessLinks is = to All_ZERO
++ */
++
++ struct ip6_mh_binding_update *bu;
++
++ struct iovec iov[IP6_MHOPT_MAX+1];
++ int iov_ind = 0;
++ int ret = -ENOMEM;
++ uint8_t *bind_key = NULL;
++ struct in6_addr_bundle addrs;
++
++ memset(iov, 0, IP6_MHOPT_MAX+1);
++ bu = mh_create(&iov[iov_ind++], IP6_MH_TYPE_BU);
++ if (!bu)
++ return -ENOMEM;
++
++ bu->ip6mhbu_seqno = htons(bule->seq);
++ bu->ip6mhbu_flags = bule->flags;
++ dbg("flags: %x\n", bu->ip6mhbu_flags);
++ bu->ip6mhbu_lifetime = htons(bule->lifetime.tv_sec >> 2);
++
++ //First, adding MN id option
++ dbg("bule mnID option: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n",(bule->mnIdentifier[0]&0xFF), (bule->mnIdentifier[1]&0xFF), (bule->mnIdentifier[2]&0xFF), (bule->mnIdentifier[3]&0xFF), (bule->mnIdentifier[4]&0xFF), (bule->mnIdentifier[5]&0xFF));
++
++ if (mh_create_opt_mn_identifier(&iov[iov_ind++], bule->mnIdentifier)) {
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++
++ //Second, check if the bule have prefix information
++ if (bule->prefix == NULL) {
++ //create option with the value 0
++ struct hnprefix home_prefix;
++ memset(&home_prefix, 0, sizeof(struct hnprefix));
++ if (mh_create_opt_home_prefix(&iov[iov_ind++], &home_prefix)){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++ dbg("PBU: No prefix assigned -> option HP NULL\n");
++ }
++ else {
++ //create an option for each prefix
++ int i = 0;
++ struct hnprefix home_prefix;
++ struct AdvPrefix *tempo;
++ tempo = bule->prefix;
++ while(tempo)
++ {
++ if (!IN6_IS_ADDR_UNSPECIFIED(&tempo->Prefix)){
++ home_prefix.plen = tempo->PrefixLen;
++ home_prefix.prefix = tempo->Prefix;
++ if (mh_create_opt_home_prefix(&iov[iov_ind++], &home_prefix)){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++ dbg("create option for prefix: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&home_prefix.prefix));
++ i++;
++ }
++ tempo = tempo->next;
++ }
++ if (i == 0) {
++ memset(&home_prefix, 0, sizeof(struct hnprefix));
++ if (mh_create_opt_home_prefix(&iov[iov_ind++], &home_prefix)){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++ }
++ }
++
++ //Next, create the Hand Off indicator option, depending on the value of the indicator in the bule
++ if (mh_create_opt_handoff_indicator(&iov[iov_ind++], bule->handoffIndicator)){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++
++ //Create the access technology type option (mandatory)
++ if (mh_create_opt_access_tech_type(&iov[iov_ind++], bule->accTechType)){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++
++ //Timestamp option depending of the value of the configuration variable
++ if (conf.TimestampBasedApproachInUse){
++ struct timespec timestamp;
++ clock_gettime(CLOCK_REALTIME, &timestamp);
++ if (mh_create_opt_timestamp(&iov[iov_ind++], timestamp)){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++ }
++
++ //Link layer identifier if known
++ if ( bule->linkLayerID != NULL){//TODO check the ALL_ZERO value
++ int llID = 0;
++ for (int i = 0; i<6; i++){
++ if (bule->linkLayerID[i] != 0){
++ llID = 1;
++ break;
++ }
++ }
++ if (llID && mh_create_opt_link_layer_identifier(&iov[iov_ind++], bule->linkLayerID )){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++ }
++
++ //Link local option if the configuration variable FixedMAGLinkLocalAddressOnAllAccessLinks is egal to AllZero
++ if (IN6_IS_ADDR_UNSPECIFIED(&conf.FixedMAGLinkLocalAddressOnAllAccessLinks)){//TODO check the test method IN6_IS_ADDR_UNSPECIFIED(addr)
++ dbg("create Link Local Address option\n");
++ if (mh_create_opt_link_local_address(&iov[iov_ind++], &bule->magLinkLocalAddress )){
++ free_iov_data(iov, iov_ind);
++ return -ENOMEM;
++ }
++ }
++
++ if (bule->flags & IP6_MH_BU_ACK)
++ bule->wait_ack = 1;
++ addrs.src = &bule->magGlobalEgressAddress;
++ addrs.dst = &bule->lmaIpAddr;
++ addrs.local_coa = &bule->coa;
++ addrs.remote_coa = NULL;
++ addrs.bind_coa = &bule->coa;
++
++ //TODO check the If_coa... interface on which the message is sent
++
++ ret = mh_send(&addrs, iov, iov_ind, bind_key, bule->if_coa);
++
++ if (ret <= 0)
++ MDBG("mh_send failed ret: %d\n", ret);
++
++ free_iov_data(iov, iov_ind);
++
++ return ret;
++
++}
++
+ static int mn_send_bu_msg(struct bulentry *bule)
+ {
+ struct ip6_mh_binding_update *bu;
+@@ -438,6 +839,121 @@ static int mn_get_ro_lifetime(struct home_addr_info *hai,
+ return 1;
+ }
+
++int dereg_mn_forwarding(struct bulentry *e){
++ dbg("Deregistering MN:\n");
++ dbg("MN prefix: %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(&e->prefix->Prefix));
++ e->delForwarding = 0;
++ if (IN6_IS_ADDR_UNSPECIFIED(&e->lmaIpAddr)) {
++ dbg("Error with the LMA address");
++ goto err;
++ } else {
++ MDBG("LMA address %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(&e->lmaIpAddr));
++ }
++
++ if (route_del(e->tunnelIfID, RT6_TABLE_MAIN,
++ IP6_RT_PRIO_MIP6_FWD,
++ &e->prefix->Prefix, e->prefix->PrefixLen, &in6addr_any, 0,
++ NULL) < 0) {
++ MDBG("failed to delete forwarding from MN\n");
++ goto err;
++ }
++
++ /* delete the tunnel &e->magGlobalEgressAddress, &e->lmaIpAddr */
++ if (tunnel_del(e->tunnelIfID, NULL, NULL) < 0){
++ dbg("Tunnel deletion failed, does the tunnel exist?\n");
++ goto err;
++ }
++
++ if (route_del(e->ifId, RT6_TABLE_MAIN,
++ IP6_RT_PRIO_MIP6_FWD,
++ NULL, 0, &e->prefix->Prefix, e->prefix->PrefixLen,
++ NULL) < 0) {
++ MDBG("failed to delete forwarding for MN\n");
++ goto err;
++ }
++
++ if (rule_del(NULL, RT6_TABLE_MIP6,
++ IP6_RULE_PRIO_MIP6_HOA_OUT, RTN_UNICAST,
++ &e->prefix->Prefix, e->prefix->PrefixLen, &in6addr_any, 0, FIB_RULE_FIND_SADDR) < 0) {
++ MDBG("Failed to delete rule for forwarding MN\n");
++ goto err;
++ }
++ return 1;
++err:
++ dbg("error with forwarding deletion\n");
++ return -1;
++}
++
++static int conf_mn_info(struct bulentry *e){
++ dbg("MN prefix: %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(&e->prefix->Prefix));
++ e->delForwarding = 1;
++ if (IN6_IS_ADDR_UNSPECIFIED(&e->lmaIpAddr)) {
++ dbg("Error with the LMA address");
++ goto err;
++ } else {
++ MDBG("LMA address %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(&e->lmaIpAddr));
++ }
++
++ if ((e->tunnelIfID = is_tnl_existing(&e->magGlobalEgressAddress, &e->lmaIpAddr)) == 0){
++ e->tunnelIfID = tunnel_add(&e->magGlobalEgressAddress, &e->lmaIpAddr,
++ e->if_coa, NULL, NULL);
++ if (e->tunnelIfID <= 0) {
++ MDBG("failed to create MAG-LMA tunnel\n");
++ goto err;
++ }
++ }
++
++ if (rule_add(NULL, RT6_TABLE_MIP6,
++ IP6_RULE_PRIO_MIP6_HOA_OUT, RTN_UNICAST,
++ &e->prefix->Prefix, e->prefix->PrefixLen, &in6addr_any, 0, FIB_RULE_FIND_SADDR) < 0) {
++ MDBG("Failed to create rule for forwarding MN\n");
++ goto err;
++ }
++
++ dbg("creating route from %x:%x:%x:%x:%x:%x:%x:%x to%x:%x:%x:%x:%x:%x:%x:%x on if %u\n"
++ ,NIP6ADDR(&e->prefix->Prefix),NIP6ADDR(&in6addr_any) ,e->tunnelIfID);
++// if (route_add(e->tunnelIfID, RT6_TABLE_MIP6,
++// RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
++// &e->prefix->Prefix, e->prefix->PrefixLen, &in6addr_any, 0,
++// NULL) < 0) {
++// MDBG("failed to create forwarding from MN\n");
++// goto err;
++// }
++ if (route_add(e->tunnelIfID, RT6_TABLE_MAIN,
++ RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
++ &e->prefix->Prefix, e->prefix->PrefixLen, &in6addr_any, 0,
++ NULL) < 0) {
++ MDBG("failed to create forwarding from MN\n");
++ goto err;
++ }
++
++ dbg("creating route from %x:%x:%x:%x:%x:%x:%x:%x to%x:%x:%x:%x:%x:%x:%x:%x on if %u\n"
++ ,NIP6ADDR(&in6addr_any),NIP6ADDR(&e->prefix->Prefix) ,e->ifId);
++// if (route_add(e->ifId, RT6_TABLE_MIP6,
++// RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
++// NULL, 0, &e->prefix->Prefix, e->prefix->PrefixLen,
++// NULL) < 0) {
++// MDBG("failed to create forwarding for MN\n");
++// goto err;
++// }
++ if (route_add(e->ifId, RT6_TABLE_MAIN,
++ RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
++ &in6addr_any, 0, &e->prefix->Prefix, e->prefix->PrefixLen,
++ NULL) < 0) {
++ MDBG("failed to create forwarding for MN\n");
++ goto err;
++ }
++
++ return 1;
++err:
++ dbg("error with forwarding set up\n");
++ return -1;
++}
++
+ static int mn_dereg(void *vbule, __attribute__ ((unused)) void *arg)
+ {
+ struct bulentry *bule = vbule;
+@@ -457,6 +973,12 @@ static int mn_dereg(void *vbule, __attribute__ ((unused)) void *arg)
+ return 0;
+ }
+
++static int mag_dereg_mn(void *vbule, void *arg)
++{
++ //Todo deregistration of the mn...
++ return 0;
++}
++
+ #define FLUSH_ALL 0
+ #define FLUSH_VALID 1
+ #define FLUSH_FAILED 2
+@@ -544,6 +1066,87 @@ static void bu_resend(struct tq_elem *tqe)
+ pthread_rwlock_unlock(&mn_lock);
+ }
+
++static void mag_mn_dereg(struct tq_elem *tqe)
++{
++ pthread_rwlock_wrlock(&mn_lock);
++ if (!task_interrupted()) {
++ struct bulentry *bule = tq_data(tqe, struct bulentry, tqe);
++ MDBG("Bul expire type %d", bule->type);
++ bul_delete(bule);
++ }
++ pthread_rwlock_unlock(&mn_lock);
++}
++
++static void pbu_resend(struct tq_elem *tqe)
++{
++ //TODO
++ pthread_rwlock_wrlock(&mn_lock);
++ if (!task_interrupted()) {
++ struct bulentry *bule = tq_data(tqe, struct bulentry, tqe);
++ struct home_addr_info *hai = bule->home;
++ int expired;
++
++ clock_gettime(CLOCK_REALTIME, &bule->lastsent);
++ tsadd(bule->delay, bule->delay, bule->delay);
++ bule->delay = tsmin(bule->delay, MAX_BINDACK_TIMEOUT_TS);
++ bule->consecutive_resends++;
++
++ /* First of all, detect the presence of the node */
++ /* Perform DAD on the link local address of the mn */
++ dbg("Performing DAD to check if the MN is still there");
++ if (ndisc_do_dad(bule->ifId, &bule->mnLinkLocalAddress, 0) == 0){
++ /* Deregister the node */
++ tsclear(bule->lifetime);
++ expired = 0;
++ bule->handoffIndicator = 4; /* Handoff State unknown */
++ bule->callback = mag_mn_dereg;
++ add_task_rel(&conf.InitialBindackTimeoutReReg_ts, &bule->tqe, bule->callback);
++
++ }
++ else {
++ /* Expend lifetime */
++ expired = !(tsisset(bule->lifetime)); /* PMIP check only the lifetime of the bule, not of COA and HOA */
++ bule->handoffIndicator = 5; /* Handoff State not changed */
++ }
++
++ MDBG("Bul resend [%p] type %d\n", bule, bule->type);
++
++// expired = bu_lft_check(bule);
++
++
++ bule->seq++;
++
++ if (bule->flags & IP6_MH_BU_HOME &&
++ bule->consecutive_resends > MAX_CONSECUTIVE_RESENDS) {
++ struct timespec now;
++ clock_gettime(CLOCK_REALTIME, &now);
++ bule_invalidate(bule, &now, 0);
++ //mn_change_ha(hai);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++// if (bule->flags & IP6_MH_BU_HOME &&
++// hai->use_dhaad &&
++// bule->consecutive_resends > MAX_CONSECUTIVE_RESENDS) {
++// struct timespec now;
++// clock_gettime(CLOCK_REALTIME, &now);
++// bule_invalidate(bule, &now, 0);
++// mn_change_ha(hai);
++// pthread_rwlock_unlock(&mn_lock);
++// return;
++// }
++ mag_send_pbu_msg(bule);
++
++ if (expired)
++ bul_delete(bule);
++ else {
++ bul_update_expire(bule);
++ bul_update_timer(bule);
++ }
++ }
++ pthread_rwlock_unlock(&mn_lock);
++}
++
+ static void bu_refresh(struct tq_elem *tqe)
+ {
+ pthread_rwlock_wrlock(&mn_lock);
+@@ -575,6 +1178,58 @@ static void bu_refresh(struct tq_elem *tqe)
+ pthread_rwlock_unlock(&mn_lock);
+ }
+
++static void pbu_refresh(struct tq_elem *tqe)
++{
++ pthread_rwlock_wrlock(&mn_lock);
++ if (!task_interrupted()) {
++ struct bulentry *bule = tq_data(tqe, struct bulentry, tqe);
++ int expired;
++ MDBG("Bul refresh type: %d\n", bule->type);
++
++ clock_gettime(CLOCK_REALTIME, &bule->lastsent);
++
++ bule->delay = conf.InitialBindackTimeoutReReg_ts;
++
++ expired = !(tsisset(bule->lifetime)); /* PMIP check only the lifetime of the bule, not of COA and HOA */
++// expired = bu_lft_check(bule);
++
++ /* First of all, detect the presence of the node */
++ /* Perform DAD on the link local address of the mn */
++ dbg("Performing DAD to check if the MN is still there");
++ if (ndisc_do_dad(bule->ifId, &bule->mnLinkLocalAddress, 0) == 0){
++ /* Deregister the node */
++ tsclear(bule->lifetime);
++ expired = 0;
++ bule->handoffIndicator = 4; /* Handoff State unknown */
++ bule->callback = mag_mn_dereg;
++ add_task_rel(&conf.InitialBindackTimeoutReReg_ts, &bule->tqe, bule->callback);
++
++ }
++ else {
++ /* Expend lifetime */
++ expired = !(tsisset(bule->lifetime)); /* PMIP check only the lifetime of the bule, not of COA and HOA */
++ bule->handoffIndicator = 5; /* Handoff State not changed */
++ bule->callback = pbu_resend;
++ }
++
++ bule->seq++;
++
++// pre_bu_bul_update(bule); /* PMIP, no XFRM rules */
++ mag_send_pbu_msg(bule);
++
++ if (expired)
++ bul_delete(bule);
++ else {
++ bul_update_expire(bule);
++ bul_update_timer(bule);
++// if (conf.OptimisticHandoff)
++// post_ba_bul_update(bule);
++ }
++ }
++ //TODO
++ pthread_rwlock_unlock(&mn_lock);
++}
++
+ static void mn_update_hoa_lifetime(struct mn_addr *mn_hoa,
+ struct timespec *timestamp,
+ uint32_t valid_time,
+@@ -764,6 +1419,65 @@ static int process_first_home_bu(struct bulentry *bule,
+ return err;
+ }
+
++/* Create the bule for PMIP purpose
++ * Todo: define all the parameters/variables
++ */
++ static int process_first_home_pbu(struct bulentry *bule,
++ struct home_addr_info *hai,
++ struct timespec *lifetime, struct AdvPrefix *prefix, uint8_t *mnID)
++{
++ int err = 0;
++ bule->type = BUL_ENTRY;
++ bule->flags = IP6_MH_BU_HOME | IP6_MH_BU_ACK | IP6_MH_BU_PREG; /* Added Proxy registration flag and delete hai->lladdr_comp */
++ dbg("P flag: %x\n L flag: %x\n byte order: %d\n", IP6_MH_BU_PREG, IP6_MH_BU_LLOCAL, BYTE_ORDER);
++ dbg("flags: %x\n", bule->flags);
++ bule->coa_changed = -1;
++ bule->coa = hai->primary_coa.addr;
++ bule->if_coa = hai->primary_coa.iif;
++ bule->lifetime = *lifetime;
++ bule->delay = conf.InitialBindackTimeoutFirstReg_ts;
++ bule->callback = pbu_resend;
++ /* Use alt. coa with IPsec */
++ bule->use_alt_coa = 1;
++ bule->ext_cleanup = mn_pol_ext_cleanup;
++ bule->home = hai;
++ bule->consecutive_resends = 0;
++
++ dbg("BUL created for mnID: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", (mnID[0]&0xFF), (mnID[1]&0xFF),
++ (mnID[2]&0xFF), (mnID[3]&0xFF) ,(mnID[4]&0xFF), (mnID[5]&0xFF));
++ for (int i = 0; i<6; i++){
++ bule->mnIdentifier[i] = mnID[i];
++ }
++ dbg("BUL created for mnID: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", (bule->mnIdentifier[0]&0xFF), (bule->mnIdentifier[1]&0xFF),
++ (bule->mnIdentifier[2]&0xFF), (bule->mnIdentifier[3]&0xFF) ,(bule->mnIdentifier[4]&0xFF), (bule->mnIdentifier[5]&0xFF));
++ hai->home_reg_status = HOME_REG_UNCERTAIN;
++
++ /* PMIP specific */
++ bule->handoffIndicator = 4;//by default, state unknown
++ bule->lmaIpAddr = bule->peer_addr; /* The creation is initiated with the value peer address containing the LMA ip address */
++ bule->proxyReg = 1;
++ bule->firstReg = 1;
++ bule->prefix = prefix;
++ bule->ifId = hai->if_home;/* use of the hai to store the interface id of the mag on the link MN/MAG */
++// uint8_t *tmp = trans_ip6addr_mnID(&bule->hoa);
++// for (int i = 0; i<6 ; i++){
++// bule->mnIdentifier[i] = tmp[i];
++// }
++ //bule->mnIdentifier = trans_ip6addr_mnID(&bule->hoa); /* For PMIP the MN Id is stored in the hoa variable */
++ if (!IN6_IS_ADDR_UNSPECIFIED(&conf.FixedMAGLinkLocalAddressOnAllAccessLinks))
++ bule->magLinkLocalAddress = conf.FixedMAGLinkLocalAddressOnAllAccessLinks;
++ bule->magGlobalEgressAddress = hai->primary_coa.addr;
++
++ /* this is the first creation so the timestamp is let to the value NULL */
++
++ //if ((err = mn_tnl_state_add(hai, hai->if_tunnel, 0)) < 0) /* create tunnel -> not necessary, not now? */
++ //MDBG("Failed to initialize new bule for MN\n");
++ //else
++ MDBG("New bule for MN %s\n", bule->mnIdentifier);
++
++ return err;
++}
++
+ static int mn_do_dad(struct home_addr_info *hai, int dereg);
+ static void mn_send_home_na(struct home_addr_info *hai);
+
+@@ -912,6 +1626,13 @@ static void mn_send_home_bu(struct home_addr_info *hai)
+ }
+ }
+
++static void mag_send_mn_pbu(struct home_addr_info *hai)
++{
++ struct bulentry *bule = NULL;
++ struct timespec lifetime;
++ //TODO
++}
++
+ void mn_send_cn_bu(struct bulentry *bule)
+ {
+ /* Rate limiting CN registration binding updates
+@@ -1250,8 +1971,370 @@ static void mn_recv_ba(const struct ip6_mh *mh, ssize_t len,
+ pthread_rwlock_unlock(&mn_lock);
+ }
+
++static void mag_recv_pba(const struct ip6_mh *mh, ssize_t len,
++ const struct in6_addr_bundle *in, int iif)
++{
++ struct ip6_mh_binding_ack *pba;
++ struct mh_options mh_opts;
++ struct bulentry *bule;
++ struct ip6_mh_opt_hom_net_prefix *homePrefix;
++ struct ip6_mh_opt_mobile_node_id *mnID;
++ struct ip6_mh_opt_handoff_indic *handoffInd;
++ struct ip6_mh_opt_access_tech_type *accTech;
++ struct ip6_mh_opt_link_layer_id *llayerId;
++ struct timespec now, ba_lifetime, br_adv, mps_delay;
++ uint16_t seqno;
++ //TODO
++
++ TRACE;
++
++ if (len < sizeof(struct ip6_mh_binding_ack) ||
++ mh_opt_parse(mh, len,
++ sizeof(struct ip6_mh_binding_ack), &mh_opts) < 0){
++ dbg("Pb with pba...\n");
++ return;
++ }
++
++ pba = (struct ip6_mh_binding_ack *)mh;
++
++ /* Check the P flag */
++ if (!(pba->ip6mhba_flags & IP6_MH_BA_PREG)){
++ dbg("Received PBA without P flag -> rejected\n");
++ return;
++ }
++
++ homePrefix = mh_opt(&pba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_HOM_NET_PRFX);
++ if (!homePrefix){
++ dbg("Received PBA without prefixes -> rejected!\n");
++ return;
++ }
++
++ mnID = mh_opt(&pba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_MN_ID);
++ if (mnID == NULL || mnID->ip6mnp_subtype != IP6_MNID_MHOPT_SUB_MAC){/* Only ID as MAC address */
++ dbg("Received PBA without Mobile Node ID -> rejected\n");
++ return;
++ }
++
++ pthread_rwlock_wrlock(&mn_lock);
++ bule = bul_get(NULL, &homePrefix->ip6mnp_prefix, in->src);
++ if (!bule || bule->type != BUL_ENTRY) {
++ MDBG("Got BA without corresponding BUL entry "
++ "from %x:%x:%x:%x:%x:%x:%x:%x "
++ "to home address %x:%x:%x:%x:%x:%x:%x:%x "
++ "with coa %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(in->src),
++ NIP6ADDR(in->dst),
++ NIP6ADDR(in->local_coa != NULL ?
++ in->local_coa : &in6addr_any));
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ int j = 0;
++ for (int i = 0; i<6; i++){
++ if (bule->mnIdentifier[i] == mnID->ip6mnp_mnid[i])
++ j++;
++ }
++ if (j != 6)
++ {
++ dbg("Got PBA corresponding to the wrong BULE -> rejected\n");
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ dbg("Got BA from %x:%x:%x:%x:%x:%x:%x:%x "
++ "to home address %x:%x:%x:%x:%x:%x:%x:%x "
++ "with coa %x:%x:%x:%x:%x:%x:%x:%x and status %d\n",
++ NIP6ADDR(in->src), NIP6ADDR(in->dst),
++ NIP6ADDR(in->local_coa != NULL ? in->local_coa : &in6addr_any),
++ pba->ip6mhba_status);
++ dbg("Dumping corresponding BULE\n");
++ dbg_func(bule, dump_bule);
++ /* First check authenticator */
++ if (!(bule->flags & IP6_MH_BU_HOME) &&
++ mn_chk_bauth(pba, len, &mh_opts, bule)) {
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ /* Then sequence number */
++ seqno = ntohs(pba->ip6mhba_seqno);
++ if (bule->seq != seqno) {
++ if (pba->ip6mhba_status != IP6_MH_BAS_SEQNO_BAD) {
++ /*
++ * In this case, ignore BA and resends BU.
++ */
++ MDBG("Got BA with incorrect sequence number %d, "
++ "the one sent in BU was %d\n", seqno, bule->seq);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ }
++ /* Check of the options values -> need to be the same as in the BULE */
++ /* getting the HandOff indicator */
++ handoffInd = mh_opt(&pba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_HANDOFF_INDIC);
++ if (!handoffInd){
++ dbg("Got PBA with no Handoff Indicator option\n");
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ else if (handoffInd->ip6mnp_handoff_indic != bule->handoffIndicator){
++ dbg("Got PBA with incorrect Handoff Indicator option %d, the one sent in the PBU was %d\n", handoffInd->ip6mnp_handoff_indic, bule->handoffIndicator);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++
++ /* getting the Access Technology type */
++ accTech = mh_opt(&pba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_ACCESS_TECH_TYPE);
++ if (!accTech){
++ dbg("Got PBA with no Access technology option\n");
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ else if (accTech->ip6mnp_access_tech_type != bule->accTechType){
++ dbg("Got PBA with incorrect Access technology option %d, the one sent in the PBU was %d\n", accTech->ip6mnp_access_tech_type, bule->accTechType);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++
++ int llID= 0;
++ for (int i = 0; i < 6; i++){
++ if (bule->linkLayerID[i] != 0){
++ llID=1;
++ break;
++ }
++ }
++ if (llID){
++ /* getting the Link Layer Identifier */
++ llayerId = mh_opt(&pba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_LINK_LAYER_ID);
++ if (!llayerId){
++ dbg("Got PBA with no Link Layer ID option\n");
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ int j = 0;
++ for (int i=0; i<6 ; i++){
++ if (bule->linkLayerID[i] == llayerId->ip6mnp_link_layer_addr[i])
++ j++;
++ }
++ if (j != 6){
++ dbg("Got PBA with incorrect Link Layer ID option\n");
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ }
++
++ bule->do_send_bu = 0;
++ bule->consecutive_resends = 0;
++ clock_gettime(CLOCK_REALTIME, &now);
++
++
++
++ if (pba->ip6mhba_status >= IP6_MH_BAS_UNSPECIFIED) {
++ /* Status PROXY_REG_NOT_ENABLED */
++ if (pba->ip6mhba_status == IP6_MH_BAS_PROXY_REG_NOT_ENABLED){
++ dbg("PBU was rejected because the MN is not authorized for the network mobility management\n");
++ bule_invalidate(bule, &now, 1);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++
++ /* Status TIMESTAMP_LOWER_THAN_PREV_ACCEPTED */
++ if (pba->ip6mhba_status == IP6_MH_BAS_TIMESTAMP_LOWER_THAN_PREV_ACCEPTED){
++ dbg("PBU was rejected because the PBU's timestamp was lower than the one from the PBU previously accepted\n");
++ clock_gettime(CLOCK_REALTIME, &bule->lastsent);
++ bule->seq = seqno + 1;
++ bule->lifetime = conf.PBUlifetime; /* PMIP select either the prefix lifetime or PBU lifetime... */
++ mag_send_pbu_msg(bule);
++ bule->delay = conf.InitialBindackTimeoutReReg_ts;
++ bul_update_timer(bule);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++
++ /* Status TIMESTAMP_MISMATCH */
++ if (pba->ip6mhba_status == IP6_MH_BAS_TIMESTAMP_MISMATCH){
++ dbg("PBU was rejected because the timestamp is invalid -> try to synchronize the clocks of MAG and LMA\n");
++ bule_invalidate(bule, &now, 1);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++
++ /* Status NOT_AUTHORIZED_FOR_HOME_NETWORK_PREFIX */
++ if (pba->ip6mhba_status == IP6_MH_BAS_NOT_AUTHORIZED_FOR_HOME_NETWORK_PREFIX){
++ dbg("PBU was rejected because the prefix is unauthorized -> try to change the allocated prefix in the configuration\n");
++ bule_invalidate(bule, &now, 1);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ if (pba->ip6mhba_status == IP6_MH_BAS_SEQNO_BAD) {
++ MDBG("out of sync seq nr\n");
++ clock_gettime(CLOCK_REALTIME, &bule->lastsent);
++ bule->seq = seqno + 1;
++// if (bule->flags & IP6_MH_BU_HOME)
++// mn_get_home_lifetime(bule->home,
++// &bule->lifetime, 0);
++// else
++// mn_get_ro_lifetime(bule->home,
++// &bule->lifetime, 0);
++ bule->lifetime = conf.PBUlifetime;
++ bule->callback = pbu_resend;
++ //pre_bu_bul_update(bule); /* PMIP: no use of xfrm rules */
++ mag_send_pbu_msg(bule);
++ bule->delay = conf.InitialBindackTimeoutReReg_ts;
++ bul_update_timer(bule);
++// if (bule->flags & IP6_MH_BU_HOME &&
++// conf.OptimisticHandoff) {
++// post_ba_bul_update(bule);
++// }
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ if (bule->flags & IP6_MH_BU_HOME) {
++ struct home_addr_info *hai = bule->home;
++ if (hai->at_home) {
++ bul_delete(bule);
++ //mn_do_dad(hai, 1);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ syslog(LOG_ERR,
++ "Unable to register with HA, deleting entry\n");
++ if (hai->use_dhaad) {
++ bule_invalidate(bule, &now, 0);
++ //mn_change_ha(hai);
++ } else {
++ bule_invalidate(bule, &now, 1);
++ }
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ } else {
++ /* Don't resend BUs to this CN */
++ bule_invalidate(bule, &now, 1);
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ }
++ if (bule->wait_ack)
++ bule->wait_ack = 0;
++ else {
++ MDBG("unexpected BA, ignoring\n");
++ pthread_rwlock_unlock(&mn_lock);
++ return;
++ }
++ tssetsec(ba_lifetime, ntohs(pba->ip6mhba_lifetime) << 2);
++ br_adv = ba_lifetime;
++ tsadd(bule->lastsent, ba_lifetime, bule->hard_expire);
++ if (!(bule->flags & IP6_MH_BU_HOME) || !conf.OptimisticHandoff)
++ post_ba_bul_update(bule);
++ if (bule->flags & IP6_MH_BU_HOME) {
++ struct home_addr_info *hai = bule->home;
++ struct ip6_mh_opt_refresh_advice *bra;
++
++ /* three cases to consider:
++ * 1. Deregistration (lifetime = 0)
++ * 2. Lifetime extension
++ * 3. First registration
++ */
++ if (!tsisset(ba_lifetime)) {
++ /* PMIP: mag deregistering the MN */
++ /* 1. delete routes
++ * 2. delete tunnel if not used anymore
++ * 3. "tear down point to point connection"??-> send RA with prefix lifetime = 0
++ * 4. delete bule entry
++ */
++ dbg("Deregistering the MN\n");
++// int type = FLUSH_FAILED;
++// mn_dereg_home(hai);
++ if (dereg_mn_forwarding(bule) < 0){
++ dbg("Error while deleting forwarding for MN\n");
++ }
++ /* options for the prefix (the RA has the same lifetime as the bul) */
++ bule->prefix->AdvValidLifetime = 0;
++ bule->prefix->AdvPreferredLifetime = 0;
++ bule->prefix->AdvOnLinkFlag = 1;
++ bule->prefix->AdvAutonomousFlag = 1;
++ /* Send the RA */
++ dbg("Sending RA to %x:%x:%x:%x:%x:%x:%x:%x"
++ "for deregistring of the prefix %x:%x:%x:%x:%x:%x:%x:%x",
++ NIP6ADDR(&bule->mnLinkLocalAddress),
++ NIP6ADDR(&bule->prefix->Prefix));
++ if (ndisc_send_ra(bule->ifId, &bule->magLinkLocalAddress, &bule->mnLinkLocalAddress, bule->prefix) , 0){
++ dbg("Problem when sending RA\n");
++ return;
++ }
++ bul_delete(bule);
++ /* If BA was for home registration & succesful
++ * Send RO BUs to CNs for this home address.
++ */
++// bul_iterate(&hai->bul, _bul_flush, &type);
++// bul_iterate(&hai->bul, mn_rr_start_handoff, NULL);
++ pthread_rwlock_unlock(&mn_lock);
++// mn_movement_event(NULL);
++// mn_block_rule_del(hai);
++ return;
++ }
++
++ /* proceeding with first registration */
++ hai->home_reg_status = HOME_REG_VALID;
++
++ bra = mh_opt(&pba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_BREFRESH);
++ if (bra)
++ tssetsec(br_adv, ntohs(bra->ip6mora_interval) << 2);
++ if (bule->firstReg){
++ /* proceeding with first registration */
++ hai->home_reg_status = HOME_REG_VALID;
++ conf_mn_info(bule); /* configure the tunnel and forwarding rules */
++ bule->firstReg = 0;
++ }
++ dbg("Bule lifetime: %u, ba_lifetime: %u\n", tstodsec(bule->lifetime), tstodsec(ba_lifetime));
++ set_bule_lifetime(bule, &ba_lifetime, &br_adv);
++ dbg("Bule lifetime: %u\n", tstodsec(bule->lifetime));
++
++ /* options for the prefix (the RA has the same lifetime as the bul) */
++ bule->prefix->AdvValidLifetime = tstodsec(bule->lifetime);
++ bule->prefix->AdvPreferredLifetime = tstodsec(bule->lifetime);
++ bule->prefix->AdvOnLinkFlag = 1;
++ bule->prefix->AdvAutonomousFlag = 1;
++
++
++ dbg("Callback to pbu_refresh after %d seconds\n",
++ bule->delay.tv_sec);
++ bule->callback = pbu_refresh;
++
++ /* Send the RA */
++ dbg("Sending RA to %x:%x:%x:%x:%x:%x:%x:%x"
++ "for the prefix %x:%x:%x:%x:%x:%x:%x:%x\n",
++ NIP6ADDR(&bule->mnLinkLocalAddress),
++ NIP6ADDR(&bule->prefix->Prefix));
++ if (ndisc_send_ra(bule->ifId, &bule->magLinkLocalAddress, &bule->mnLinkLocalAddress, bule->prefix) , 0){
++ dbg("Problem when sending RA\n");
++ return;
++ }
++ bul_update_expire(bule);
++ bul_update_timer(bule);
++
++ /* If status of BA is 0 or 1, Binding Update is accepted. */
++// if (ba->ip6mhba_status == IP6_MH_BAS_PRFX_DISCOV){/* PMIP: Prefix discovery needed? -> not for the moment */
++// mpd_trigger_mps(&bule->hoa, &bule->peer_addr);
++// }else if( hai->home_reg_status == HOME_REG_UNCERTAIN && tsisset(ba_lifetime)){
++// if(tsisset(hai->hoa.timestamp)){
++// mps_delay = tsmin(hai->hoa.valid_time, ba_lifetime);
++// mpd_schedule_first_mps(&bule->hoa, &bule->peer_addr, &mps_delay);
++// }else
++// mpd_trigger_mps(&bule->hoa, &bule->peer_addr);
++// }
++
++ /* If BA was for home registration & succesful
++ * Send RO BUs to CNs for this home address.
++ */
++ }
++ pthread_rwlock_unlock(&mn_lock);
++}
++
+ static struct mh_handler mn_ba_handler = {
++#ifndef ENABLE_PMIPV6
+ .recv = mn_recv_ba,
++#else
++ .recv = mag_recv_pba,
++#endif /* ENABLE_PMIPV6 */
+ };
+
+ static int do_handoff(struct home_addr_info *hai)
+@@ -2616,11 +3699,80 @@ int mn_init(void)
+ if (conf_home_addr_info(hai) < 0)
+ goto err_hoa;
+ }
++#ifdef PMIP_DEBUG
++ /* Test: Sending a PBU !!!!!!!!!!!!!!!!!!!!!!!!!!*/
++// uint8_t mnID[6];/* 00:09:6b:fa:f9:b4 */
++// mnID[0]=0x00;
++// mnID[1]=0x09;
++// mnID[2]=0x6b;
++// mnID[3]=0xfa;
++// mnID[4]=0xf9;
++// mnID[5]=0xb4;
++// struct bulentry *e = NULL;
++// struct pmipMobileNodeEntry *mnProfil;
++// mnProfil = getMNProfile(mnID);
++// if (mnProfil == NULL){
++// dbg("MN with MN Identifier %s not authorized for PMIP (pas de profil)\n", mnID);
++// return -1;
++// }
++//
++// if (!mnProfil->pmip_enabled){
++// dbg("MN with MN Identifier %s not authorized for PMIP (PMIP non enabled)\n", mnID);
++// return -1;
++// }
++//
++// struct home_addr_info *hai;
++// hai = malloc(sizeof(struct home_addr_info));
++//
++// //hai->if_home = iif;
++// hai->ha_addr = mnProfil->lma_address;
++// /* TODO: Initialiser les informations concernant le MAG:
++// * hoa = addresse locale de la MAG sur le lien MN/MAG
++// * COA = global address and iif of the egress interface (link LMA/MAG)
++// */
++// struct timespec lifetime;
++// tsset(lifetime, 420, 0);/*temporary, need to be fixed to a better value, dynamicaly assigned... */
++//
++// /* Get the Home prefixes in policy store */
++// struct AdvPrefix *prefix;
++// prefix = getHomePrefixesFromProfile(mnProfil);
++//
++// /* addresse source et interface source pour envoyer le pbu */
++// hai->primary_coa.addr = conf.MAGEgressGlobalAddress;
++// hai->primary_coa.iif = conf.MAGEgressInterfaceIndex;
++//
++// /* MN is allowed to use PMIP */
++// /* Creation of the Bule */
++// struct in6_addr *mnIDip;
++// mnIDip = transf_mnID_ip6addr(mnProfil->mnIdentifier);
++// dbg("mnID IPv6 format: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(mnIDip));
++// e = create_bule(mnIDip, &mnProfil->lma_address);
++// if (e == NULL)
++// return -1;
++// if (process_first_home_pbu(e, hai, &lifetime, prefix) < 0 /*||
++// bul_add(e) < 0*/) {
++// bul_delete(e);
++// return -1;
++// }
++// dbg("sending pbu from %x:%x:%x:%x:%x:%x:%x:%x to %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&e->magGlobalEgressAddress), NIP6ADDR(&e->lmaIpAddr));
++//
++// /* Sending PBU */
++// mag_send_pbu_msg(e);
++ /* End of the test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
++ //For test purpose, we comment the home address configuration
++// list_for_each(l, &conf.home_addrs) {
++// struct home_addr_info *hai;
++// hai = list_entry(l, struct home_addr_info, list);
++// if (conf_home_addr_info(hai) < 0)
++// goto err_hoa;
++// }
++#endif
+ if_mc_group(ICMP6_MAIN_SOCK, 0, &in6addr_all_nodes_mc,
+ IPV6_JOIN_GROUP);
+ if (linklocal_rt_rules_add() < 0)
+ goto err_rule;
+ icmp6_handler_reg(ICMP6_PARAM_PROB, &mn_param_prob_handler);
++ icmp6_handler_reg(ND_ROUTER_SOLICIT, &mag_router_sol_handler);
+ mh_handler_reg(IP6_MH_TYPE_BERROR, &mn_be_handler);
+ mh_handler_reg(IP6_MH_TYPE_BACK, &mn_ba_handler);
+ mh_handler_reg(IP6_MH_TYPE_BRR, &mn_brr_handler);
+@@ -2632,6 +3784,7 @@ err_md:
+ mh_handler_dereg(IP6_MH_TYPE_BACK, &mn_ba_handler);
+ mh_handler_dereg(IP6_MH_TYPE_BERROR, &mn_be_handler);
+ icmp6_handler_dereg(ICMP6_PARAM_PROB, &mn_param_prob_handler);
++ icmp6_handler_dereg(ND_ROUTER_SOLICIT, &mag_router_sol_handler);
+ linklocal_rt_rules_del();
+ err_rule:
+ pthread_rwlock_wrlock(&mn_lock);
+@@ -2664,6 +3817,7 @@ void mn_cleanup()
+ mh_handler_dereg(IP6_MH_TYPE_BACK, &mn_ba_handler);
+ mh_handler_dereg(IP6_MH_TYPE_BERROR, &mn_be_handler);
+ icmp6_handler_dereg(ICMP6_PARAM_PROB, &mn_param_prob_handler);
++ icmp6_handler_dereg(ND_ROUTER_SOLICIT, &mag_router_sol_handler);
+ linklocal_rt_rules_del();
+ pthread_rwlock_wrlock(&mn_lock);
+ list_for_each_safe(l, n, &home_addr_list) {
+diff --git a/src/mn.h b/src/mn.h
+index 5ed25b7..97ef32e 100644
+--- a/src/mn.h
++++ b/src/mn.h
+@@ -89,6 +89,8 @@ struct home_addr_info {
+ char name[IF_NAMESIZE];
+ int mnp_count;
+ struct list_head mob_net_prefixes;
++ /* PMIP info */
++ int is_if_lma; /* 1 for the interface with LMA */
+ };
+
+ enum {
+@@ -155,6 +157,10 @@ int mn_rr_post_home_handoff(void *bule, void *vcoa);
+
+ void mn_start_ro(struct in6_addr *cn_addr, struct in6_addr *home_addr);
+
++int dereg_mn_forwarding(struct bulentry *e);
++
++struct AdvPrefix *getMNPrefix (uint8_t *mnID);
++
+ static inline int mn_is_at_home(struct list_head *prefixes,
+ const struct in6_addr *home_prefix,
+ int home_plen)
+diff --git a/src/movement.c b/src/movement.c
+index d985937..dfceea6 100644
+--- a/src/movement.c
++++ b/src/movement.c
+@@ -34,6 +34,7 @@
+ #include <net/if.h>
+ #include <linux/types.h>
+ #include <linux/ipv6_route.h>
++#include <arpa/inet.h>
+
+ #include "debug.h"
+ #include "icmp6.h"
+@@ -579,6 +580,61 @@ static void __md_discover_router(struct md_inet6_iface *iface)
+ tssetsec(exp_in, iface->devconf[DEVCONF_RTR_SOLICIT_INTERVAL]);
+ add_task_rel(&exp_in, &iface->tqe, md_discover_router);
+ }
++#ifdef PMIP_DEBUG
++ /****************************************************************************
++ * Ceci est a des fins exclusives de test, supprimer dans la version finale
++ * ***************************************************************************/
++
++ /* On dump les interfaces */
++// dbg("Start debugging!!!!!!!!!!!!\n");
++// struct list_head *list;
++// list_for_each(list, &ifaces){
++// struct md_inet6_iface *iface;
++// iface = list_entry(list, struct md_inet6_iface, list);
++// dbg("iface : %s\n home link: %d\nHwaddr: %s", iface->name, iface->home_link, iface->hwa);
++// }
++//
++//
++// struct AdvPrefix *prefix;
++// struct in6_addr dest, src;
++// char src_addr[50];
++// prefix = malloc(sizeof(struct AdvPrefix));
++// memset(prefix, 0, sizeof(struct AdvPrefix));
++// memset(src_addr, 0, 50);
++// strncpy(src_addr, "2001:200:0:6802:209:6bff:fefa:f9b4",50);
++// prefix->AdvOnLinkFlag = PInfo_AdvOnLinkFlag;
++// prefix->AdvAutonomousFlag = PInfo_AdvAutonomousFlag;
++// prefix->AdvRouterAddr = PInfo_AdvRouterAddr;
++// prefix->AdvValidLifetime = PInfo_AdvValidLifetime;
++// prefix->AdvPreferredLifetime = PInfo_AdvPreferredLifetime;
++// prefix->if6to4[0] = 0;
++// prefix->enabled = 1;
++//
++// memset(&dest, 0, sizeof(dest));
++//
++// inet_pton(AF_INET6, src_addr, &src);
++//
++// struct list_head *l;
++// list_for_each(l, &conf.pmipMobileNodes) {
++//// dbg("***** Mobile Nodes PMIP policy *****\n");
++// struct pmipMobileNodeEntry *npmipmnentry;
++// npmipmnentry = list_entry(l, struct pmipMobileNodeEntry, list);
++// if (npmipmnentry != NULL) {
++// memcpy(&prefix->Prefix, &npmipmnentry->home_network_prefix1, sizeof(struct in6_addr));
++// prefix->PrefixLen = (uint8_t) npmipmnentry->home_network_plen1;
++// dbg("Debuggage : envoi de prefix via RA, prefix = %d\n", prefix->PrefixLen);
++// if (!IN6_IS_ADDR_UNSPECIFIED(&prefix->Prefix))
++// dbg("Home Network Prefix = %x:%x:%x:%x:%x:%x:%x:%x for the interface identified by %s\n", NIP6ADDR(&prefix->Prefix), npmipmnentry->pmip_interface1);
++// memcpy(&dest, &npmipmnentry->lma_address, sizeof(struct in6_addr));
++// }
++//
++// }
++// ndisc_send_ra(iface->ifindex, &src, &dest, prefix);
++
++ /****************************************************************************
++ * Fins du test; TODO delete this test!!!
++ * ***************************************************************************/
++#endif
+ }
+
+ static void md_discover_router(struct tq_elem *tqe)
+@@ -2055,6 +2111,17 @@ int md_start(void)
+ if (pthread_create(&md_listener, NULL, md_nl_listen, NULL))
+ return -1;
+ inet6_ifaces_iterate(process_nlmsg, NULL);
++ /*******************************************************
++ * Debuggage!!!!!!!!!
++ */
++ /* On dump les interfaces */
++ // dbg("Start debugging!!!!!!!!!!!!\n");
++ /*struct list_head *list;
++ list_for_each(list, &ifaces){
++ struct md_inet6_iface *iface;
++ iface = list_entry(list, struct md_inet6_iface, list);
++ dbg("iface : %s\n home link: %d\nHwaddr: %s\n", iface->name, iface->home_link, iface->hwa);
++ }*/
+ return 0;
+ }
+
+diff --git a/src/ndisc.c b/src/ndisc.c
+index ed37f89..f00d415 100644
+--- a/src/ndisc.c
++++ b/src/ndisc.c
+@@ -349,6 +349,7 @@ int ndisc_l2addr_to_opt(int ifindex, uint8_t *addr)
+ break;
+ }
+ out:
++ dbg("***** MAC address %s ******\n", ifr.ifr_hwaddr.sa_data);
+ close(fd);
+ return res;
+ }
+@@ -516,6 +517,152 @@ int ndisc_send_rs(int ifindex, const struct in6_addr *dst,
+ return ndisc_send_unspec(ifindex, dst, hdr, hdrlen, opts, optslen);
+ }
+
++int ndisc_send_ra(int ifindex, const struct in6_addr *src,
++ const struct in6_addr *dst, struct AdvPrefix *prefix)
++{
++ struct iovec iov; /* le header plus le nombre d options: MTU, source link address et prefix information */
++ uint8_t l2addr[32];
++ size_t len = 0;
++ int lenL2Addr;
++ ssize_t err;
++ int res;
++ int flagManagedAddressConfiguration = 0; /* TODO: Check the defaults values of the variables for PMIP! (maybe those values can be unspecified) */
++ int flagOtherStatefulConfiguration = 0;
++ uint16_t raDefaultLifeTime = 1800;
++ uint32_t reachableTime = 0;
++ uint32_t retransTimer = 0;
++ int mtuOption = 0; /* pas d option mtu pour le moment */
++ unsigned char buff[MSG_SIZE];
++ struct nd_router_advert *radvert;
++ dbg("start sending RA****************************\n Interface index = %d\n", ifindex);
++ dbg("Source address = %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(src));
++ dbg("Destination address = %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(dst));
++ /* We will use the radvd code for creating the message */
++ /* XXX: */
++ if (IN6_IS_ADDR_UNSPECIFIED(src)) {
++ dbg ("should be handled appropriately\n");
++ // return ndisc_send_unspec(ND_ROUTER_ADVERT, ifindex, dst, NULL, 0);/* TODO: check if it is ok with the protocol (XXX: seems not to work) */
++ }
++
++ /* Create the Router Advertisement message */
++ memset(&buff, 0, sizeof(buff));
++ radvert = (struct nd_router_advert *) buff;
++
++ //dbg("buff= %s\n", buff);
++
++ radvert->nd_ra_type = ND_ROUTER_ADVERT;
++ radvert->nd_ra_code = 0;
++ radvert->nd_ra_cksum = 0;
++
++ radvert->nd_ra_curhoplimit = 255;
++
++ radvert->nd_ra_flags_reserved =
++ (flagManagedAddressConfiguration)?ND_RA_FLAG_MANAGED:0;
++ radvert->nd_ra_flags_reserved |=
++ (flagOtherStatefulConfiguration)?ND_RA_FLAG_OTHER:0;
++
++ radvert->nd_ra_router_lifetime = htons(raDefaultLifeTime);
++
++ radvert->nd_ra_reachable = htonl(reachableTime);
++ radvert->nd_ra_retransmit = htonl(retransTimer);
++
++ len = sizeof(struct nd_router_advert);
++ //dbg("sending RA : avant option prefix***************\n");
++ //dbg("buff= %s\n", buff);
++
++ //dbg("length beofre prefix option = %d\n", len);
++ /*
++ * add prefix options
++ */
++ while(prefix)
++ {
++ if(!IN6_IS_ADDR_UNSPECIFIED(&prefix->Prefix)){
++ struct nd_opt_prefix_info *pinfo;
++ //dbg("sending RA : option prefix***************\n");
++ pinfo = (struct nd_opt_prefix_info *) (buff + len);
++
++ pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
++ pinfo->nd_opt_pi_len = 4;
++ //dbg("sending RA : option prefix***************\n Prefix = %d\n", prefix->PrefixLen);
++ pinfo->nd_opt_pi_prefix_len = prefix->PrefixLen;
++
++ pinfo->nd_opt_pi_flags_reserved =
++ (prefix->AdvOnLinkFlag)?ND_OPT_PI_FLAG_ONLINK:0;
++ pinfo->nd_opt_pi_flags_reserved |=
++ (prefix->AdvAutonomousFlag)?ND_OPT_PI_FLAG_AUTO:0;
++ /* Mobile IPv6 ext */
++ pinfo->nd_opt_pi_flags_reserved |=
++ (prefix->AdvRouterAddr)?ND_OPT_PI_FLAG_RADDR:0;
++
++ pinfo->nd_opt_pi_valid_time = htonl(prefix->AdvValidLifetime);
++ pinfo->nd_opt_pi_preferred_time = htonl(prefix->AdvPreferredLifetime);
++ pinfo->nd_opt_pi_reserved2 = 0;
++
++ memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix,
++ sizeof(struct in6_addr));
++
++ len += sizeof(*pinfo);
++ }
++ prefix = prefix->next;
++ }
++
++ //dbg("length before MTU option = %d\n", len);
++ /*
++ * add MTU option
++ */
++
++ if (mtuOption != 0) {
++ struct nd_opt_mtu *mtu;
++
++ mtu = (struct nd_opt_mtu *) (buff + len);
++
++ mtu->nd_opt_mtu_type = ND_OPT_MTU;
++ mtu->nd_opt_mtu_len = 1;
++ mtu->nd_opt_mtu_reserved = 0;
++ mtu->nd_opt_mtu_mtu = htonl(mtuOption);
++
++ len += sizeof(*mtu);
++ }
++
++ /*
++ * add Source Link-layer Address option
++ */
++ if (lenL2Addr = ndisc_l2addr_to_opt(ifindex, l2addr) < 0)
++ return -EINVAL;
++
++ //dbg("MAC address = %s, length = %d\n", l2addr, lenL2Addr);
++ //dbg("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n",(l2addr[0]&0xFF), (l2addr[1]&0xFF), (l2addr[2]&0xFF), (l2addr[3]&0xFF), (l2addr[4]&0xFF), (l2addr[5]&0xFF));
++
++ //dbg("length before LL option = %d\n", len);
++ if (lenL2Addr>0)
++ {
++ uint8_t *ucp;
++ unsigned int i;
++
++ ucp = (uint8_t *) (buff + len);
++
++ *ucp++ = ND_OPT_SOURCE_LINKADDR; /* if_hwaddr_len is in unit of bit */
++ *ucp++ = (uint8_t) ((lenL2Addr + 16 + 63) >> 6); /* size of the field length of the option is in unit of 8 bytes */
++ //*ucp++ = (uint8_t) ((int)lenL2Addr + (int)2); /* simplifier l'expression du dessus, lenL2Addr est en Bytes et non en bits.... */
++ len += 2 * sizeof(uint8_t);
++
++ //i = (lenL2Addr + 7) >> 3; /* size in bytes */
++ memcpy(buff + len, &l2addr, lenL2Addr);
++ len += lenL2Addr;
++ }
++ //dbg("buff*********\n");
++ //for (int i = 0; i<len;i++)
++ //dbg("%x\n", buff[i]);
++ iov.iov_len = len;
++ iov.iov_base = (caddr_t) buff;
++ //dbg("length = %d \n", len);
++
++ res = icmp6_send(ifindex, 255, src, dst, &iov, 1);
++
++
++ return res;
++}
++
+ int ndisc_send_ns(int ifindex, const struct in6_addr *target)
+ {
+ struct nd_neighbor_solicit ns;
+@@ -545,6 +692,7 @@ int ndisc_send_na(int ifindex, const struct in6_addr *src,
+ if ((len = ndisc_l2addr_to_opt(ifindex, l2addr)) < 0)
+ return -EINVAL;
+
++ dbg("MAC address = %s, length = %d\n", l2addr, len);
+ na = icmp6_create(iov, ND_NEIGHBOR_ADVERT, iovlen++);
+
+ if (na == NULL)
+diff --git a/src/ndisc.h b/src/ndisc.h
+index ca64d32..057d5b6 100644
+--- a/src/ndisc.h
++++ b/src/ndisc.h
+@@ -4,12 +4,24 @@
+ #define __NDISC_H__ 1
+
+ #include <net/if_arp.h>
++#include <net/if.h>
+
+ #define DAD_TIMEOUT 1 /* one second */
+ #define L2ADDR_MAX_SIZE 6 /* Max required size for supported L2 @ */
+ #define MAP_L2ADDR_MAX_SIZE 6 /* Max required size for mapped @ format used
+ * in ND Src/Tgt Link-Layer Address option */
+
++/* maximum message size for incoming and outgoing RSs and RAs */
++#define MSG_SIZE 4096
++
++/* Each prefix has an associated: */
++
++#define PInfo_AdvValidLifetime 86400 /* seconds */
++#define PInfo_AdvOnLinkFlag 1
++#define PInfo_AdvPreferredLifetime 14400 /* seconds */
++#define PInfo_AdvAutonomousFlag 1
++#define PInfo_AdvRouterAddr 0 /* for MIP6 */
++
+ short ndisc_get_l2addr_len(unsigned short iface_type);
+
+ int ndisc_set_linklocal(struct in6_addr *lladdr, uint8_t *hwa,
+@@ -22,6 +34,26 @@ int ndisc_l2addr_to_opt(int ifindex, uint8_t *addr);
+
+ int nd_get_iface_type(int ifindex);
+
++struct AdvPrefix {
++ struct in6_addr Prefix;
++ uint8_t PrefixLen;
++
++ int AdvOnLinkFlag;
++ int AdvAutonomousFlag;
++ uint32_t AdvValidLifetime;
++ uint32_t AdvPreferredLifetime;
++
++ /* Mobile IPv6 extensions */
++ int AdvRouterAddr;
++
++ /* 6to4 etc. extensions */
++ char if6to4[IF_NAMESIZE];
++ int enabled;
++ int AutoSelected;
++
++ struct AdvPrefix *next;
++};
++
+ int ndisc_do_dad(int ifi, struct in6_addr *addr, int ll);
+
+ int ndisc_send_rs(int ifindex, const struct in6_addr *dst,
+@@ -33,6 +65,9 @@ int ndisc_send_na(int ifindex, const struct in6_addr *src,
+ const struct in6_addr *dst,
+ const struct in6_addr *target, uint32_t flags);
+
++int ndisc_send_ra(int ifindex, const struct in6_addr *src,
++ const struct in6_addr *dst, struct AdvPrefix *prefix);
++
+ void proxy_nd_iface_init(int ifindex);
+
+ void proxy_nd_iface_cleanup(int ifindex);
+diff --git a/src/scan.l b/src/scan.l
+index 50fae0a..8561d6d 100644
+--- a/src/scan.l
++++ b/src/scan.l
+@@ -289,6 +289,30 @@ HaServedPrefix { return HASERVEDPREFIX; }
+ HomePrefix { return HOMEPREFIX; }
+ MobRtrUseExplicitMode { return MOBRTRUSEEXPLICITMODE; }
+ internal { return INTERNAL; }
++EnableMAGLocalRouting { return ENABLEMAGLOCALROUTING; }
++TimestampBasedApproachInUse { return TIMESTAMPBASEDAPPROACHINUSE; }
++MobileNodeGeneratedTimestampInUse { return MOBILENODEGENERATEDTIMESTAMPINUSE; }
++MinDelayBeforeBCEDelete { return MINDELAYBEFOREBCEDELETE; }
++MaxDelayBeforeNewBCEAssign { return MAXDELAYBEFORENEWBCEASSIGNE; }
++TimestampValidityWindow { return TIMESTAMPVALIDITYWINDOW; }
++FixedMAGLinkLocalAddressOnAllAccessLinks { return FIXEDMAGLINKLOCALADDRESSONALLACCESSLINKS; }
++FixedMAGLinkLayerAddressOnAllAccessLinks { return FIXEDMAGLINKLAYERADDRESSONALLACCESSLINKS; }
++MNIdentifier { return MNIDENTIFIER; }
++LMAAddress { return LMAADDRESS; }
++SupportedConfigurationMode { return SUPPORTEDCONFIGURATIONMODE; }
++PMIPEnabled { return PMIPENABLED; }
++LinklayerIdentifier { return LINKLAYERIDENTIFIER; }
++HomePrefixLifetime { return HOMEPREFIXLIFETIME; }
++HomeNetworkPrefix1 { return HOMENETWORKPREFIX1; }
++HomeNetworkPrefix2 { return HOMENETWORKPREFIX2; }
++HomeNetworkPrefix3 { return HOMENETWORKPREFIX3; }
++PMIPInterface1 { return PMIPINTERFACE1; }
++PMIPInterface2 { return PMIPINTERFACE2; }
++PMIPInterface3 { return PMIPINTERFACE3; }
++MAGInterfaceLMA { return MAGINTERFACELMA; }
++MAGEgressGlobalAddress { return MAGEGRESSGLOBALADDRESS; }
++PBUlifetime { return PBULIFETIME; }
++LMAInterfaceMAG { return LMAINTERFACEMAG; }
+
+ {addr} {
+ int i;
+diff --git a/src/tunnelctl.c b/src/tunnelctl.c
+index 23fc20b..252fe5d 100644
+--- a/src/tunnelctl.c
++++ b/src/tunnelctl.c
+@@ -142,6 +142,21 @@ static inline struct mip6_tnl *get_tnl(int ifindex)
+ return tnl;
+ }
+
++int is_tnl_existing(struct in6_addr *local, struct in6_addr *remote)
++{
++ int res = 0;
++ struct list_head *list;
++ list_for_each(list, &tnl_list) {
++ struct mip6_tnl *tmp;
++ tmp = list_entry(list, struct mip6_tnl, list);
++ if (IN6_ARE_ADDR_EQUAL(&(tmp->parm.laddr),local) && IN6_ARE_ADDR_EQUAL(&(tmp->parm.raddr), remote)) {
++ res = tmp->ifindex;
++ break;
++ }
++ }
++ return res;
++}
++
+ static int __tunnel_del(struct mip6_tnl *tnl)
+ {
+ int res = 0;
+@@ -398,10 +413,14 @@ int tunnel_mod(int ifindex,
+ }
+ } else {
+ new = old;
+-
+- if (old->users == 1 &&
+- (res = __tunnel_mod(old, local, remote, link)) < 0 &&
+- (new = __tunnel_add(local, remote, link)) == NULL) {
++ /* PMIP modification, bug MIP??-> when more than one user?? */
++ if (old->users == 1){
++ if ((res = __tunnel_mod(old, local, remote, link)) < 0){
++ pthread_mutex_unlock(&tnl_lock);
++ return -1;
++ }
++ }
++ else if ((new = __tunnel_add(local, remote, link)) == NULL) {
+ pthread_mutex_unlock(&tnl_lock);
+ return -1;
+ }
+@@ -415,8 +434,8 @@ int tunnel_mod(int ifindex,
+ pthread_mutex_unlock(&tnl_lock);
+ return -1;
+ }
+- if (old != new)
+- __tunnel_del(old);
++// if (old != new)
++// __tunnel_del(old);/* More thant one user! */
+
+ res = new->ifindex;
+ pthread_mutex_unlock(&tnl_lock);
+diff --git a/src/tunnelctl.h b/src/tunnelctl.h
+index 8c956a6..a826110 100644
+--- a/src/tunnelctl.h
++++ b/src/tunnelctl.h
+@@ -31,6 +31,9 @@ int tunnel_del(int ifindex,
+
+ int tunnelctl_init(void);
+
++int is_tnl_existing(struct in6_addr *local, struct in6_addr *remote);
++
++
+ void tunnelctl_cleanup(void);
+
+ #endif
+diff --git a/src/xfrm.c b/src/xfrm.c
+index 920a833..f231e76 100644
+--- a/src/xfrm.c
++++ b/src/xfrm.c
+@@ -56,7 +56,7 @@
+ #include "conf.h"
+ #include "ipsec.h"
+
+-#define XFRM_DEBUG_LEVEL 1
++#define XFRM_DEBUG_LEVEL 2
+
+ #if XFRM_DEBUG_LEVEL >= 1
+ #define XDBG dbg