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