K&R style function removal. Update functions to ANSI style.
[dragonfly.git] / sbin / atm / atm / atm_subr.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sbin/atm/atm/atm_subr.c,v 1.3.2.1 2000/07/01 06:02:14 ps Exp $
27  *      @(#) $DragonFly: src/sbin/atm/atm/atm_subr.c,v 1.3 2003/09/28 14:39:16 hmp Exp $
28  */
29
30 /*
31  * User configuration and display program
32  * --------------------------------------
33  *
34  * General subroutines
35  *
36  */
37
38 #include <sys/param.h>  
39 #include <sys/socket.h> 
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <netatm/port.h>
43 #include <netatm/atm.h>
44 #include <netatm/atm_if.h> 
45 #include <netatm/atm_sap.h>
46 #include <netatm/atm_sys.h>
47 #include <netatm/atm_ioctl.h>
48 #include <arpa/inet.h>
49
50 #include <errno.h>
51 #include <libatm.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55
56 #include "atm.h"
57
58 /*
59  * Table entry definition
60  */
61 typedef struct {
62         int     type;
63         char    *name;
64 } tbl_ent;
65
66
67 /*
68  * Table to translate vendor codes to ASCII
69  */
70 tbl_ent vendors[] = {
71         { VENDAPI_UNKNOWN,      "Unknown" },
72         { VENDAPI_FORE_1,       "Fore" },
73         { VENDAPI_ENI_1,        "ENI" },
74         { 0,                    0 },
75 };
76
77
78 /*
79  * Table to translate adapter codes to ASCII
80  */
81 tbl_ent adapter_types[] = {
82         { DEV_UNKNOWN,          "Unknown" },
83         { DEV_FORE_SBA200E,     "SBA-200E" },
84         { DEV_FORE_SBA200,      "SBA-200" },
85         { DEV_FORE_PCA200E,     "PCA-200E" },
86         { DEV_ENI_155P,         "ENI-155p" },
87         { 0,                    0 },
88 };
89
90 /*
91  * Table to translate medium types to ASCII
92  */
93 tbl_ent media_types[] = {
94         { MEDIA_UNKNOWN,        "Unknown" },
95         { MEDIA_TAXI_100,       "100 Mbps 4B/5B" },
96         { MEDIA_TAXI_140,       "140 Mbps 4B/5B" },
97         { MEDIA_OC3C,           "OC-3c" },
98         { MEDIA_OC12C,          "OC-12c" },
99         { MEDIA_UTP155,         "155 Mbps UTP" },
100         { 0,                    0 },
101 };
102
103 /*
104  * Table to translate bus types to ASCII
105  */
106 tbl_ent bus_types[] = {
107         { BUS_UNKNOWN,  "Unknown" },
108         { BUS_SBUS_B16, "SBus" },
109         { BUS_SBUS_B32, "SBus" },
110         { BUS_PCI,      "PCI" },
111         { 0,                    0 },
112 };
113
114
115 /*
116  * Get interface vendor name
117  *
118  * Return a character string with a vendor name, given a vendor code.
119  * 
120  * Arguments:
121  *      vendor  vendor ID
122  *
123  * Returns:
124  *      char *  pointer to a string with the vendor name
125  *
126  */
127 char *
128 get_vendor(int vendor)
129 {
130         int     i;
131
132         for(i=0; vendors[i].name; i++) {
133                 if (vendors[i].type == vendor)
134                         return(vendors[i].name);
135         }
136
137         return("-");
138 }
139
140
141 /*
142  * Get adapter type
143  *
144  * Arguments:
145  *      dev     adapter code
146  *
147  * Returns:
148  *      char *  pointer to a string with the adapter type
149  *
150  */
151 char *
152 get_adapter(int dev)
153 {
154         int     i;
155
156         for(i=0; adapter_types[i].name; i++) {
157                 if (adapter_types[i].type == dev)
158                         return(adapter_types[i].name);
159         }
160
161         return("-");
162 }
163
164
165 /*
166  * Get communication medium type
167  *
168  * Arguments:
169  *      media   medium code
170  *
171  * Returns:
172  *      char *  pointer to a string with the name of the medium
173  *
174  */
175 char *
176 get_media_type(int media)
177 {
178         int     i;
179
180         for(i=0; media_types[i].name; i++) {
181                 if (media_types[i].type == media)
182                         return(media_types[i].name);
183         }
184
185         return("-");
186 }
187
188
189 /*
190  * Get bus type
191  *
192  * Arguments:
193  *      bus     bus type code
194  *
195  * Returns:
196  *      char *  pointer to a string with the bus type
197  *
198  */
199 char *
200 get_bus_type(int bus)
201 {
202         int     i;
203
204         for(i=0; bus_types[i].name; i++) {
205                 if (bus_types[i].type == bus)
206                         return(bus_types[i].name);
207         }
208
209         return("-");
210 }
211
212
213 /*
214  * Get adapter ID
215  *
216  * Get a string giving the adapter's vendor and type.
217  *
218  * Arguments:
219  *      intf    interface name
220  *
221  * Returns:
222  *      char *  pointer to a string identifying the adapter
223  *
224  */
225 char *
226 get_adapter_name(char *intf)
227 {
228         int                     buf_len;
229         struct atminfreq        air;
230         struct air_cfg_rsp      *cfg;
231         static char             name[256];
232
233         /*
234          * Initialize
235          */
236         UM_ZERO(&air, sizeof(air));
237         UM_ZERO(name, sizeof(name));
238
239         /*
240          * Get configuration information from the kernel
241          */
242         air.air_opcode = AIOCS_INF_CFG;
243         strcpy(air.air_cfg_intf, intf);
244         buf_len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp));
245         if (buf_len < sizeof(struct air_cfg_rsp))
246                 return("-");
247         cfg = (struct air_cfg_rsp *) air.air_buf_addr;
248
249         /*
250          * Build a string describing the adapter
251          */
252         strcpy(name, get_vendor(cfg->acp_vendor));
253         strcat(name, " ");
254         strcat(name, get_adapter(cfg->acp_device));
255
256         UM_FREE(cfg);
257
258         return(name);
259 }
260
261
262 /*
263  * Format a MAC address into a string
264  * 
265  * Arguments:
266  *      addr    pointer to a MAC address
267  *
268  * Returns:
269  *              the address of a string representing the MAC address
270  *
271  */
272 char *
273 format_mac_addr(Mac_addr *addr)
274 {
275         static char     str[256];
276
277         /*
278          * Check for null pointer
279          */
280         if (!addr)
281                 return("-");
282
283         /*
284          * Clear the returned string
285          */
286         UM_ZERO(str, sizeof(str));
287
288         /*
289          * Format the address
290          */
291         sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
292                         addr->ma_data[0],
293                         addr->ma_data[1],
294                         addr->ma_data[2],
295                         addr->ma_data[3],
296                         addr->ma_data[4],
297                         addr->ma_data[5]);
298
299         return(str);
300 }
301
302
303 /*
304  * Parse an IP prefix designation in the form nnn.nnn.nnn.nnn/mm
305  *
306  * Arguments:
307  *      cp      pointer to prefix designation string
308  *      op      pointer to a pair of in_addrs for the result
309  *
310  * Returns:
311  *      0       success
312  *      -1      prefix was invalid
313  *
314  */
315 int
316 parse_ip_prefix(char *cp, struct in_addr *op)
317 {
318         int             len;
319         char            *mp;
320         struct in_addr  ip_addr;
321
322         static u_long   masks[33] = {
323                 0x0,
324                 0x80000000,
325                 0xc0000000,
326                 0xe0000000,
327                 0xf0000000,
328                 0xf8000000,
329                 0xfc000000,
330                 0xfe000000,
331                 0xff000000,
332                 0xff800000,
333                 0xffc00000,
334                 0xffe00000,
335                 0xfff00000,
336                 0xfff80000,
337                 0xfffc0000,
338                 0xfffe0000,
339                 0xffff0000,
340                 0xffff8000,
341                 0xffffc000,
342                 0xffffe000,
343                 0xfffff000,
344                 0xfffff800,
345                 0xfffffc00,
346                 0xfffffe00,
347                 0xffffff00,
348                 0xffffff80,
349                 0xffffffc0,
350                 0xffffffe0,
351                 0xfffffff0,
352                 0xfffffff8,
353                 0xfffffffc,
354                 0xfffffffe,
355                 0xffffffff
356         };
357
358         /*
359          * Find the slash that marks the start of the mask
360          */
361         mp = strchr(cp, '/');
362         if (mp) {
363                 *mp = '\0';
364                 mp++;
365         }
366
367         /*
368          * Convert the IP-address part of the prefix
369          */
370         ip_addr.s_addr = inet_addr(cp);
371         if (ip_addr.s_addr == -1)
372                 return(-1);
373
374         /*
375          * Set the default mask length
376          */
377         if (IN_CLASSA(ntohl(ip_addr.s_addr)))
378                 len = 8;
379         else if (IN_CLASSB(ntohl(ip_addr.s_addr)))
380                 len = 16;
381         else if (IN_CLASSC(ntohl(ip_addr.s_addr)))
382                 len = 24;
383         else
384                 return(-1);
385
386         /*
387          * Get the mask length
388          */
389         if (mp) {
390                 len = atoi(mp);
391                 if (len < 1 || len > 32)
392                         return(-1);
393         }
394
395         /*
396          * Select the mask and copy the IP address into the
397          * result buffer, ANDing it with the mask
398          */
399         op[1].s_addr = htonl(masks[len]);
400         op[0].s_addr = ip_addr.s_addr & op[1].s_addr;
401
402         return(0);
403 }
404
405
406 /*
407  * Compress a list of IP network prefixes
408  *
409  * Arguments:
410  *      ipp     pointer to list of IP address/mask pairs
411  *      ipc     length of list
412  *
413  * Returns:
414  *      length of compressed list
415  *
416  */
417 int
418 compress_prefix_list(struct in_addr *ipp, int ilen)
419 {
420         int             i, j, n;
421         struct in_addr  *ip1, *ip2, *m1, *m2;
422
423         /*
424          * Figure out how many pairs there are
425          */
426         n = ilen / (sizeof(struct in_addr) * 2);
427
428         /*
429          * Check each pair of address/mask pairs to make sure
430          * none contains the other
431          */
432         for (i = 0; i < n; i++) {
433                 ip1 = &ipp[i*2];
434                 m1 = &ipp[i*2+1];
435
436                 /*
437                  * If we've already eliminated this address,
438                  * skip the checks
439                  */
440                 if (ip1->s_addr == 0)
441                         continue;
442
443                 /*
444                  * Try all possible second members of the pair
445                  */
446                 for (j = i + 1; j < n; j++) {
447                         ip2 = &ipp[j*2];
448                         m2 = &ipp[j*2+1];
449
450                         /*
451                          * If we've already eliminated the second
452                          * address, just skip the checks
453                          */
454                         if (ip2->s_addr == 0)
455                                 continue;
456
457                         /*
458                          * Compare the address/mask pairs
459                          */
460                         if (m1->s_addr == m2->s_addr) {
461                                 /*
462                                  * Masks are equal
463                                  */
464                                 if (ip1->s_addr == ip2->s_addr) {
465                                         ip2->s_addr = 0;
466                                         m2->s_addr = 0;
467                                 }
468                         } else if (ntohl(m1->s_addr) <
469                                         ntohl(m2->s_addr)) {
470                                 /*
471                                  * m1 is shorter
472                                  */
473                                 if ((ip2->s_addr & m1->s_addr) ==
474                                                 ip1->s_addr) {
475                                         ip2->s_addr = 0;
476                                         m2->s_addr = 0;
477                                 }
478                         } else {
479                                 /*
480                                  * m1 is longer
481                                  */
482                                 if ((ip1->s_addr & m2->s_addr) ==
483                                                 ip2->s_addr) {
484                                         ip1->s_addr = 0;
485                                         m1->s_addr = 0;
486                                         break;
487                                 }
488                         }
489                 }
490         }
491
492         /*
493          * Now pull up the list, eliminating zeroed entries
494          */
495         for (i = 0, j = 0; i < n; i++) {
496                 ip1 = &ipp[i*2];
497                 m1 = &ipp[i*2+1];
498                 ip2 = &ipp[j*2];
499                 m2 = &ipp[j*2+1];
500                 if (ip1->s_addr != 0) {
501                         if (i != j) {
502                                 *ip2 = *ip1;
503                                 *m2 = *m1;
504                         }
505                         j++;
506                 }
507         }
508
509         return(j * sizeof(struct in_addr) * 2);
510 }
511
512
513 /*
514  * Make sure a user-supplied parameter is a valid network interface
515  * name
516  *
517  * When a socket call fails, print an error message and exit
518  * 
519  * Arguments:
520  *      nif     pointer to network interface name
521  *
522  * Returns:
523  *      none    exits if name is not valid
524  *
525  */
526 void
527 check_netif_name(char *nif)
528 {
529         int     rc;
530
531         /*
532          * Look up the name in the kernel
533          */
534         rc = verify_nif_name(nif);
535
536         /*
537          * Check the result
538          */
539         if (rc > 0) {
540                 /*
541                  * Name is OK
542                  */
543                 return;
544         } else if (rc == 0) {
545                 /*
546                  * Name is not valid
547                  */
548                 fprintf(stderr, "%s: Invalid network interface name %s\n",
549                                 prog, nif);
550         } else {
551                 /*
552                  * Error performing IOCTL
553                  */
554                 fprintf(stderr, "%s: ", prog);
555                 switch(errno) {
556                 case ENOPROTOOPT:
557                 case EOPNOTSUPP:
558                         perror("Internal error");
559                         break;
560                 case ENXIO:
561                         fprintf(stderr, "%s is not an ATM device\n",
562                                         nif);
563                         break;
564                 default:
565                         perror("ioctl (AIOCINFO)");
566                         break;
567                 }
568         }
569
570         exit(1);
571 }
572
573
574 /*
575  * Socket error handler
576  *
577  * When a socket call fails, print an error message and exit
578  * 
579  * Arguments:
580  *      err     an errno describing the error
581  *
582  * Returns:
583  *      none
584  *
585  */
586 void
587 sock_error(int err)
588 {
589         fprintf(stderr, "%s: ", prog);
590
591         switch (err) {
592
593         case EPROTONOSUPPORT:
594                 fprintf(stderr, "ATM protocol support not loaded\n");
595                 break;
596
597         default:
598                 perror("socket");
599                 break;
600         }
601
602         exit(1);
603 }