From 3a6ae1adc61f86c7427ebf246a348919bd1ab95f Mon Sep 17 00:00:00 2001 From: t-momose Date: Tue, 23 Aug 2005 08:24:52 +0000 Subject: [PATCH] - home agent forwards icmp6 packets as specified rfc2473 when error occured on tunneling - Codes in icmp6_input_common() are splitted to each functions. --- kame/kame/shisad/cnd.c | 26 ++- kame/kame/shisad/common.c | 410 +++++--------------------------------- kame/kame/shisad/had.c | 90 ++++++++- kame/kame/shisad/hal.c | 177 +++++++++++++++- kame/kame/shisad/mnd.c | 148 +++++++++++++- kame/kame/shisad/shisad.h | 53 +++-- 6 files changed, 522 insertions(+), 382 deletions(-) diff --git a/kame/kame/shisad/cnd.c b/kame/kame/shisad/cnd.c index e841a451a4..db46282b0f 100644 --- a/kame/kame/shisad/cnd.c +++ b/kame/kame/shisad/cnd.c @@ -1,4 +1,4 @@ -/* $KAME: cnd.c,v 1.11 2005/05/24 10:16:19 keiichi Exp $ */ +/* $KAME: cnd.c,v 1.12 2005/08/23 08:24:52 t-momose Exp $ */ /* * Copyright (C) 2004 WIDE Project. @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -204,10 +205,29 @@ static void cn_lists_init(void) { mip6_bc_init(); - - return; } +int +cn_receive_dst_unreach(icp) + struct icmp6_hdr *icp; +{ + struct ip6_hdr *iip6; + struct binding_cache *bc; + struct ip6_rthdr2 *rth2; + + iip6 = (struct ip6_hdr *)(icp + 1); + if ((rth2 = find_rthdr2(iip6)) == NULL) + return (0); + bc = mip6_bc_lookup((struct in6_addr *)(rth2 + 1), &iip6->ip6_src, 0); + if (bc) { + mip6_bc_delete(bc); + syslog(LOG_INFO, + "binding for %s is deleted due to ICMP destunreach.\n", + ip6_sprintf(&iip6->ip6_dst)); + } + + return (0); +} int mipsock_input(miphdr) diff --git a/kame/kame/shisad/common.c b/kame/kame/shisad/common.c index 53f2ad101e..e68d6c3399 100644 --- a/kame/kame/shisad/common.c +++ b/kame/kame/shisad/common.c @@ -1,4 +1,4 @@ -/* $KAME: common.c,v 1.20 2005/08/19 02:01:55 t-momose Exp $ */ +/* $KAME: common.c,v 1.21 2005/08/23 08:24:52 t-momose Exp $ */ /* * Copyright (C) 2004 WIDE Project. All rights reserved. @@ -78,13 +78,8 @@ static const struct in6_addr haanyaddr_ifidnn = { #endif #ifndef MIP_CN -struct nd6options { - struct nd_opt_prefix_info *ndpi_start, *ndpi_end; /* could be multiple */ - struct nd_opt_adv_interval *ndadvi; - struct nd_opt_homeagent_info *ndhai; -} ndopts; +struct nd6options ndopts; -static int mip6_get_nd6options(struct nd6options *, char *, int); extern struct mip6_hpfx_list hpfx_head; #endif /* MIP_CN */ @@ -164,12 +159,15 @@ icmp6sock_open() ICMP6_FILTER_SETPASS(MIP6_HA_DISCOVERY_REPLY, &filter); ICMP6_FILTER_SETPASS(MIP6_PREFIX_SOLICIT, &filter); ICMP6_FILTER_SETPASS(MIP6_PREFIX_ADVERT, &filter); -#ifdef MIP_CN +#if defined(MIP_CN) || defined(MIP_HA) ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); -#endif /* MIP_CN */ -#ifdef MIP_MN +#endif /* MIP_CN || MIP_HA */ +#ifdef MIP_HA + ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter); +#endif /* MIP_HA */ +#if defined(MIP_MN) || defined(MIP_HA) ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter); -#endif /* MIP_MN */ +#endif /* MIP_MN || MIP_HA */ if (setsockopt(icmp6sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0) { perror("setsockopt ICMP6_FILTER"); @@ -182,7 +180,7 @@ icmp6sock_open() } #ifndef MIP_CN -static int +int mip6_get_nd6options(ndoptions, options, total) struct nd6options *ndoptions; char *options; @@ -249,30 +247,9 @@ icmp6_input_common(fd) struct in6_pktinfo *pkt = NULL; char adata[512], buf[1024]; #ifdef MIP_MN - struct mip6_hoainfo *hoainfo = NULL; struct binding_update_list *bul; - struct mip6_prefix_advert *mpsadv; - struct mip6_dhaad_rep *dhrep; - struct in6_addr *dhrep_addr; - struct mip6_mipif *mif = NULL; #endif /* MIP_MN */ -#ifndef MIP_CN - struct mip6_hpfxl *hpfx = NULL; - struct mip6_hpfx_list *hpfxhead = NULL; - struct home_agent_list *hal = NULL; - struct nd_opt_hdr *pt; - - struct nd_router_advert *ra; - uint16_t hai_preference = 0; - uint16_t hai_lifetime = 0; - uint8_t hai_pfxlen = 0; -#endif /* MIP_CN */ - -#ifdef MIP_HA - struct mip6_dhaad_req *dhreq; -#endif /* MIP_HA */ - memset(&from, 0, sizeof(from)); msg.msg_name = (void *)&from; msg.msg_namelen = sizeof(struct sockaddr_in6); @@ -288,7 +265,7 @@ icmp6_input_common(fd) readlen = recvmsg(fd, &msg, 0); if (readlen < 0) { perror("recvmsg"); - return (-1); + return (EINVAL); } for (cmsgptr = CMSG_FIRSTHDR(&msg); @@ -334,36 +311,8 @@ icmp6_input_common(fd) switch(icp->icmp6_type) { #ifdef MIP_CN case ICMP6_DST_UNREACH: - { - u_int8_t nh; - struct ip6_hdr *iip6; - struct binding_cache *bc; - struct ip6_ext *ext; - struct ip6_rthdr2 *rth2; - - iip6 = (struct ip6_hdr *)(icp + 1); - for (ext = (struct ip6_ext *)(iip6 + 1), nh = iip6->ip6_nxt; - nh == IPPROTO_HOPOPTS || - nh == IPPROTO_FRAGMENT || - nh == IPPROTO_DSTOPTS; - /* sizeof *ext is 2 bytes. */ - nh = ext->ip6e_nxt, ext += (ext->ip6e_len + 1) << 2); - if (nh != IPPROTO_ROUTING) - break; - - rth2 = (struct ip6_rthdr2 *)ext; - if (rth2->ip6r2_type != 2) - break; - bc = mip6_bc_lookup((struct in6_addr *)(rth2 + 1), &iip6->ip6_src, 0); - if (bc) { - mip6_bc_delete(bc); - syslog(LOG_INFO, - "binding for %s is deleted due to ICMP destunreach.\n", - ip6_sprintf(&iip6->ip6_dst)); - } + error = cn_receive_dst_unreach(icp); break; - - } #endif /* MIP_CN */ #ifndef MIP_CN @@ -376,168 +325,16 @@ icmp6_input_common(fd) * procedure. */ case ND_ROUTER_ADVERT: - ra = (struct nd_router_advert *)icp; - -/* - if (debug) - syslog(LOG_INFO, - "ra lifetime = %d\n", ntohs(ra->nd_ra_router_lifetime)); -*/ - - /* parse nd_options */ - memset(&ndopts, 0, sizeof(ndopts)); - error = mip6_get_nd6options(&ndopts, - (char *)icp + sizeof(struct nd_router_advert), - readlen - sizeof(struct nd_router_advert)); - if (error) - break; - -#if defined(MIP_HA) - hpfxhead = &hpfx_head; -#elif defined(MIP_MN) /* MIP_MN */ - mif = mnd_get_mipif(receivedifindex); - if (mif == NULL) - break; - hpfxhead = &mif->mipif_hprefx_head; -#endif /* MIP_HA */ - if (hpfxhead == NULL) - break; - - hai_lifetime = ntohs(ra->nd_ra_router_lifetime); - - for (pt = (struct nd_opt_hdr *)ndopts.ndpi_start; - pt <= (struct nd_opt_hdr *)ndopts.ndpi_end; - pt = (struct nd_opt_hdr *)((caddr_t)pt + - (pt->nd_opt_len << 3))) { - struct nd_opt_prefix_info *pi; - - if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) - continue; - pi = (struct nd_opt_prefix_info *)pt; - - hai_preference = 0; - hai_lifetime = ntohs(ra->nd_ra_router_lifetime); - hai_pfxlen = pi->nd_opt_pi_prefix_len; - in6_gladdr = &pi->nd_opt_pi_prefix; -#if 0 - if (hai_lifetime == 0) - hai_lifetime = ntohl(pi->nd_opt_pi_valid_time); -#endif - -/* - if (debug) - syslog(LOG_INFO, "prefix lifetime = %d\n", hai_lifetime); -*/ - - /* check H flag */ - if (!(pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)) { -#if defined(MIP_HA) - /* delete HAL */ - hpfx = mip6_get_hpfxlist(&pi->nd_opt_pi_prefix, - pi->nd_opt_pi_prefix_len, - hpfxhead); - if (hpfx == NULL) - continue; - - if ((hal = mip6_get_hal(hpfx, in6_gladdr))) - mip6_delete_hal(hpfx, &pi->nd_opt_pi_prefix); -#endif /* MIP_HA */ - continue; /* MN ignores RA which not having R flag */ - } - - /* - * when the prefix field does not - * have global address, it should - * be ignored - */ - if (IN6_IS_ADDR_LINKLOCAL(in6_gladdr) - || IN6_IS_ADDR_MULTICAST(in6_gladdr) - || IN6_IS_ADDR_LOOPBACK(in6_gladdr) - || IN6_IS_ADDR_V4MAPPED(in6_gladdr) - || IN6_IS_ADDR_UNSPECIFIED(in6_gladdr)) - continue; - - /* - * when the prefix field does not - * contain 128-bit address, it should - * be ignored - */ - if ((in6_gladdr->s6_addr[15] == 0) && - (in6_gladdr->s6_addr[14] == 0) && - (in6_gladdr->s6_addr[13] == 0) && - (in6_gladdr->s6_addr[12] == 0) && - (in6_gladdr->s6_addr[11] == 0) && - (in6_gladdr->s6_addr[10] == 0)) - continue; - - if (debug) - syslog(LOG_INFO, "RA received from HA (%s)\n", - ip6_sprintf(&pi->nd_opt_pi_prefix)); - /* Home Agent Information Option */ - if (ndopts.ndhai) { - hai_preference = ntohs(ndopts.ndhai->nd_opt_hai_preference); - hai_lifetime = ntohs(ndopts.ndhai->nd_opt_hai_lifetime); - - if (debug) - syslog(LOG_INFO, - "hainfo option found in RA (pref=%d,life=%d)\n", - hai_preference, hai_lifetime); - } - - /* - * if lifetime is zero, correspondent HA must be - * removed from home agent list - */ - if (hai_lifetime == 0 || - !(ra->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)) { - hpfx = mip6_get_hpfxlist(&pi->nd_opt_pi_prefix, - pi->nd_opt_pi_prefix_len, - hpfxhead); - if (hpfx == NULL) - continue; - - hal = mip6_get_hal(hpfx, in6_gladdr); - if (hal == NULL) - continue; - - mip6_delete_hal(hpfx, &pi->nd_opt_pi_prefix); - } else { - /* need both linklocal and - global address to add home prefix info */ - if (in6_gladdr == NULL) - continue; - - hpfx = mip6_get_hpfxlist(in6_gladdr, hai_pfxlen, hpfxhead); - if (hpfx == NULL) { -#if defined(MIP_HA) - continue; -#else - /* add_hpfx XXXX ? */ -#endif /* MIP_HA */ - } -#ifdef MIP_HA - hpfx->hpfx_vltime = ntohl(pi->nd_opt_pi_valid_time); - hpfx->hpfx_pltime = ntohl(pi->nd_opt_pi_preferred_time); - - /* add or update home agent list */ - if (had_add_hal(hpfx, in6_gladdr, - in6_lladdr, hai_lifetime, hai_preference, 0) == NULL) { - /* error = EINVAL; */ - /* break; */ - continue; - } -#endif /* MIP_HA */ - } - } - + error = receive_ra((struct nd_router_advert *)icp, readlen, + receivedifindex, in6_lladdr, in6_gladdr); break; #endif /* MIP_CN */ #ifdef MIP_HA case MIP6_HA_DISCOVERY_REQUEST: mip6stat.mip6s_dhreq++; - dhreq = (struct mip6_dhaad_req *)msg.msg_iov[0].iov_base; - error = send_haadrep(&from.sin6_addr, &dst, dhreq, receivedifindex); + error = send_haadrep(&from.sin6_addr, &dst, + (struct mip6_dhaad_req *)icp, receivedifindex); break; case MIP6_PREFIX_SOLICIT: @@ -545,98 +342,28 @@ icmp6_input_common(fd) struct mip6_prefix_solicit *mps; mip6stat.mip6s_mps++; - mps = (struct mip6_prefix_solicit *)msg.msg_iov[0].iov_base; + mps = (struct mip6_prefix_solicit *)icp; error = send_mpa(&from.sin6_addr, mps->mip6_ps_id, receivedifindex); break; } - + + case ICMP6_TIME_EXCEEDED: + case ICMP6_PARAM_PROB: + case ICMP6_PACKET_TOO_BIG: + error = relay_icmp6_error(icp, readlen, receivedifindex); + break; #endif /* MIP_HA */ #ifdef MIP_MN case MIP6_HA_DISCOVERY_REPLY: - { - struct mip6_hpfxl *hpfx; - struct mip6_mipif *mipif = NULL; - char *options; - int optlen, total; - mip6stat.mip6s_dhreply++; - dhrep = (struct mip6_dhaad_rep *)msg.msg_iov[0].iov_base; - - /* Is this HAADREPLY mine? */ - hoainfo = hoainfo_get_withdhaadid(ntohs(dhrep->mip6_dhrep_id)); - if (hoainfo == NULL) { - error = ENOENT; - break; - } - -#ifdef MIP_NEMO - if ((dhrep->mip6_dhrep_reserved & MIP6_DHREP_FLAG_MR) == 0) { - /* XXX */ - syslog(LOG_INFO, "HA does not support the basic NEMO protocol\n"); - error = ENOENT; - break; - } -#endif /* MIP_NEMO */ - - /* - * When MN receives DHAAD reply, it flushes all home - * agent entries in the list except for static - * configured entries. After flush, new entries will - * be added according to the reply packet - */ - - mipif = mnd_get_mipif(hoainfo->hinfo_ifindex); - if (mipif == NULL) - return (0); - - LIST_FOREACH(hpfx, &mipif->mipif_hprefx_head, hpfx_entry) { - if (mip6_are_prefix_equal(&hoainfo->hinfo_hoa, - &hpfx->hpfx_prefix, hpfx->hpfx_prefixlen)) { - break; - } - } - if (hpfx == NULL) { - error = ENOENT; - break; - } - mip6_flush_hal(hpfx, MIP6_HAL_STATIC); - - options = (char *)icp + sizeof(struct mip6_dhaad_rep); - total = readlen - sizeof(struct mip6_dhaad_rep); - for (optlen = 0; total > 0; total -= optlen) { - options += optlen; - dhrep_addr = (struct in6_addr *)options; - optlen = sizeof(struct in6_addr); - if (mnd_add_hal(hpfx, dhrep_addr, 0) == NULL) - continue; - - if (debug) - syslog(LOG_INFO, "%s is added into hal list\n", - ip6_sprintf(dhrep_addr)); - } + error = receive_hadisc_reply((struct mip6_dhaad_rep *)icp, readlen); + break; - bul = bul_get_homeflag(&hoainfo->hinfo_hoa); - if (bul) { - bul->bul_reg_fsm_state = MIP6_BUL_REG_FSM_STATE_DHAAD; - bul_kick_fsm(bul, MIP6_BUL_FSM_EVENT_DHAAD_REPLY, NULL); - syslog(LOG_INFO, "DHAAD gets %s\n", - ip6_sprintf(&bul->bul_peeraddr)); - -#ifdef MIP_MCOA - if (!LIST_EMPTY(&bul->bul_mcoa_head)) { - struct binding_update_list *mbul; - - for (mbul = LIST_FIRST(&bul->bul_mcoa_head); mbul; - mbul = LIST_NEXT(mbul, bul_entry)) { - mbul->bul_reg_fsm_state = MIP6_BUL_REG_FSM_STATE_DHAAD; - bul_kick_fsm(mbul, MIP6_BUL_FSM_EVENT_DHAAD_REPLY, NULL); - } - } -#endif /* MIP_MCOA */ - } + case MIP6_PREFIX_ADVERT: + error = receive_mpa((struct mip6_prefix_advert *)icp, readlen); break; - } + case ICMP6_PARAM_PROB: switch (icp->icmp6_code) { case ICMP6_PARAMPROB_NEXTHEADER: @@ -664,63 +391,7 @@ icmp6_input_common(fd) "failed.\n"); } break; - case MIP6_PREFIX_ADVERT: - { - int done = 0; - struct mip6_mipif *mif; - struct mip6_hpfx_mn_exclusive mnoption; - - mpsadv = (struct mip6_prefix_advert *)icp; - - /* Check MPS ID */ - LIST_FOREACH(mif, &mipifhead, mipif_entry) { - if (mif->mipif_mps_id == ntohl(mpsadv->mip6_pa_id)) - break; - } - if (mif == NULL) - break; - - memset(&ndopts, 0, sizeof(ndopts)); - error = mip6_get_nd6options(&ndopts, - (char *)icp + sizeof(struct mip6_prefix_advert), - readlen - sizeof(struct mip6_prefix_advert)); - - for (pt = (struct nd_opt_hdr *)ndopts.ndpi_start; - pt <= (struct nd_opt_hdr *)ndopts.ndpi_end; - pt = (struct nd_opt_hdr *)((caddr_t)pt + - (pt->nd_opt_len << 3))) { - struct nd_opt_prefix_info *pi; - - if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) - continue; - pi = (struct nd_opt_prefix_info *)pt; - - if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || - IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) - continue; - - /* aggregatable unicast address, rfc2374 XXX */ - if (pi->nd_opt_pi_prefix_len != 64) - continue; - - memset(&mnoption, 0, sizeof(mnoption)); - mnoption.hpfxlist_vltime = - ntohl(pi->nd_opt_pi_valid_time); - mnoption.hpfxlist_pltime = - ntohl(pi->nd_opt_pi_preferred_time); - - mnd_add_hpfxlist(&pi->nd_opt_pi_prefix, - pi->nd_opt_pi_prefix_len, - &mnoption, mif); - done = 1; - } - if (!done) { - error = EINVAL; - syslog(LOG_ERR, "Could not find valid PI in MPA\n"); - } - break; - } #endif /* MIP_MN */ default: break; @@ -786,6 +457,31 @@ mip6_create_addr(addr, ifid, prefix, prefixlen) return; } +struct ip6_rthdr2* +find_rthdr2(ip6) + struct ip6_hdr *ip6; +{ + u_int8_t nh; + struct ip6_ext *ext; + struct ip6_rthdr2 *rth2; + + for (ext = (struct ip6_ext *)(ip6 + 1), nh = ip6->ip6_nxt; + nh == IPPROTO_HOPOPTS || + nh == IPPROTO_FRAGMENT || + nh == IPPROTO_DSTOPTS; + /* sizeof *ext is 2 bytes. */ + nh = ext->ip6e_nxt, ext += (ext->ip6e_len + 1) << 2) + ; + if (nh != IPPROTO_ROUTING) + return (NULL); + + rth2 = (struct ip6_rthdr2 *)ext; + if (rth2->ip6r2_type != 2) + return (NULL); + + return (rth2); +} + #if 0 #ifdef MIP_MN int diff --git a/kame/kame/shisad/had.c b/kame/kame/shisad/had.c index 4142075606..25194484b6 100644 --- a/kame/kame/shisad/had.c +++ b/kame/kame/shisad/had.c @@ -1,4 +1,4 @@ -/* $KAME: had.c,v 1.22 2005/08/18 12:08:42 t-momose Exp $ */ +/* $KAME: had.c,v 1.23 2005/08/23 08:24:53 t-momose Exp $ */ /* * Copyright (C) 2004 WIDE Project. @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -688,3 +689,90 @@ send_mpa(dst, mps_id, ifindex) return (errno); } + +/* Relay icmp error occured on the path of a tunneling */ +/* icmp type and code are specified in rfc2473 */ +int +relay_icmp6_error(oicp, oicp_len, ifindex) + struct icmp6_hdr *oicp; /* Original ICMP6 message */ + size_t oicp_len; + u_short ifindex; +{ + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr = NULL; + struct in6_pktinfo *pi = NULL; + struct sockaddr_in6 to; + char adata[512], buf[1024]; + struct icmp6_hdr *icp; + struct ip6_hdr *oip6, *iip6; + + oip6 = (struct ip6_hdr *)(oicp + 1); + if (oip6->ip6_nxt != IPPROTO_IPV6) + return (EINVAL); + iip6 = oip6 + 1; + + /* Relaying icmp6 packet should be done + only when this HA manages the destination MN */ + if (mip6_bc_lookup(&iip6->ip6_dst, &oip6->ip6_dst, 0)) { + return (EINVAL); + } + + memset(&to, 0, sizeof(to)); + to.sin6_family = AF_INET6; + to.sin6_addr = iip6->ip6_src; + to.sin6_port = 0; + to.sin6_scope_id = 0; + to.sin6_len = sizeof (struct sockaddr_in6); + + msg.msg_name = (void *)&to; + msg.msg_namelen = sizeof(struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + cmsgptr = CMSG_FIRSTHDR(&msg); + pi = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr)); + memset(pi, 0, sizeof(*pi)); + if (ifindex) + pi->ipi6_ifindex = ifindex; + else + return (-1); + cmsgptr->cmsg_level = IPPROTO_IPV6; + cmsgptr->cmsg_type = IPV6_PKTINFO; + cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr); + + bzero(buf, sizeof(buf)); + icp = (struct icm6_hdr *)buf; + switch (oicp->icmp6_type) { + case ICMP6_TIME_EXCEEDED: + case ICMP6_PARAM_PROB: + case ICMP6_DST_UNREACH: + icp->icmp6_type = ICMP6_DST_UNREACH; + icp->icmp6_code = ICMP6_DST_UNREACH_ADDR; + break; + case ICMP6_PACKET_TOO_BIG: + icp->icmp6_type = ICMP6_PACKET_TOO_BIG; + break; + } + icp->icmp6_cksum = 0; + memcpy(icp + 1, iip6, oicp_len - sizeof(*oicp) - sizeof(struct ip6_hdr)); + + iov.iov_base = buf; + iov.iov_len = oicp_len - sizeof(struct ip6_hdr); + + if (debug) + syslog(LOG_INFO, "relaying icmp6 error message to %s\n", + ip6_sprintf(&iip6->ip6_src)); + + if (sendmsg(icmp6sock, &msg, 0) < 0) + syslog(LOG_ERR, "sendmsg icmp6 @{dest unreach, packet too big} is failed %s\n", strerror(errno)); +#if 0 + else + mip6stat.mip6s_ompa++; +#endif + + return (errno); +} diff --git a/kame/kame/shisad/hal.c b/kame/kame/shisad/hal.c index 642ea0ee77..fc15ee41a6 100644 --- a/kame/kame/shisad/hal.c +++ b/kame/kame/shisad/hal.c @@ -1,4 +1,4 @@ -/* $KAME: hal.c,v 1.1 2005/08/18 10:15:31 t-momose Exp $ */ +/* $KAME: hal.c,v 1.2 2005/08/23 08:24:53 t-momose Exp $ */ /* * Copyright (C) 2005 WIDE Project. All rights reserved. @@ -332,3 +332,178 @@ show_hal(s, head) } } } + +#if defined(MIP_MN) || defined(MIP_HA) +int +receive_ra(ra, ralen, receivedifindex, in6_lladdr, in6_gladdr) + struct nd_router_advert *ra; + size_t ralen; + int receivedifindex; + struct in6_addr *in6_lladdr, *in6_gladdr; +{ + int error; +#ifdef MIP_MN + struct mip6_mipif *mif = NULL; +#endif /* MIP_MN */ + struct mip6_hpfxl *hpfx = NULL; + struct mip6_hpfx_list *hpfxhead = NULL; + struct nd_opt_hdr *pt; + + uint16_t hai_preference = 0; + uint16_t hai_lifetime = 0; + uint8_t hai_pfxlen = 0; + +/* + if (debug) + syslog(LOG_INFO, + "ra lifetime = %d\n", ntohs(ra->nd_ra_router_lifetime)); +*/ + + /* parse nd_options */ + memset(&ndopts, 0, sizeof(ndopts)); + error = mip6_get_nd6options(&ndopts, + (char *)ra + sizeof(struct nd_router_advert), + ralen - sizeof(struct nd_router_advert)); + if (error) + return (error); + +#if defined(MIP_HA) + hpfxhead = &hpfx_head; +#elif defined(MIP_MN) /* MIP_MN */ + mif = mnd_get_mipif(receivedifindex); + if (mif == NULL) + return (0); + hpfxhead = &mif->mipif_hprefx_head; +#endif /* MIP_HA */ + if (hpfxhead == NULL) + return (0); + + hai_lifetime = ntohs(ra->nd_ra_router_lifetime); + + for (pt = (struct nd_opt_hdr *)ndopts.ndpi_start; + pt <= (struct nd_opt_hdr *)ndopts.ndpi_end; + pt = (struct nd_opt_hdr *)((caddr_t)pt + + (pt->nd_opt_len << 3))) { + struct nd_opt_prefix_info *pi; + + if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) + continue; + pi = (struct nd_opt_prefix_info *)pt; + + hai_preference = 0; + hai_lifetime = ntohs(ra->nd_ra_router_lifetime); + hai_pfxlen = pi->nd_opt_pi_prefix_len; + in6_gladdr = &pi->nd_opt_pi_prefix; +#if 0 + if (hai_lifetime == 0) + hai_lifetime = ntohl(pi->nd_opt_pi_valid_time); +#endif + +/* + if (debug) + syslog(LOG_INFO, "prefix lifetime = %d\n", hai_lifetime); +*/ + + /* check H flag */ + if (!(pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)) { +#if defined(MIP_HA) + /* delete HAL */ + hpfx = mip6_get_hpfxlist(&pi->nd_opt_pi_prefix, + pi->nd_opt_pi_prefix_len, + hpfxhead); + if (hpfx == NULL) + continue; + + if (mip6_get_hal(hpfx, in6_gladdr)) + mip6_delete_hal(hpfx, &pi->nd_opt_pi_prefix); +#endif /* MIP_HA */ + continue; /* MN ignores RA which not having R flag */ + } + + /* + * when the prefix field does not + * have global address, it should + * be ignored + */ + if (IN6_IS_ADDR_LINKLOCAL(in6_gladdr) + || IN6_IS_ADDR_MULTICAST(in6_gladdr) + || IN6_IS_ADDR_LOOPBACK(in6_gladdr) + || IN6_IS_ADDR_V4MAPPED(in6_gladdr) + || IN6_IS_ADDR_UNSPECIFIED(in6_gladdr)) + continue; + + /* + * when the prefix field does not + * contain 128-bit address, it should + * be ignored + */ + if ((in6_gladdr->s6_addr[15] == 0) && + (in6_gladdr->s6_addr[14] == 0) && + (in6_gladdr->s6_addr[13] == 0) && + (in6_gladdr->s6_addr[12] == 0) && + (in6_gladdr->s6_addr[11] == 0) && + (in6_gladdr->s6_addr[10] == 0)) + continue; + + if (debug) + syslog(LOG_INFO, "RA received from HA (%s)\n", + ip6_sprintf(&pi->nd_opt_pi_prefix)); + /* Home Agent Information Option */ + if (ndopts.ndhai) { + hai_preference = ntohs(ndopts.ndhai->nd_opt_hai_preference); + hai_lifetime = ntohs(ndopts.ndhai->nd_opt_hai_lifetime); + + if (debug) + syslog(LOG_INFO, + "hainfo option found in RA (pref=%d,life=%d)\n", + hai_preference, hai_lifetime); + } + + /* + * if lifetime is zero, correspondent HA must be + * removed from home agent list + */ + if (hai_lifetime == 0 || + !(ra->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)) { + hpfx = mip6_get_hpfxlist(&pi->nd_opt_pi_prefix, + pi->nd_opt_pi_prefix_len, + hpfxhead); + if (hpfx == NULL) + continue; + + if (mip6_get_hal(hpfx, in6_gladdr) == NULL) + continue; + + mip6_delete_hal(hpfx, &pi->nd_opt_pi_prefix); + } else { + /* need both linklocal and + global address to add home prefix info */ + if (in6_gladdr == NULL) + continue; + + hpfx = mip6_get_hpfxlist(in6_gladdr, hai_pfxlen, hpfxhead); + if (hpfx == NULL) { +#if defined(MIP_HA) + continue; +#else + /* add_hpfx XXXX ? */ +#endif /* MIP_HA */ + } +#ifdef MIP_HA + hpfx->hpfx_vltime = ntohl(pi->nd_opt_pi_valid_time); + hpfx->hpfx_pltime = ntohl(pi->nd_opt_pi_preferred_time); + + /* add or update home agent list */ + if (had_add_hal(hpfx, in6_gladdr, + in6_lladdr, hai_lifetime, hai_preference, 0) == NULL) { + /* error = EINVAL; */ + /* break; */ + continue; + } +#endif /* MIP_HA */ + } + } + + return (error); +} +#endif /* MIP_MN || MIP_HA */ diff --git a/kame/kame/shisad/mnd.c b/kame/kame/shisad/mnd.c index e699a17997..ee163dcc46 100644 --- a/kame/kame/shisad/mnd.c +++ b/kame/kame/shisad/mnd.c @@ -1,4 +1,4 @@ -/* $KAME: mnd.c,v 1.15 2005/05/24 10:16:19 keiichi Exp $ */ +/* $KAME: mnd.c,v 1.16 2005/08/23 08:24:53 t-momose Exp $ */ /* * Copyright (C) 2004 WIDE Project. @@ -1333,6 +1333,152 @@ set_default_bu_lifetime(hoainfo) return (default_lifetime); } +int +receive_hadisc_reply(dhrep, dhrep_len) + struct mip6_dhaad_rep *dhrep; + size_t dhrep_len; +{ + int optlen, total; + char *options; + struct binding_update_list *bul; + struct mip6_mipif *mif; + struct mip6_hpfxl *hpfx; + struct in6_addr *dhrep_addr; + struct mip6_hoainfo *hoainfo; + + /* Is this HAADREPLY mine? */ + hoainfo = hoainfo_get_withdhaadid(ntohs(dhrep->mip6_dhrep_id)); + if (hoainfo == NULL) + return (ENOENT); + +#ifdef MIP_NEMO + if ((dhrep->mip6_dhrep_reserved & MIP6_DHREP_FLAG_MR) == 0) { + /* XXX */ + syslog(LOG_INFO, "HA does not support the basic NEMO protocol\n"); + return (ENOENT); + } +#endif /* MIP_NEMO */ + + /* + * When MN receives DHAAD reply, it flushes all home + * agent entries in the list except for static + * configured entries. After flush, new entries will + * be added according to the reply packet + */ + mif = mnd_get_mipif(hoainfo->hinfo_ifindex); + if (mif == NULL) + return (0); + + LIST_FOREACH(hpfx, &mif->mipif_hprefx_head, hpfx_entry) { + if (mip6_are_prefix_equal(&hoainfo->hinfo_hoa, + &hpfx->hpfx_prefix, hpfx->hpfx_prefixlen)) { + break; + } + } + if (hpfx == NULL) + return (ENOENT); + + mip6_flush_hal(hpfx, MIP6_HAL_STATIC); + + options = (char *)dhrep + sizeof(struct mip6_dhaad_rep); + total = dhrep_len - sizeof(struct mip6_dhaad_rep); + for (optlen = 0; total > 0; total -= optlen) { + options += optlen; + dhrep_addr = (struct in6_addr *)options; + optlen = sizeof(struct in6_addr); + if (mnd_add_hal(hpfx, dhrep_addr, 0) == NULL) + continue; + + if (debug) + syslog(LOG_INFO, "%s is added into hal list\n", + ip6_sprintf(dhrep_addr)); + } + + if ((bul = bul_get_homeflag(&hoainfo->hinfo_hoa)) == NULL) + return (0); + + bul->bul_reg_fsm_state = MIP6_BUL_REG_FSM_STATE_DHAAD; + bul_kick_fsm(bul, MIP6_BUL_FSM_EVENT_DHAAD_REPLY, NULL); + syslog(LOG_INFO, "DHAAD gets %s\n", + ip6_sprintf(&bul->bul_peeraddr)); + +#ifdef MIP_MCOA + if (!LIST_EMPTY(&bul->bul_mcoa_head)) { + struct binding_update_list *mbul; + + for (mbul = LIST_FIRST(&bul->bul_mcoa_head); mbul; + mbul = LIST_NEXT(mbul, bul_entry)) { + mbul->bul_reg_fsm_state = MIP6_BUL_REG_FSM_STATE_DHAAD; + bul_kick_fsm(mbul, MIP6_BUL_FSM_EVENT_DHAAD_REPLY, NULL); + } + } +#endif /* MIP_MCOA */ + + return (0); +} + +int +receive_mpa(mpa, mpalen) + struct mip6_prefix_advert *mpa; + size_t mpalen; +{ + int error = 0; + int done = 0; + struct mip6_mipif *mif = NULL; + struct nd_opt_hdr *pt; + struct mip6_hpfx_mn_exclusive mnoption; + + /* Check MPS ID */ + LIST_FOREACH(mif, &mipifhead, mipif_entry) { + if (mif->mipif_mps_id == ntohl(mpa->mip6_pa_id)) + break; + } + if (mif == NULL) + return (0); + + memset(&ndopts, 0, sizeof(ndopts)); + error = mip6_get_nd6options(&ndopts, + (char *)mpa + sizeof(struct mip6_prefix_advert), + mpalen - sizeof(struct mip6_prefix_advert)); + + for (pt = (struct nd_opt_hdr *)ndopts.ndpi_start; + pt <= (struct nd_opt_hdr *)ndopts.ndpi_end; + pt = (struct nd_opt_hdr *)((caddr_t)pt + + (pt->nd_opt_len << 3))) { + struct nd_opt_prefix_info *pi; + + if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) + continue; + pi = (struct nd_opt_prefix_info *)pt; + + if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || + IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) + continue; + + /* aggregatable unicast address, rfc2374 XXX */ + if (pi->nd_opt_pi_prefix_len != 64) + continue; + + memset(&mnoption, 0, sizeof(mnoption)); + mnoption.hpfxlist_vltime = + ntohl(pi->nd_opt_pi_valid_time); + mnoption.hpfxlist_pltime = + ntohl(pi->nd_opt_pi_preferred_time); + + mnd_add_hpfxlist(&pi->nd_opt_pi_prefix, + pi->nd_opt_pi_prefix_len, + &mnoption, mif); + done = 1; + } + + if (!done) { + error = EINVAL; + syslog(LOG_ERR, "Could not find valid PI in MPA\n"); + } + + return (error); +} + static void terminate(dummy) int dummy; diff --git a/kame/kame/shisad/shisad.h b/kame/kame/shisad/shisad.h index aa50746e27..e390438790 100644 --- a/kame/kame/shisad/shisad.h +++ b/kame/kame/shisad/shisad.h @@ -1,4 +1,4 @@ -/* $KAME: shisad.h,v 1.18 2005/08/18 12:08:43 t-momose Exp $ */ +/* $KAME: shisad.h,v 1.19 2005/08/23 08:24:53 t-momose Exp $ */ /* * Copyright (C) 2004 WIDE Project. @@ -379,6 +379,12 @@ struct binding_cache { }; LIST_HEAD(binding_cache_head, binding_cache); +struct nd6options { + struct nd_opt_prefix_info *ndpi_start, *ndpi_end; /* could be multiple */ + struct nd_opt_adv_interval *ndadvi; + struct nd_opt_homeagent_info *ndhai; +}; +extern struct nd6options ndopts; extern int debug, namelookup; /* mh.c */ @@ -389,7 +395,6 @@ int get_mobility_options(struct ip6_mh *, int, int, struct mip6_mobility_options *); int mip6_icmp6_create_haanyaddr(struct in6_addr *, struct in6_addr *, int); int in6_mask2len(struct in6_addr *, u_char *); -struct home_agent_list *mip6_find_hal(struct mip6_hoainfo *); int mh_input(struct in6_addr *, struct in6_addr *, struct in6_addr *, struct in6_addr *, struct ip6_mh *, int); #ifdef MIP_MCOA @@ -476,21 +481,18 @@ int mipsock_nodetype_request(u_int8_t, u_int8_t); int mipsock_behint_input(struct mip_msghdr *); void icmp6sock_open(void); int icmp6_input_common(int); +int mip6_get_nd6options(struct nd6options *, char *, int); void mip6_create_addr(struct in6_addr *, const struct in6_addr *, struct in6_addr *, u_int8_t); -struct mip6_hpfxl *mip6_get_hpfxlist(struct in6_addr *, int, - struct mip6_hpfx_list *); -struct home_agent_list *mip6_get_hal(struct mip6_hpfxl *, struct in6_addr *); -void mip6_delete_hal(struct mip6_hpfxl *, struct in6_addr *); int mip6_are_prefix_equal(struct in6_addr *, struct in6_addr *, int); -void mip6_flush_hal(struct mip6_hpfxl *, int); -void mip6_delete_hpfxlist(struct in6_addr *, u_int16_t, - struct mip6_hpfx_list *); void hal_set_expire_timer(struct home_agent_list *, int); void hal_stop_expire_timer(struct home_agent_list *); -void hal_expire_timer(void *); void command_show_stat(int, char *); -void show_hal(int, struct mip6_hpfx_list *); +struct ip6_hdr; +struct ip6_rthdr2 *find_rthdr2(struct ip6_hdr *); + +/* cnd.c */ +int cn_receive_dst_unreach(struct icmp6_hdr *); /* mnd.c */ int mipsock_bul_request(struct binding_update_list *, u_char); @@ -507,20 +509,14 @@ struct mip6_hpfxl *mnd_add_hpfxlist(struct in6_addr *, struct mip6_mipif *mnd_get_mipif(u_int16_t); int send_na_home(struct in6_addr *, u_int16_t); int set_default_bu_lifetime(struct mip6_hoainfo *); +int receive_hadisc_reply(struct mip6_dhaad_rep *, size_t); +int receive_mpa(struct mip6_prefix_advert *, size_t); struct noro_host_list *noro_get(struct in6_addr *); void noro_add(struct in6_addr *); - void hpfxlist_expire_timer(void *); -void hxplist_stop_expire_timer(struct mip6_hpfxl *); -void hpfxlist_set_expire_timer(struct mip6_hpfxl *, int); - - /* had.c */ int mipsock_input(struct mip_msghdr *); -struct home_agent_list *had_add_hal(struct mip6_hpfxl *, struct in6_addr *, - struct in6_addr *, uint16_t, uint16_t, int); -struct mip6_hpfxl *had_add_hpfxlist(struct in6_addr *, u_int16_t); int had_is_ha_if(u_int16_t); #ifdef MIP_HA u_int16_t ha_if(void); @@ -531,6 +527,7 @@ struct mip6_hpfxl *had_is_myhomenet(struct in6_addr *); int send_haadrep(struct in6_addr *, struct in6_addr *, struct mip6_dhaad_req *, u_short); int send_mpa(struct in6_addr *, u_int16_t, u_short); +int relay_icmp6_error(struct icmp6_hdr *, size_t, u_short); /* nemo_var.c */ #ifdef MIP_NEMO @@ -548,6 +545,24 @@ void command_show_pt(int, char *); #endif /* MIP_NEMO */ +/* hal.c */ +struct home_agent_list *mip6_find_hal(struct mip6_hoainfo *); +struct home_agent_list *had_add_hal(struct mip6_hpfxl *, struct in6_addr *, + struct in6_addr *, uint16_t, uint16_t, int); +struct mip6_hpfxl *had_add_hpfxlist(struct in6_addr *, u_int16_t); +void mip6_flush_hal(struct mip6_hpfxl *, int); +void mip6_delete_hal(struct mip6_hpfxl *, struct in6_addr *); +struct home_agent_list *mip6_get_hal(struct mip6_hpfxl *, struct in6_addr *); +void hxplist_stop_expire_timer(struct mip6_hpfxl *); +void hpfxlist_set_expire_timer(struct mip6_hpfxl *, int); +void hal_expire_timer(void *); +void mip6_delete_hpfxlist(struct in6_addr *, u_int16_t, + struct mip6_hpfx_list *); +struct mip6_hpfxl *mip6_get_hpfxlist(struct in6_addr *, int, + struct mip6_hpfx_list *); +void show_hal(int, struct mip6_hpfx_list *); +int receive_ra(struct nd_router_advert *, size_t, int, struct in6_addr *, struct in6_addr *); + /* other utility functions */ char *hexdump(void *, size_t); const char *ip6_sprintf(const struct in6_addr *addr);