]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libncp/ipx.c
This commit was generated by cvs2svn to compensate for changes in r162012,
[FreeBSD/FreeBSD.git] / lib / libncp / ipx.c
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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41
42 #include <arpa/inet.h>
43 #include <net/if.h>
44 #include <net/if_var.h>
45 #include <net/if_dl.h>
46 #include <net/if_types.h>
47 #include <net/route.h>
48
49 /* IPX */
50 #include <netipx/ipx.h>
51 #include <netipx/ipx_if.h>
52
53 #include <ctype.h>
54 #include <err.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #include <netncp/ncp_lib.h>
63
64 #define IPX_NODE_LEN    6
65
66 typedef u_long          IPXNet;
67 typedef u_short         IPXPort;
68 typedef union ipx_host  IPXNode;
69
70
71 void
72 ipx_fprint_node(FILE * file, IPXNode node){
73         fprintf(file, "%02X%02X%02X%02X%02X%02X",
74                 (unsigned char) node.c_host[0],
75                 (unsigned char) node.c_host[1],
76                 (unsigned char) node.c_host[2],
77                 (unsigned char) node.c_host[3],
78                 (unsigned char) node.c_host[4],
79                 (unsigned char) node.c_host[5]
80             );
81 }
82
83 void
84 ipx_fprint_network(FILE * file, const IPXNet net){
85         fprintf(file, "%08X", (u_int32_t)ntohl(net));
86 }
87
88 void
89 ipx_fprint_port(FILE * file, IPXPort port)
90 {
91         fprintf(file, "%04X", ntohs(port));
92 }
93
94 void
95 ipx_fprint_addr(FILE * file, struct ipx_addr *ipx)
96 {
97         ipx_fprint_network(file, ipx_netlong(*ipx));
98         fprintf(file, ":");
99         ipx_fprint_node(file, ipx->x_host);
100         fprintf(file, ":");
101         ipx_fprint_port(file, ipx->x_port);
102 }
103
104 void
105 ipx_print_node(IPXNode node)
106 {
107         ipx_fprint_node(stdout, node);
108 }
109
110 void
111 ipx_print_network(IPXNet net)
112 {
113         ipx_fprint_network(stdout, net);
114 }
115
116 void
117 ipx_print_port(IPXPort port)
118 {
119         ipx_fprint_port(stdout, port);
120 }
121
122 void
123 ipx_print_addr(struct ipx_addr *ipx)
124 {
125         ipx_fprint_addr(stdout, ipx);
126 }
127
128 int
129 ipx_sscanf_node(char *buf, unsigned char node[6])
130 {
131         int i;
132         int n[6];
133
134         if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
135                         &(n[0]), &(n[1]), &(n[2]),
136                         &(n[3]), &(n[4]), &(n[5]))) != 6)
137         {
138                 return i;
139         }
140         for (i = 0; i < 6; i++)
141         {
142                 node[i] = n[i];
143         }
144         return 6;
145 }
146
147 int
148 ipx_sscanf_saddr(char *buf, struct sockaddr_ipx *target)
149 {
150         char *p;
151         struct sockaddr_ipx addr;
152         unsigned long sipx_net;
153
154         addr.sipx_family = AF_IPX;
155 /*!!    addr.sipx_type = NCP_PTYPE;*/
156
157         if (sscanf(buf, "%lx", &sipx_net) != 1)
158         {
159                 return 1;
160         }
161         ((union ipx_net_u*)(&addr.sipx_addr.x_net))->long_e = htonl(sipx_net);
162         if ((p = strchr(buf, ':')) == NULL){
163                 return 1;
164         }
165         p += 1;
166         if (ipx_sscanf_node(p, addr.sipx_node) != 6)
167         {
168                 return 1;
169         }
170         if ((p = strchr(p, ':')) == NULL)
171         {
172                 return 1;
173         }
174         p += 1;
175         if (sscanf(p, "%hx", &addr.sipx_port) != 1)
176         {
177                 return 1;
178         }
179         addr.sipx_port = htons(addr.sipx_port);
180         *target = addr;
181         return 0;
182 }
183
184
185 void ipx_assign_node(IPXNode *dest, IPXNode *src) {
186         memcpy(dest, src, IPX_NODE_LEN);
187 }
188
189
190 static void     rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
191 static int      if_ipxscan(int addrcount, struct sockaddr_dl *sdl,
192                     struct if_msghdr *ifm, struct ifa_msghdr *ifam,
193                     struct ipx_addr *addr);
194
195 /*
196  * Find an IPX interface. 
197  * ifname specifies interface name, if NULL search for all interfaces
198  *        if ifname[0]='0', also all interfaces, but return its name
199  * addr   on input preferred net address can be specified or 0 for any,
200  *        on return contains full address (except port)
201  * returns 0 if interface was found
202  */
203 int
204 ipx_iffind(char *ifname,struct ipx_addr *addr){
205         char name[32];
206         int all=0, flags, foundit = 0, addrcount;
207         struct  if_msghdr *ifm, *nextifm;
208         struct  ifa_msghdr *ifam;
209         struct  sockaddr_dl *sdl;
210         char    *buf, *lim, *next;
211         size_t  needed;
212         int mib[6];
213         
214         if( ifname!=NULL ) {
215             strncpy(name,ifname,sizeof(name)-1);
216             if( name[0]==0 )
217                 all=1;
218         } else
219             all = 1;
220
221         mib[0] = CTL_NET;
222         mib[1] = PF_ROUTE;
223         mib[2] = 0;
224         mib[3] = AF_IPX;
225         mib[4] = NET_RT_IFLIST;
226         mib[5] = 0;
227
228         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
229                 return(1);
230         if ((buf = malloc(needed)) == NULL)
231                 return(1);
232         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
233                 free(buf);
234                 return(1);
235         }
236         lim = buf + needed;
237
238         next = buf;
239         while (next < lim) {
240                 ifm = (struct if_msghdr *)next;
241                 if (ifm->ifm_type == RTM_IFINFO) {
242                         sdl = (struct sockaddr_dl *)(ifm + 1);
243                         flags = ifm->ifm_flags;
244                 } else {
245                         fprintf(stderr, "if_ipxfind: out of sync parsing NET_RT_IFLIST\n");
246                         fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, ifm->ifm_type);
247                         fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
248                         fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, lim);
249                         free(buf);
250                         return(1);
251                 }
252
253                 next += ifm->ifm_msglen;
254                 ifam = NULL;
255                 addrcount = 0;
256                 while (next < lim) {
257                         nextifm = (struct if_msghdr *)next;
258                         if (nextifm->ifm_type != RTM_NEWADDR)
259                                 break;
260                         if (ifam == NULL)
261                                 ifam = (struct ifa_msghdr *)nextifm;
262                         addrcount++;
263                         next += nextifm->ifm_msglen;
264                 }
265
266                 if (all) {
267                         if ((flags & IFF_UP) == 0)
268                                 continue; /* not up */
269                         strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
270                         name[sdl->sdl_nlen] = '\0';
271                 } else {
272                         if (strlen(name) != sdl->sdl_nlen)
273                                 continue; /* not same len */
274                         if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
275                                 continue; /* not same name */
276                 }
277
278                 foundit=if_ipxscan(addrcount, sdl, ifm, ifam, addr);
279                 if( foundit ) {
280                         if( ifname!=NULL && ifname[0]==0) {
281                             strncpy(ifname,sdl->sdl_data, sdl->sdl_nlen);
282                             ifname[sdl->sdl_nlen]=0;
283                         }
284                         break;
285                 }
286         }
287         free(buf);
288
289         return foundit ? 0:1;
290 }
291
292
293 int
294 if_ipxscan(addrcount, sdl, ifm, ifam, addr)
295         int addrcount;
296         struct  sockaddr_dl *sdl;
297         struct if_msghdr *ifm;
298         struct ifa_msghdr *ifam;
299         struct ipx_addr *addr;
300 {
301         struct  rt_addrinfo info;
302         struct sockaddr_ipx *sipx;
303         int s;
304
305         if ((s = socket(AF_IPX, SOCK_DGRAM, 0)) < 0) {
306                 perror("ifconfig: socket");
307                 return 0;
308         }
309
310         while (addrcount > 0) {
311                 info.rti_addrs = ifam->ifam_addrs;
312                 /* Expand the compacted addresses */
313                 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
314                 addrcount--;
315                 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
316                 if (info.rti_info[RTAX_IFA]->sa_family == AF_IPX) {
317                         sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
318                         if( ipx_nullnet(sipx->sipx_addr) ) continue;
319                         if( ipx_nullnet(*addr) || 
320                             ipx_neteq(sipx->sipx_addr,*addr) ) {
321                             *addr=sipx->sipx_addr;
322                             close(s);
323                             return(1);
324                         }
325                 }
326         }
327         close(s);
328         return(0);
329 }
330 /*
331  * Expand the compacted form of addresses as returned via the
332  * configuration read via sysctl().
333  */
334
335 #define ROUNDUP(a) \
336         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
337 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
338
339 static void
340 rt_xaddrs(cp, cplim, rtinfo)
341         caddr_t cp, cplim;
342         struct rt_addrinfo *rtinfo;
343 {
344         struct sockaddr *sa;
345         int i;
346
347         memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
348         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
349                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
350                         continue;
351                 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
352                 ADVANCE(cp, sa);
353         }
354 }
355