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 63typedef u_long IPXNet; 64typedef u_short IPXPort; 65typedef union ipx_host IPXNode; 66 67 68void 69ipx_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 80void 81ipx_fprint_network(FILE * file, const IPXNet net){ 82 fprintf(file, "%08X", (u_int32_t)ntohl(net)); 83} 84 85void 86ipx_fprint_port(FILE * file, IPXPort port) 87{ 88 fprintf(file, "%04X", ntohs(port)); 89} 90 91void 92ipx_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 101void 102ipx_print_node(IPXNode node) 103{ 104 ipx_fprint_node(stdout, node); 105} 106 107void 108ipx_print_network(IPXNet net) 109{ 110 ipx_fprint_network(stdout, net); 111} 112 113void 114ipx_print_port(IPXPort port) 115{ 116 ipx_fprint_port(stdout, port); 117} 118 119void 120ipx_print_addr(struct ipx_addr *ipx) 121{ 122 ipx_fprint_addr(stdout, ipx); 123} 124 125int 126ipx_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 144int 145ipx_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 182void ipx_assign_node(IPXNode *dest, IPXNode *src) { 183 memcpy(dest, src, IPX_NODE_LEN); 184} 185 186 187static void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); 188static 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 */ 200int 201ipx_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 290int 291if_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 336static void 337rt_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 353