1/*	$NetBSD: netscope.c,v 1.1 2024/02/18 20:57:49 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16/*! \file */
17
18#include <inttypes.h>
19#include <stdlib.h>
20
21#include <isc/net.h>
22#include <isc/netscope.h>
23#include <isc/result.h>
24#include <isc/string.h>
25#include <isc/util.h>
26
27isc_result_t
28isc_netscope_pton(int af, char *scopename, void *addr, uint32_t *zoneid) {
29	char *ep;
30#ifdef HAVE_IF_NAMETOINDEX
31	unsigned int ifid;
32	struct in6_addr *in6;
33#endif /* ifdef HAVE_IF_NAMETOINDEX */
34	uint32_t zone = 0;
35	uint64_t llz;
36
37#ifndef HAVE_IF_NAMETOINDEX
38	UNUSED(addr);
39#endif
40
41	/* at this moment, we only support AF_INET6 */
42	if (af != AF_INET6) {
43		return (ISC_R_FAILURE);
44	}
45
46	/*
47	 * Basically, "names" are more stable than numeric IDs in terms
48	 * of renumbering, and are more preferred.  However, since there
49	 * is no standard naming convention and APIs to deal with the
50	 * names.  Thus, we only handle the case of link-local
51	 * addresses, for which we use interface names as link names,
52	 * assuming one to one mapping between interfaces and links.
53	 */
54#ifdef HAVE_IF_NAMETOINDEX
55	in6 = (struct in6_addr *)addr;
56	if (IN6_IS_ADDR_LINKLOCAL(in6) &&
57	    (ifid = if_nametoindex((const char *)scopename)) != 0)
58	{
59		zone = (uint32_t)ifid;
60	} else {
61#endif /* ifdef HAVE_IF_NAMETOINDEX */
62		llz = strtoull(scopename, &ep, 10);
63		if (ep == scopename) {
64			return (ISC_R_FAILURE);
65		}
66
67		/* check overflow */
68		zone = (uint32_t)(llz & 0xffffffffUL);
69		if (zone != llz) {
70			return (ISC_R_FAILURE);
71		}
72#ifdef HAVE_IF_NAMETOINDEX
73	}
74#endif /* ifdef HAVE_IF_NAMETOINDEX */
75
76	*zoneid = zone;
77	return (ISC_R_SUCCESS);
78}
79