1/*
2 * Copyright (c) 1999, Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/param.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <sys/errno.h>
37#include <sys/syscall.h>
38#include <ctype.h>
39#include <netinet/in.h>
40#include <netipx/ipx.h>
41#include <netdb.h>
42#include <string.h>
43#include <stdio.h>
44#include <unistd.h>
45
46#include "ipxsap.h"
47#include <netncp/ncp_lib.h>
48
49static int ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name);
50
51static int
52ncp_find_server_ipx(struct ncp_conn_loginfo *li, int type) {
53	char server[NCP_BINDERY_NAME_LEN + 1];
54	int error;
55	char nearest[NCP_BINDERY_NAME_LEN + 1];
56	struct nw_property prop;
57	struct ipx_addr *n_addr = (struct ipx_addr *) &prop;
58/*	struct ncp_conn_loginfo ltmp;*/
59	int connid;
60
61	bzero(server, sizeof(server));
62	bzero(nearest, sizeof(nearest));
63
64	strcpy(server, li->server);
65	ncp_str_upper(server);
66
67	if ((error = sap_find_nearest(type, &li->ipxaddr, nearest)) != 0) {
68		return error;
69	}
70	/* if no server specified return info about nearest */
71	if (!li->server[0]) {
72		strcpy(li->server, nearest);
73		return 0;
74	}
75/*	printf("%s\n",ipx_ntoa(li->ipxaddr.sipx_addr));*/
76	if (strcmp(server, nearest) == 0) {
77		return 0;
78	}
79	/* We have to ask the nearest server for our wanted server */
80	li->opt=0;
81	if ((error = ncp_connect(li, &connid)) != 0) {
82		return error;
83	}
84	if (ncp_read_property_value(connid, type, server, 1, "NET_ADDRESS", &prop) != 0) {
85		ncp_disconnect(connid);
86		return EHOSTUNREACH;
87	}
88	if ((error = ncp_disconnect(connid)) != 0) {
89		return error;
90	}
91	li->ipxaddr.sipx_family = AF_IPX;
92	li->ipxaddr.sipx_addr.x_net = n_addr->x_net;
93	li->ipxaddr.sipx_port = n_addr->x_port;
94	li->ipxaddr.sipx_addr.x_host = n_addr->x_host;
95	return 0;
96}
97
98static int
99ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name) {
100	struct hostent* h;
101	int l;
102
103	h = gethostbyname(server_name);
104	if (!h) {
105		fprintf(stderr, "Get host address `%s': ", server_name);
106		herror(NULL);
107		return 1;
108	}
109	if (h->h_addrtype != AF_INET) {
110		fprintf(stderr, "Get host address `%s': Not AF_INET\n", server_name);
111		return 1;
112	}
113	if (h->h_length != 4) {
114		fprintf(stderr, "Get host address `%s': Bad address length\n", server_name);
115		return 1;
116	}
117	l = sizeof(struct sockaddr_in);
118	bzero(&li->inaddr, l);
119	li->inaddr.sin_len = l;
120	li->inaddr.sin_family = h->h_addrtype;
121	memcpy(&li->inaddr.sin_addr.s_addr, h->h_addr, 4);
122	li->inaddr.sin_port = htons(524); /* ncp */
123	return 0;
124}
125
126int
127ncp_find_server(struct ncp_conn_loginfo *li, int type, int af, char *name) {
128	int error = EHOSTUNREACH;
129
130	switch(af) {
131	    case AF_IPX:
132		error = ncp_find_server_ipx(li, type);
133		break;
134	    case AF_INET:
135		if (name)
136			error = ncp_find_server_in(li, type, name);
137		break;
138	    default:
139		error = EPROTONOSUPPORT;
140	}
141	return error;
142}
143
144int
145ncp_find_fileserver(struct ncp_conn_loginfo *li, int af, char *name) {
146	return ncp_find_server(li, NCP_BINDERY_FSERVER, af, name);
147}
148