171333Sitojun/* $FreeBSD$ */ 2118664Sume/* $KAME: rrenum.c,v 1.12 2002/06/10 19:59:47 itojun Exp $ */ 362656Skris 455505Sshin/* 555505Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 655505Sshin * All rights reserved. 755505Sshin * 855505Sshin * Redistribution and use in source and binary forms, with or without 955505Sshin * modification, are permitted provided that the following conditions 1055505Sshin * are met: 1155505Sshin * 1. Redistributions of source code must retain the above copyright 1255505Sshin * notice, this list of conditions and the following disclaimer. 1355505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455505Sshin * notice, this list of conditions and the following disclaimer in the 1555505Sshin * documentation and/or other materials provided with the distribution. 1655505Sshin * 3. Neither the name of the project nor the names of its contributors 1755505Sshin * may be used to endorse or promote products derived from this software 1855505Sshin * without specific prior written permission. 1955505Sshin * 2055505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055505Sshin * SUCH DAMAGE. 3155505Sshin */ 3278064Sume#include <sys/types.h> 3355505Sshin#include <sys/param.h> 3455505Sshin#include <sys/ioctl.h> 3555505Sshin#include <sys/socket.h> 3655505Sshin#include <sys/sysctl.h> 3755505Sshin 3855505Sshin#include <net/if.h> 39224144Shrs#include <net/if_dl.h> 4055505Sshin#include <net/if_var.h> 4155505Sshin#include <net/route.h> 4255505Sshin#include <netinet/in.h> 4355505Sshin#include <netinet/in_var.h> 4455505Sshin#include <netinet/icmp6.h> 4555505Sshin 4655505Sshin#include <arpa/inet.h> 4755505Sshin 4855505Sshin#include <errno.h> 49222732Shrs#include <netdb.h> 5055505Sshin#include <string.h> 5155505Sshin#include <stdlib.h> 52253970Shrs#include <time.h> 5355505Sshin#include <syslog.h> 5478064Sume#include "rtadvd.h" 5555505Sshin#include "rrenum.h" 5655505Sshin#include "if.h" 5755505Sshin 5855505Sshin#define RR_ISSET_SEGNUM(segnum_bits, segnum) \ 5955505Sshin ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) 6055505Sshin#define RR_SET_SEGNUM(segnum_bits, segnum) \ 6155505Sshin (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) 6255505Sshin 6355505Sshinstruct rr_operation { 6455505Sshin u_long rro_seqnum; 6555505Sshin u_long rro_segnum_bits[8]; 6655505Sshin}; 6755505Sshin 6862656Skrisstatic struct rr_operation rro; 6962656Skrisstatic int rr_rcvifindex; 7062656Skrisstatic int rrcmd2pco[RPM_PCO_MAX] = { 7162656Skris 0, 7262656Skris SIOCAIFPREFIX_IN6, 7362656Skris SIOCCIFPREFIX_IN6, 7462656Skris SIOCSGIFPREFIX_IN6 7555505Sshin}; 7662656Skrisstatic int s = -1; 7755505Sshin 7855505Sshin/* 7955505Sshin * Check validity of a Prefix Control Operation(PCO). 80222732Shrs * return 0 on success, 1 on failure. 8155505Sshin */ 8255505Sshinstatic int 8355505Sshinrr_pco_check(int len, struct rr_pco_match *rpm) 8455505Sshin{ 8555505Sshin struct rr_pco_use *rpu, *rpulim; 8655505Sshin int checklen; 8755505Sshin 8855505Sshin /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ 8955505Sshin if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ 9055505Sshin (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ 9155505Sshin syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", 92222732Shrs __func__, rpm->rpm_len); 93222732Shrs return (1); 9455505Sshin } 9555505Sshin /* rpm->rpm_code must be valid value */ 96118664Sume switch (rpm->rpm_code) { 9755505Sshin case RPM_PCO_ADD: 9855505Sshin case RPM_PCO_CHANGE: 9955505Sshin case RPM_PCO_SETGLOBAL: 10055505Sshin break; 10155505Sshin default: 102118660Sume syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__, 103222732Shrs rpm->rpm_code); 104222732Shrs return (1); 10555505Sshin } 10655505Sshin /* rpm->rpm_matchlen must be 0 to 128 inclusive */ 10755505Sshin if (rpm->rpm_matchlen > 128) { 10855505Sshin syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", 109222732Shrs __func__, rpm->rpm_matchlen); 110222732Shrs return (1); 11155505Sshin } 11255505Sshin 11355505Sshin /* 11455505Sshin * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be 11555505Sshin * between 0 and 128 inclusive 11655505Sshin */ 11755505Sshin for (rpu = (struct rr_pco_use *)(rpm + 1), 11855505Sshin rpulim = (struct rr_pco_use *)((char *)rpm + len); 11955505Sshin rpu < rpulim; 12055505Sshin rpu += 1) { 12155505Sshin checklen = rpu->rpu_uselen; 12255505Sshin checklen += rpu->rpu_keeplen; 12355505Sshin /* 12455505Sshin * omit these check, because either of rpu_uselen 12555505Sshin * and rpu_keeplen is unsigned char 12655505Sshin * (128 > rpu_uselen > 0) 12755505Sshin * (128 > rpu_keeplen > 0) 12855505Sshin * (rpu_uselen + rpu_keeplen > 0) 12955505Sshin */ 13055505Sshin if (checklen > 128) { 13155505Sshin syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" 132222732Shrs " rpu_keeplen %d is %d(over 128)", 133222732Shrs __func__, rpu->rpu_uselen, rpu->rpu_keeplen, 134222732Shrs rpu->rpu_uselen + rpu->rpu_keeplen); 135222732Shrs return (1); 13655505Sshin } 13755505Sshin } 138222732Shrs return (0); 13955505Sshin} 14055505Sshin 14155505Sshinstatic void 14278064Sumedo_use_prefix(int len, struct rr_pco_match *rpm, 143222732Shrs struct in6_rrenumreq *irr, int ifindex) 14478064Sume{ 14555505Sshin struct rr_pco_use *rpu, *rpulim; 14678064Sume struct rainfo *rai; 147224144Shrs struct ifinfo *ifi; 148222732Shrs struct prefix *pfx; 14955505Sshin 15055505Sshin rpu = (struct rr_pco_use *)(rpm + 1); 15155505Sshin rpulim = (struct rr_pco_use *)((char *)rpm + len); 15255505Sshin 15378064Sume if (rpu == rpulim) { /* no use prefix */ 15455505Sshin if (rpm->rpm_code == RPM_PCO_ADD) 15555505Sshin return; 15655505Sshin 15755505Sshin irr->irr_u_uselen = 0; 15855505Sshin irr->irr_u_keeplen = 0; 15955505Sshin irr->irr_raf_mask_onlink = 0; 16055505Sshin irr->irr_raf_mask_auto = 0; 16155505Sshin irr->irr_vltime = 0; 16255505Sshin irr->irr_pltime = 0; 16355505Sshin memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); 16455505Sshin irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ 16555505Sshin irr->irr_useprefix.sin6_family = 0; 16655505Sshin irr->irr_useprefix.sin6_addr = in6addr_any; 16755505Sshin if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 16855505Sshin errno != EADDRNOTAVAIL) 169118660Sume syslog(LOG_ERR, "<%s> ioctl: %s", __func__, 170222732Shrs strerror(errno)); 17155505Sshin return; 17255505Sshin } 17355505Sshin 17455505Sshin for (rpu = (struct rr_pco_use *)(rpm + 1), 17555505Sshin rpulim = (struct rr_pco_use *)((char *)rpm + len); 17655505Sshin rpu < rpulim; 17755505Sshin rpu += 1) { 17855505Sshin /* init in6_rrenumreq fields */ 17955505Sshin irr->irr_u_uselen = rpu->rpu_uselen; 18055505Sshin irr->irr_u_keeplen = rpu->rpu_keeplen; 18155505Sshin irr->irr_raf_mask_onlink = 182222732Shrs !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 18355505Sshin irr->irr_raf_mask_auto = 184222732Shrs !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 18578064Sume irr->irr_vltime = ntohl(rpu->rpu_vltime); 18678064Sume irr->irr_pltime = ntohl(rpu->rpu_pltime); 18755505Sshin irr->irr_raf_onlink = 188222732Shrs (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 189222732Shrs 0 : 1; 19055505Sshin irr->irr_raf_auto = 191222732Shrs (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 192222732Shrs 0 : 1; 19355505Sshin irr->irr_rrf_decrvalid = 194222732Shrs (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 195222732Shrs 0 : 1; 19655505Sshin irr->irr_rrf_decrprefd = 197222732Shrs (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 198222732Shrs 0 : 1; 19955505Sshin irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); 20055505Sshin irr->irr_useprefix.sin6_family = AF_INET6; 20155505Sshin irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; 20255505Sshin 20355505Sshin if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 20455505Sshin errno != EADDRNOTAVAIL) 205118660Sume syslog(LOG_ERR, "<%s> ioctl: %s", __func__, 206222732Shrs strerror(errno)); 20778064Sume 20878064Sume /* very adhoc: should be rewritten */ 20978064Sume if (rpm->rpm_code == RPM_PCO_CHANGE && 21078064Sume IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) && 21178064Sume rpm->rpm_matchlen == rpu->rpu_uselen && 21278064Sume rpu->rpu_uselen == rpu->rpu_keeplen) { 213224144Shrs ifi = if_indextoifinfo(ifindex); 214224144Shrs if (ifi == NULL || ifi->ifi_rainfo == NULL) 21578064Sume continue; /* non-advertising IF */ 216224144Shrs rai = ifi->ifi_rainfo; 21778064Sume 218222732Shrs TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { 219253970Shrs struct timespec now; 22078064Sume 221222732Shrs if (prefix_match(&pfx->pfx_prefix, 222222732Shrs pfx->pfx_prefixlen, &rpm->rpm_prefix, 223222732Shrs rpm->rpm_matchlen)) { 22478064Sume /* change parameters */ 225222732Shrs pfx->pfx_validlifetime = 226222732Shrs ntohl(rpu->rpu_vltime); 227222732Shrs pfx->pfx_preflifetime = 228222732Shrs ntohl(rpu->rpu_pltime); 22978064Sume if (irr->irr_rrf_decrvalid) { 230253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, 231253970Shrs &now); 232222732Shrs pfx->pfx_vltimeexpire = 233222732Shrs now.tv_sec + 234222732Shrs pfx->pfx_validlifetime; 23578064Sume } else 236222732Shrs pfx->pfx_vltimeexpire = 0; 23778064Sume if (irr->irr_rrf_decrprefd) { 238253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, 239253970Shrs &now); 240222732Shrs pfx->pfx_pltimeexpire = 241222732Shrs now.tv_sec + 242222732Shrs pfx->pfx_preflifetime; 24378064Sume } else 244222732Shrs pfx->pfx_pltimeexpire = 0; 24578064Sume } 24678064Sume } 24778064Sume } 24855505Sshin } 24955505Sshin} 25055505Sshin 25155505Sshin/* 25255505Sshin * process a Prefix Control Operation(PCO). 25355505Sshin * return 0 on success, 1 on failure 25455505Sshin */ 25555505Sshinstatic int 25655505Sshindo_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) 25755505Sshin{ 25855505Sshin int ifindex = 0; 25955505Sshin struct in6_rrenumreq irr; 260224144Shrs struct ifinfo *ifi; 261224144Shrs 262126797Sbde if ((rr_pco_check(len, rpm) != 0)) 263222732Shrs return (1); 26455505Sshin 26562656Skris if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 266118660Sume syslog(LOG_ERR, "<%s> socket: %s", __func__, 267222732Shrs strerror(errno)); 26862656Skris exit(1); 26962656Skris } 27062656Skris 27155505Sshin memset(&irr, 0, sizeof(irr)); 27255505Sshin irr.irr_origin = PR_ORIG_RR; 27355505Sshin irr.irr_m_len = rpm->rpm_matchlen; 27455505Sshin irr.irr_m_minlen = rpm->rpm_minlen; 27555505Sshin irr.irr_m_maxlen = rpm->rpm_maxlen; 27655505Sshin irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); 27755505Sshin irr.irr_matchprefix.sin6_family = AF_INET6; 27855505Sshin irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; 27955505Sshin 28055505Sshin while (if_indextoname(++ifindex, irr.irr_name)) { 281224144Shrs ifi = if_indextoifinfo(ifindex); 282224144Shrs if (ifi == NULL) { 283224144Shrs syslog(LOG_ERR, "<%s> ifindex not found.", 284224144Shrs __func__); 285224144Shrs return (1); 286224144Shrs } 28755505Sshin /* 288222732Shrs * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and 289222732Shrs * IFF_UP is off, the interface is not applied 29055505Sshin */ 29155505Sshin if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && 292224144Shrs (ifi->ifi_flags & IFF_UP) == 0) 29355505Sshin continue; 29455505Sshin /* TODO: interface scope check */ 29578064Sume do_use_prefix(len, rpm, &irr, ifindex); 29655505Sshin } 29755505Sshin if (errno == ENXIO) 298222732Shrs return (0); 29955505Sshin else if (errno) { 300118660Sume syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__, 301222732Shrs strerror(errno)); 302222732Shrs return (1); 30355505Sshin } 304222732Shrs return (0); 30555505Sshin} 30655505Sshin 30755505Sshin/* 30855505Sshin * call do_pco() for each Prefix Control Operations(PCOs) in a received 30955505Sshin * Router Renumbering Command packet. 31055505Sshin * return 0 on success, 1 on failure 31155505Sshin */ 31255505Sshinstatic int 31355505Sshindo_rr(int len, struct icmp6_router_renum *rr) 31455505Sshin{ 31555505Sshin struct rr_pco_match *rpm; 31655505Sshin char *cp, *lim; 31755505Sshin 31855505Sshin lim = (char *)rr + len; 31955505Sshin cp = (char *)(rr + 1); 32055505Sshin len -= sizeof(struct icmp6_router_renum); 32155505Sshin 322224144Shrs update_ifinfo(&ifilist, UPDATE_IFINFO_ALL); 32355505Sshin 32455505Sshin while (cp < lim) { 32555505Sshin int rpmlen; 32655505Sshin 32755505Sshin rpm = (struct rr_pco_match *)cp; 328222732Shrs if ((size_t)len < sizeof(struct rr_pco_match)) { 32955505Sshin tooshort: 33055505Sshin syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " 331250302Seadler "garbage at end of pkt?", __func__, len); 332222732Shrs return (1); 33355505Sshin } 33455505Sshin rpmlen = rpm->rpm_len << 3; 33555505Sshin if (len < rpmlen) 33655505Sshin goto tooshort; 33755505Sshin 33855505Sshin if (do_pco(rr, rpmlen, rpm)) { 339118660Sume syslog(LOG_WARNING, "<%s> invalid PCO", __func__); 34055505Sshin goto next; 34155505Sshin } 34255505Sshin 34355505Sshin next: 34455505Sshin cp += rpmlen; 34555505Sshin len -= rpmlen; 34655505Sshin } 34762656Skris 348222732Shrs return (0); 34955505Sshin} 35055505Sshin 35155505Sshin/* 35255505Sshin * check validity of a router renumbering command packet 35355505Sshin * return 0 on success, 1 on failure 35455505Sshin */ 35555505Sshinstatic int 35655505Sshinrr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, 357222732Shrs struct in6_addr *dst) 35855505Sshin{ 35955505Sshin u_char ntopbuf[INET6_ADDRSTRLEN]; 36055505Sshin 36155505Sshin /* omit rr minimal length check. hope kernel have done it. */ 36255505Sshin /* rr_command length check */ 363222732Shrs if ((size_t)len < (sizeof(struct icmp6_router_renum) + 364222732Shrs sizeof(struct rr_pco_match))) { 36555505Sshin syslog(LOG_ERR, "<%s> rr_command len %d is too short", 366222732Shrs __func__, len); 367222732Shrs return (1); 36855505Sshin } 36955505Sshin 37055505Sshin /* destination check. only for multicast. omit unicast check. */ 37155505Sshin if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && 37255505Sshin !IN6_IS_ADDR_MC_SITELOCAL(dst)) { 37355505Sshin syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", 374222732Shrs __func__, 375222732Shrs inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf))); 376222732Shrs return (1); 37755505Sshin } 37855505Sshin 37955505Sshin /* seqnum and segnum check */ 38055505Sshin if (rro.rro_seqnum > rr->rr_seqnum) { 38155505Sshin syslog(LOG_WARNING, 382222732Shrs "<%s> rcvd old seqnum %d from %s", 383222732Shrs __func__, (u_int32_t)ntohl(rr->rr_seqnum), 384222732Shrs inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf))); 385222732Shrs return (1); 38655505Sshin } 38755505Sshin if (rro.rro_seqnum == rr->rr_seqnum && 38855505Sshin (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && 38955505Sshin RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { 39055505Sshin if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) 39155505Sshin syslog(LOG_WARNING, 392222732Shrs "<%s> rcvd duped segnum %d from %s", 393222732Shrs __func__, rr->rr_segnum, inet_ntop(AF_INET6, from, 394222732Shrs ntopbuf, sizeof(ntopbuf))); 395222732Shrs return (0); 39655505Sshin } 39755505Sshin 39855505Sshin /* update seqnum */ 39955505Sshin if (rro.rro_seqnum != rr->rr_seqnum) { 40055505Sshin /* then must be "<" */ 40155505Sshin 40255505Sshin /* init rro_segnum_bits */ 40355505Sshin memset(rro.rro_segnum_bits, 0, 404222732Shrs sizeof(rro.rro_segnum_bits)); 40555505Sshin } 40655505Sshin rro.rro_seqnum = rr->rr_seqnum; 40755505Sshin 408222732Shrs return (0); 40955505Sshin} 41055505Sshin 41155505Sshinstatic void 41255505Sshinrr_command_input(int len, struct icmp6_router_renum *rr, 413222732Shrs struct in6_addr *from, struct in6_addr *dst) 41455505Sshin{ 41555505Sshin /* rr_command validity check */ 41655505Sshin if (rr_command_check(len, rr, from, dst)) 41755505Sshin goto failed; 41855505Sshin if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == 41955505Sshin ICMP6_RR_FLAGS_TEST) 42055505Sshin return; 42155505Sshin 42255505Sshin /* do router renumbering */ 423222732Shrs if (do_rr(len, rr)) 42455505Sshin goto failed; 42555505Sshin 42655505Sshin /* update segnum */ 42755505Sshin RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); 42855505Sshin 42955505Sshin return; 43055505Sshin 43155505Sshin failed: 432118660Sume syslog(LOG_ERR, "<%s> received RR was invalid", __func__); 43355505Sshin return; 43455505Sshin} 43555505Sshin 43655505Sshinvoid 43755505Sshinrr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, 438222732Shrs struct sockaddr_in6 *from, struct in6_addr *dst) 43955505Sshin{ 44055505Sshin u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 44155505Sshin 44255505Sshin syslog(LOG_DEBUG, 443222732Shrs "<%s> RR received from %s to %s on %s", 444222732Shrs __func__, 445222732Shrs inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])), 446222732Shrs inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), 447222732Shrs if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 44855505Sshin 44978064Sume /* packet validation based on Section 4.1 of RFC2894 */ 450222732Shrs if ((size_t)len < sizeof(struct icmp6_router_renum)) { 45178064Sume syslog(LOG_NOTICE, 452222732Shrs "<%s>: RR short message (size %d) from %s to %s on %s", 453222732Shrs __func__, len, 454222732Shrs inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0], 455222732Shrs sizeof(ntopbuf[0])), 456222732Shrs inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), 457222732Shrs if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 45878064Sume return; 45978064Sume } 46078064Sume 46178064Sume /* 46278064Sume * If the IPv6 destination address is neither an All Routers multicast 46378064Sume * address [AARCH] nor one of the receiving router's unicast addresses, 46478064Sume * the message MUST be discarded and SHOULD be logged to network 46578064Sume * management. 46678064Sume * We rely on the kernel input routine for unicast addresses, and thus 46778064Sume * check multicast destinations only. 46878064Sume */ 469222732Shrs if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL( 470222732Shrs &sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) { 47178064Sume syslog(LOG_NOTICE, 472222732Shrs "<%s>: RR message with invalid destination (%s) " 473222732Shrs "from %s on %s", 474222732Shrs __func__, 475222732Shrs inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])), 476222732Shrs inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1], 477222732Shrs sizeof(ntopbuf[1])), 478222732Shrs if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 47978064Sume return; 48078064Sume } 48178064Sume 48255505Sshin rr_rcvifindex = pi->ipi6_ifindex; 48355505Sshin 48455505Sshin switch (rr->rr_code) { 48555505Sshin case ICMP6_ROUTER_RENUMBERING_COMMAND: 48655505Sshin rr_command_input(len, rr, &from->sin6_addr, dst); 48755505Sshin /* TODO: send reply msg */ 48855505Sshin break; 48955505Sshin case ICMP6_ROUTER_RENUMBERING_RESULT: 49055505Sshin /* RESULT will be processed by rrenumd */ 49155505Sshin break; 49255505Sshin case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 49355505Sshin /* TODO: sequence number reset */ 49455505Sshin break; 49555505Sshin default: 49655505Sshin syslog(LOG_ERR, "<%s> received unknown code %d", 497222732Shrs __func__, rr->rr_code); 49855505Sshin break; 49955505Sshin 50055505Sshin } 50155505Sshin 50255505Sshin return; 50355505Sshin} 504