]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libncp/ipx.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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. 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/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <sys/time.h>
38
39 #include <arpa/inet.h>
40 #include <net/if.h>
41 #include <net/if_var.h>
42 #include <net/if_dl.h>
43 #include <net/if_types.h>
44 #include <net/route.h>
45
46 /* IPX */
47 #include <netipx/ipx.h>
48 #include <netipx/ipx_if.h>
49
50 #include <ctype.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 #include <netncp/ncp_lib.h>
60
61 #define IPX_NODE_LEN    6
62
63 typedef u_long          IPXNet;
64 typedef u_short         IPXPort;
65 typedef union ipx_host  IPXNode;
66
67
68 void
69 ipx_fprint_node(FILE * file, IPXNode node){
70         fprintf(file, "%02X%02X%02X%02X%02X%02X",
71                 (unsigned char) node.c_host[0],
72                 (unsigned char) node.c_host[1],
73                 (unsigned char) node.c_host[2],
74                 (unsigned char) node.c_host[3],
75                 (unsigned char) node.c_host[4],
76                 (unsigned char) node.c_host[5]
77             );
78 }
79
80 void
81 ipx_fprint_network(FILE * file, const IPXNet net){
82         fprintf(file, "%08X", (u_int32_t)ntohl(net));
83 }
84
85 void
86 ipx_fprint_port(FILE * file, IPXPort port)
87 {
88         fprintf(file, "%04X", ntohs(port));
89 }
90
91 void
92 ipx_fprint_addr(FILE * file, struct ipx_addr *ipx)
93 {
94         ipx_fprint_network(file, ipx_netlong(*ipx));
95         fprintf(file, ":");
96         ipx_fprint_node(file, ipx->x_host);
97         fprintf(file, ":");
98         ipx_fprint_port(file, ipx->x_port);
99 }
100
101 void
102 ipx_print_node(IPXNode node)
103 {
104         ipx_fprint_node(stdout, node);
105 }
106
107 void
108 ipx_print_network(IPXNet net)
109 {
110         ipx_fprint_network(stdout, net);
111 }
112
113 void
114 ipx_print_port(IPXPort port)
115 {
116         ipx_fprint_port(stdout, port);
117 }
118
119 void
120 ipx_print_addr(struct ipx_addr *ipx)
121 {
122         ipx_fprint_addr(stdout, ipx);
123 }
124
125 int
126 ipx_sscanf_node(char *buf, unsigned char node[6])
127 {
128         int i;
129         int n[6];
130
131         if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
132                         &(n[0]), &(n[1]), &(n[2]),
133                         &(n[3]), &(n[4]), &(n[5]))) != 6)
134         {
135                 return i;
136         }
137         for (i = 0; i < 6; i++)
138         {
139                 node[i] = n[i];
140         }
141         return 6;
142 }
143
144 int
145 ipx_sscanf_saddr(char *buf, struct sockaddr_ipx *target)
146 {
147         char *p;
148         struct sockaddr_ipx addr;
149         unsigned long sipx_net;
150
151         addr.sipx_family = AF_IPX;
152 /*!!    addr.sipx_type = NCP_PTYPE;*/
153
154         if (sscanf(buf, "%lx", &sipx_net) != 1)
155         {
156                 return 1;
157         }
158         ((union ipx_net_u*)(&addr.sipx_addr.x_net))->long_e = htonl(sipx_net);
159         if ((p = strchr(buf, ':')) == NULL){
160                 return 1;
161         }
162         p += 1;
163         if (ipx_sscanf_node(p, addr.sipx_node) != 6)
164         {
165                 return 1;
166         }
167         if ((p = strchr(p, ':')) == NULL)
168         {
169                 return 1;
170         }
171         p += 1;
172         if (sscanf(p, "%hx", &addr.sipx_port) != 1)
173         {
174                 return 1;
175         }
176         addr.sipx_port = htons(addr.sipx_port);
177         *target = addr;
178         return 0;
179 }
180
181
182 void ipx_assign_node(IPXNode *dest, IPXNode *src) {
183         memcpy(dest, src, IPX_NODE_LEN);
184 }
185
186
187 static void     rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
188 static int      if_ipxscan(int addrcount, struct sockaddr_dl *sdl,
189                     struct if_msghdr *ifm, struct ifa_msghdr *ifam,
190                     struct ipx_addr *addr);
191
192 /*
193  * Find an IPX interface. 
194  * ifname specifies interface name, if NULL search for all interfaces
195  *        if ifname[0]='0', also all interfaces, but return its name
196  * addr   on input preferred net address can be specified or 0 for any,
197  *        on return contains full address (except port)
198  * returns 0 if interface was found
199  */
200 int
201 ipx_iffind(char *ifname,struct ipx_addr *addr){
202         char name[32];
203         int all=0, flags, foundit = 0, addrcount;
204         struct  if_msghdr *ifm, *nextifm;
205         struct  ifa_msghdr *ifam;
206         struct  sockaddr_dl *sdl;
207         char    *buf, *lim, *next;
208         size_t  needed;
209         int mib[6];
210         
211         if( ifname!=NULL ) {
212             strncpy(name,ifname,sizeof(name)-1);
213             if( name[0]==0 )
214                 all=1;
215         } else
216             all = 1;
217
218         mib[0] = CTL_NET;
219         mib[1] = PF_ROUTE;
220         mib[2] = 0;
221         mib[3] = AF_IPX;
222         mib[4] = NET_RT_IFLIST;
223         mib[5] = 0;
224
225         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
226                 return(1);
227         if ((buf = malloc(needed)) == NULL)
228                 return(1);
229         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
230                 free(buf);
231                 return(1);
232         }
233         lim = buf + needed;
234
235         next = buf;
236         while (next < lim) {
237                 ifm = (struct if_msghdr *)next;
238                 if (ifm->ifm_type == RTM_IFINFO) {
239                         sdl = (struct sockaddr_dl *)(ifm + 1);
240                         flags = ifm->ifm_flags;
241                 } else {
242                         fprintf(stderr, "if_ipxfind: out of sync parsing NET_RT_IFLIST\n");
243                         fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, ifm->ifm_type);
244                         fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
245                         fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, lim);
246                         free(buf);
247                         return(1);
248                 }
249
250                 next += ifm->ifm_msglen;
251                 ifam = NULL;
252                 addrcount = 0;
253                 while (next < lim) {
254                         nextifm = (struct if_msghdr *)next;
255                         if (nextifm->ifm_type != RTM_NEWADDR)
256                                 break;
257                         if (ifam == NULL)
258                                 ifam = (struct ifa_msghdr *)nextifm;
259                         addrcount++;
260                         next += nextifm->ifm_msglen;
261                 }
262
263                 if (all) {
264                         if ((flags & IFF_UP) == 0)
265                                 continue; /* not up */
266                         strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
267                         name[sdl->sdl_nlen] = '\0';
268                 } else {
269                         if (strlen(name) != sdl->sdl_nlen)
270                                 continue; /* not same len */
271                         if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
272                                 continue; /* not same name */
273                 }
274
275                 foundit=if_ipxscan(addrcount, sdl, ifm, ifam, addr);
276                 if( foundit ) {
277                         if( ifname!=NULL && ifname[0]==0) {
278                             strncpy(ifname,sdl->sdl_data, sdl->sdl_nlen);
279                             ifname[sdl->sdl_nlen]=0;
280                         }
281                         break;
282                 }
283         }
284         free(buf);
285
286         return foundit ? 0:1;
287 }
288
289
290 int
291 if_ipxscan(addrcount, sdl, ifm, ifam, addr)
292         int addrcount;
293         struct  sockaddr_dl *sdl;
294         struct if_msghdr *ifm;
295         struct ifa_msghdr *ifam;
296         struct ipx_addr *addr;
297 {
298         struct  rt_addrinfo info;
299         struct sockaddr_ipx *sipx;
300         int s;
301
302         if ((s = socket(AF_IPX, SOCK_DGRAM, 0)) < 0) {
303                 perror("ifconfig: socket");
304                 return 0;
305         }
306
307         while (addrcount > 0) {
308                 info.rti_addrs = ifam->ifam_addrs;
309                 /* Expand the compacted addresses */
310                 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
311                 addrcount--;
312                 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
313                 if (info.rti_info[RTAX_IFA]->sa_family == AF_IPX) {
314                         sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
315                         if( ipx_nullnet(sipx->sipx_addr) ) continue;
316                         if( ipx_nullnet(*addr) || 
317                             ipx_neteq(sipx->sipx_addr,*addr) ) {
318                             *addr=sipx->sipx_addr;
319                             close(s);
320                             return(1);
321                         }
322                 }
323         }
324         close(s);
325         return(0);
326 }
327 /*
328  * Expand the compacted form of addresses as returned via the
329  * configuration read via sysctl().
330  */
331
332 #define ROUNDUP(a) \
333         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
334 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
335
336 static void
337 rt_xaddrs(cp, cplim, rtinfo)
338         caddr_t cp, cplim;
339         struct rt_addrinfo *rtinfo;
340 {
341         struct sockaddr *sa;
342         int i;
343
344         memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
345         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
346                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
347                         continue;
348                 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
349                 ADVANCE(cp, sa);
350         }
351 }
352