152153Sbp/*
252153Sbp * Copyright (c) 1999, Boris Popov
352153Sbp * All rights reserved.
452153Sbp *
552153Sbp * Redistribution and use in source and binary forms, with or without
652153Sbp * modification, are permitted provided that the following conditions
752153Sbp * are met:
852153Sbp * 1. Redistributions of source code must retain the above copyright
952153Sbp *    notice, this list of conditions and the following disclaimer.
1052153Sbp * 2. Redistributions in binary form must reproduce the above copyright
1152153Sbp *    notice, this list of conditions and the following disclaimer in the
1252153Sbp *    documentation and/or other materials provided with the distribution.
13165920Simp * 3. Neither the name of the author nor the names of any co-contributors
1452153Sbp *    may be used to endorse or promote products derived from this software
1552153Sbp *    without specific prior written permission.
1652153Sbp *
1752153Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1852153Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1952153Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2052153Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2152153Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2252153Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2352153Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2452153Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2552153Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2652153Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2752153Sbp * SUCH DAMAGE.
2852153Sbp */
2984213Sdillon
3084213Sdillon#include <sys/cdefs.h>
3184213Sdillon__FBSDID("$FreeBSD$");
3284213Sdillon
3352153Sbp#include <sys/param.h>
3452153Sbp#include <sys/ioctl.h>
3552153Sbp#include <sys/socket.h>
3652153Sbp#include <sys/sysctl.h>
3752153Sbp#include <sys/time.h>
3852153Sbp
3990868Smike#include <arpa/inet.h>
4052153Sbp#include <net/if.h>
4152153Sbp#include <net/if_var.h>
4252153Sbp#include <net/if_dl.h>
4352153Sbp#include <net/if_types.h>
4452153Sbp#include <net/route.h>
4552153Sbp
4652153Sbp/* IPX */
4752153Sbp#include <netipx/ipx.h>
4852153Sbp#include <netipx/ipx_if.h>
4952153Sbp
5052153Sbp#include <ctype.h>
5152153Sbp#include <err.h>
5252153Sbp#include <errno.h>
5352153Sbp#include <fcntl.h>
5452153Sbp#include <stdio.h>
5552153Sbp#include <stdlib.h>
5652153Sbp#include <string.h>
5752153Sbp#include <unistd.h>
5852153Sbp
5952153Sbp#include <netncp/ncp_lib.h>
6052153Sbp
6152153Sbp#define	IPX_NODE_LEN	6
6252153Sbp
6352153Sbptypedef u_long		IPXNet;
6452153Sbptypedef u_short		IPXPort;
6552153Sbptypedef union ipx_host	IPXNode;
6652153Sbp
6752153Sbp
6852153Sbpvoid
6952153Sbpipx_fprint_node(FILE * file, IPXNode node){
7052153Sbp	fprintf(file, "%02X%02X%02X%02X%02X%02X",
7152153Sbp		(unsigned char) node.c_host[0],
7252153Sbp		(unsigned char) node.c_host[1],
7352153Sbp		(unsigned char) node.c_host[2],
7452153Sbp		(unsigned char) node.c_host[3],
7552153Sbp		(unsigned char) node.c_host[4],
7652153Sbp		(unsigned char) node.c_host[5]
7752153Sbp	    );
7852153Sbp}
7952153Sbp
8052153Sbpvoid
8152153Sbpipx_fprint_network(FILE * file, const IPXNet net){
8252153Sbp	fprintf(file, "%08X", (u_int32_t)ntohl(net));
8352153Sbp}
8452153Sbp
8552153Sbpvoid
8652153Sbpipx_fprint_port(FILE * file, IPXPort port)
8752153Sbp{
8852153Sbp	fprintf(file, "%04X", ntohs(port));
8952153Sbp}
9052153Sbp
9152153Sbpvoid
9252153Sbpipx_fprint_addr(FILE * file, struct ipx_addr *ipx)
9352153Sbp{
9452153Sbp	ipx_fprint_network(file, ipx_netlong(*ipx));
9552153Sbp	fprintf(file, ":");
9652153Sbp	ipx_fprint_node(file, ipx->x_host);
9752153Sbp	fprintf(file, ":");
9852153Sbp	ipx_fprint_port(file, ipx->x_port);
9952153Sbp}
10052153Sbp
10152153Sbpvoid
10252153Sbpipx_print_node(IPXNode node)
10352153Sbp{
10452153Sbp	ipx_fprint_node(stdout, node);
10552153Sbp}
10652153Sbp
10752153Sbpvoid
10852153Sbpipx_print_network(IPXNet net)
10952153Sbp{
11052153Sbp	ipx_fprint_network(stdout, net);
11152153Sbp}
11252153Sbp
11352153Sbpvoid
11452153Sbpipx_print_port(IPXPort port)
11552153Sbp{
11652153Sbp	ipx_fprint_port(stdout, port);
11752153Sbp}
11852153Sbp
11952153Sbpvoid
12052153Sbpipx_print_addr(struct ipx_addr *ipx)
12152153Sbp{
12252153Sbp	ipx_fprint_addr(stdout, ipx);
12352153Sbp}
12452153Sbp
12552153Sbpint
12652153Sbpipx_sscanf_node(char *buf, unsigned char node[6])
12752153Sbp{
12852153Sbp	int i;
12952153Sbp	int n[6];
13052153Sbp
13152153Sbp	if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
13252153Sbp			&(n[0]), &(n[1]), &(n[2]),
13352153Sbp			&(n[3]), &(n[4]), &(n[5]))) != 6)
13452153Sbp	{
13552153Sbp		return i;
13652153Sbp	}
13752153Sbp	for (i = 0; i < 6; i++)
13852153Sbp	{
13952153Sbp		node[i] = n[i];
14052153Sbp	}
14152153Sbp	return 6;
14252153Sbp}
14352153Sbp
14452153Sbpint
14552153Sbpipx_sscanf_saddr(char *buf, struct sockaddr_ipx *target)
14652153Sbp{
14752153Sbp	char *p;
14852153Sbp	struct sockaddr_ipx addr;
14952153Sbp	unsigned long sipx_net;
15052153Sbp
15152153Sbp	addr.sipx_family = AF_IPX;
15252153Sbp/*!!	addr.sipx_type = NCP_PTYPE;*/
15352153Sbp
15452153Sbp	if (sscanf(buf, "%lx", &sipx_net) != 1)
15552153Sbp	{
15652153Sbp		return 1;
15752153Sbp	}
15852153Sbp	((union ipx_net_u*)(&addr.sipx_addr.x_net))->long_e = htonl(sipx_net);
15952153Sbp	if ((p = strchr(buf, ':')) == NULL){
16052153Sbp		return 1;
16152153Sbp	}
16252153Sbp	p += 1;
16352153Sbp	if (ipx_sscanf_node(p, addr.sipx_node) != 6)
16452153Sbp	{
16552153Sbp		return 1;
16652153Sbp	}
16752153Sbp	if ((p = strchr(p, ':')) == NULL)
16852153Sbp	{
16952153Sbp		return 1;
17052153Sbp	}
17152153Sbp	p += 1;
17252153Sbp	if (sscanf(p, "%hx", &addr.sipx_port) != 1)
17352153Sbp	{
17452153Sbp		return 1;
17552153Sbp	}
17652153Sbp	addr.sipx_port = htons(addr.sipx_port);
17752153Sbp	*target = addr;
17852153Sbp	return 0;
17952153Sbp}
18052153Sbp
18152153Sbp
18252153Sbpvoid ipx_assign_node(IPXNode *dest, IPXNode *src) {
18352153Sbp	memcpy(dest, src, IPX_NODE_LEN);
18452153Sbp}
18552153Sbp
18652153Sbp
18792917Sobrienstatic void	rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
18892941Sobrienstatic int	if_ipxscan(int addrcount, struct sockaddr_dl *sdl,
18992941Sobrien		    struct if_msghdr *ifm, struct ifa_msghdr *ifam,
19092941Sobrien		    struct ipx_addr *addr);
19152153Sbp
19252153Sbp/*
19352153Sbp * Find an IPX interface.
19452153Sbp * ifname specifies interface name, if NULL search for all interfaces
19552153Sbp *        if ifname[0]='0', also all interfaces, but return its name
19652153Sbp * addr   on input preferred net address can be specified or 0 for any,
19752153Sbp *        on return contains full address (except port)
19852153Sbp * returns 0 if interface was found
19952153Sbp */
20052153Sbpint
20152153Sbpipx_iffind(char *ifname,struct ipx_addr *addr){
20252153Sbp	char name[32];
20352153Sbp	int all=0, flags, foundit = 0, addrcount;
20452153Sbp	struct	if_msghdr *ifm, *nextifm;
20552153Sbp	struct	ifa_msghdr *ifam;
20652153Sbp	struct	sockaddr_dl *sdl;
20752153Sbp	char	*buf, *lim, *next;
20852153Sbp	size_t	needed;
20952153Sbp	int mib[6];
21052153Sbp
21152153Sbp	if( ifname!=NULL ) {
21252153Sbp	    strncpy(name,ifname,sizeof(name)-1);
21352153Sbp	    if( name[0]==0 )
21452153Sbp		all=1;
21552153Sbp	} else
21652153Sbp	    all = 1;
21752153Sbp
21852153Sbp	mib[0] = CTL_NET;
21952153Sbp	mib[1] = PF_ROUTE;
22052153Sbp	mib[2] = 0;
22152153Sbp	mib[3] = AF_IPX;
22252153Sbp	mib[4] = NET_RT_IFLIST;
22352153Sbp	mib[5] = 0;
22452153Sbp
22552153Sbp	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
22652153Sbp		return(1);
22752153Sbp	if ((buf = malloc(needed)) == NULL)
22852153Sbp		return(1);
22952153Sbp	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
23052153Sbp		free(buf);
23152153Sbp		return(1);
23252153Sbp	}
23352153Sbp	lim = buf + needed;
23452153Sbp
23552153Sbp	next = buf;
23652153Sbp	while (next < lim) {
23752153Sbp		ifm = (struct if_msghdr *)next;
23852153Sbp		if (ifm->ifm_type == RTM_IFINFO) {
23952153Sbp			sdl = (struct sockaddr_dl *)(ifm + 1);
24052153Sbp			flags = ifm->ifm_flags;
24152153Sbp		} else {
24252153Sbp			fprintf(stderr, "if_ipxfind: out of sync parsing NET_RT_IFLIST\n");
24352153Sbp			fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, ifm->ifm_type);
24452153Sbp			fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
24552153Sbp			fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, lim);
24652153Sbp			free(buf);
24752153Sbp			return(1);
24852153Sbp		}
24952153Sbp
25052153Sbp		next += ifm->ifm_msglen;
25152153Sbp		ifam = NULL;
25252153Sbp		addrcount = 0;
25352153Sbp		while (next < lim) {
25452153Sbp			nextifm = (struct if_msghdr *)next;
25552153Sbp			if (nextifm->ifm_type != RTM_NEWADDR)
25652153Sbp				break;
25752153Sbp			if (ifam == NULL)
25852153Sbp				ifam = (struct ifa_msghdr *)nextifm;
25952153Sbp			addrcount++;
26052153Sbp			next += nextifm->ifm_msglen;
26152153Sbp		}
26252153Sbp
26352153Sbp		if (all) {
26452153Sbp			if ((flags & IFF_UP) == 0)
26552153Sbp				continue; /* not up */
26652153Sbp			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
26752153Sbp			name[sdl->sdl_nlen] = '\0';
26852153Sbp		} else {
26952153Sbp			if (strlen(name) != sdl->sdl_nlen)
27052153Sbp				continue; /* not same len */
27152153Sbp			if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
27252153Sbp				continue; /* not same name */
27352153Sbp		}
27452153Sbp
27552153Sbp		foundit=if_ipxscan(addrcount, sdl, ifm, ifam, addr);
27652153Sbp		if( foundit ) {
27752153Sbp			if( ifname!=NULL && ifname[0]==0) {
27852153Sbp			    strncpy(ifname,sdl->sdl_data, sdl->sdl_nlen);
27952153Sbp			    ifname[sdl->sdl_nlen]=0;
28052153Sbp			}
28152153Sbp			break;
28252153Sbp		}
28352153Sbp	}
28452153Sbp	free(buf);
28552153Sbp
28652153Sbp	return foundit ? 0:1;
28752153Sbp}
28852153Sbp
28952153Sbp
29052153Sbpint
29152153Sbpif_ipxscan(addrcount, sdl, ifm, ifam, addr)
29252153Sbp	int addrcount;
29352153Sbp	struct	sockaddr_dl *sdl;
29452153Sbp	struct if_msghdr *ifm;
29552153Sbp	struct ifa_msghdr *ifam;
29652153Sbp	struct ipx_addr *addr;
29752153Sbp{
29852153Sbp	struct	rt_addrinfo info;
29952153Sbp	struct sockaddr_ipx *sipx;
30052153Sbp	int s;
30152153Sbp
30252153Sbp	if ((s = socket(AF_IPX, SOCK_DGRAM, 0)) < 0) {
30352153Sbp		perror("ifconfig: socket");
30452153Sbp		return 0;
30552153Sbp	}
30652153Sbp
30752153Sbp	while (addrcount > 0) {
30852153Sbp		info.rti_addrs = ifam->ifam_addrs;
30952153Sbp		/* Expand the compacted addresses */
31052153Sbp		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
31152153Sbp		addrcount--;
31252153Sbp		ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
31352153Sbp		if (info.rti_info[RTAX_IFA]->sa_family == AF_IPX) {
31452153Sbp			sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
31552153Sbp			if( ipx_nullnet(sipx->sipx_addr) ) continue;
31652153Sbp			if( ipx_nullnet(*addr) ||
31752153Sbp			    ipx_neteq(sipx->sipx_addr,*addr) ) {
31852153Sbp			    *addr=sipx->sipx_addr;
31952153Sbp			    close(s);
32052153Sbp			    return(1);
32152153Sbp			}
32252153Sbp		}
32352153Sbp	}
32452153Sbp	close(s);
32552153Sbp	return(0);
32652153Sbp}
32752153Sbp/*
32852153Sbp * Expand the compacted form of addresses as returned via the
32952153Sbp * configuration read via sysctl().
33052153Sbp */
33152153Sbp
33252153Sbp#define ROUNDUP(a) \
33352153Sbp	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
33452153Sbp#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
33552153Sbp
33652153Sbpstatic void
33752153Sbprt_xaddrs(cp, cplim, rtinfo)
33852153Sbp	caddr_t cp, cplim;
33952153Sbp	struct rt_addrinfo *rtinfo;
34052153Sbp{
34152153Sbp	struct sockaddr *sa;
34252153Sbp	int i;
34352153Sbp
34452153Sbp	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
34552153Sbp	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
34652153Sbp		if ((rtinfo->rti_addrs & (1 << i)) == 0)
34752153Sbp			continue;
34852153Sbp		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
34952153Sbp		ADVANCE(cp, sa);
35052153Sbp	}
35152153Sbp}
35252153Sbp
353