Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:27:32 dillon 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(vendor)
129         int     vendor;
130 {
131         int     i;
132
133         for(i=0; vendors[i].name; i++) {
134                 if (vendors[i].type == vendor)
135                         return(vendors[i].name);
136         }
137
138         return("-");
139 }
140
141
142 /*
143  * Get adapter type
144  *
145  * Arguments:
146  *      dev     adapter code
147  *
148  * Returns:
149  *      char *  pointer to a string with the adapter type
150  *
151  */
152 char *
153 get_adapter(dev)
154         int     dev;
155 {
156         int     i;
157
158         for(i=0; adapter_types[i].name; i++) {
159                 if (adapter_types[i].type == dev)
160                         return(adapter_types[i].name);
161         }
162
163         return("-");
164 }
165
166
167 /*
168  * Get communication medium type
169  *
170  * Arguments:
171  *      media   medium code
172  *
173  * Returns:
174  *      char *  pointer to a string with the name of the medium
175  *
176  */
177 char *
178 get_media_type(media)
179         int     media;
180 {
181         int     i;
182
183         for(i=0; media_types[i].name; i++) {
184                 if (media_types[i].type == media)
185                         return(media_types[i].name);
186         }
187
188         return("-");
189 }
190
191
192 /*
193  * Get bus type
194  *
195  * Arguments:
196  *      bus     bus type code
197  *
198  * Returns:
199  *      char *  pointer to a string with the bus type
200  *
201  */
202 char *
203 get_bus_type(bus)
204         int     bus;
205 {
206         int     i;
207
208         for(i=0; bus_types[i].name; i++) {
209                 if (bus_types[i].type == bus)
210                         return(bus_types[i].name);
211         }
212
213         return("-");
214 }
215
216
217 /*
218  * Get adapter ID
219  *
220  * Get a string giving the adapter's vendor and type.
221  *
222  * Arguments:
223  *      intf    interface name
224  *
225  * Returns:
226  *      char *  pointer to a string identifying the adapter
227  *
228  */
229 char *
230 get_adapter_name(intf)
231         char    *intf;
232 {
233         int                     buf_len;
234         struct atminfreq        air;
235         struct air_cfg_rsp      *cfg;
236         static char             name[256];
237
238         /*
239          * Initialize
240          */
241         UM_ZERO(&air, sizeof(air));
242         UM_ZERO(name, sizeof(name));
243
244         /*
245          * Get configuration information from the kernel
246          */
247         air.air_opcode = AIOCS_INF_CFG;
248         strcpy(air.air_cfg_intf, intf);
249         buf_len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp));
250         if (buf_len < sizeof(struct air_cfg_rsp))
251                 return("-");
252         cfg = (struct air_cfg_rsp *) air.air_buf_addr;
253
254         /*
255          * Build a string describing the adapter
256          */
257         strcpy(name, get_vendor(cfg->acp_vendor));
258         strcat(name, " ");
259         strcat(name, get_adapter(cfg->acp_device));
260
261         UM_FREE(cfg);
262
263         return(name);
264 }
265
266
267 /*
268  * Format a MAC address into a string
269  * 
270  * Arguments:
271  *      addr    pointer to a MAC address
272  *
273  * Returns:
274  *              the address of a string representing the MAC address
275  *
276  */
277 char *
278 format_mac_addr(addr)
279         Mac_addr *addr;
280 {
281         static char     str[256];
282
283         /*
284          * Check for null pointer
285          */
286         if (!addr)
287                 return("-");
288
289         /*
290          * Clear the returned string
291          */
292         UM_ZERO(str, sizeof(str));
293
294         /*
295          * Format the address
296          */
297         sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
298                         addr->ma_data[0],
299                         addr->ma_data[1],
300                         addr->ma_data[2],
301                         addr->ma_data[3],
302                         addr->ma_data[4],
303                         addr->ma_data[5]);
304
305         return(str);
306 }
307
308
309 /*
310  * Parse an IP prefix designation in the form nnn.nnn.nnn.nnn/mm
311  *
312  * Arguments:
313  *      cp      pointer to prefix designation string
314  *      op      pointer to a pair of in_addrs for the result
315  *
316  * Returns:
317  *      0       success
318  *      -1      prefix was invalid
319  *
320  */
321 int
322 parse_ip_prefix(cp, op)
323         char            *cp;
324         struct in_addr  *op;
325 {
326         int             len;
327         char            *mp;
328         struct in_addr  ip_addr;
329
330         static u_long   masks[33] = {
331                 0x0,
332                 0x80000000,
333                 0xc0000000,
334                 0xe0000000,
335                 0xf0000000,
336                 0xf8000000,
337                 0xfc000000,
338                 0xfe000000,
339                 0xff000000,
340                 0xff800000,
341                 0xffc00000,
342                 0xffe00000,
343                 0xfff00000,
344                 0xfff80000,
345                 0xfffc0000,
346                 0xfffe0000,
347                 0xffff0000,
348                 0xffff8000,
349                 0xffffc000,
350                 0xffffe000,
351                 0xfffff000,
352                 0xfffff800,
353                 0xfffffc00,
354                 0xfffffe00,
355                 0xffffff00,
356                 0xffffff80,
357                 0xffffffc0,
358                 0xffffffe0,
359                 0xfffffff0,
360                 0xfffffff8,
361                 0xfffffffc,
362                 0xfffffffe,
363                 0xffffffff
364         };
365
366         /*
367          * Find the slash that marks the start of the mask
368          */
369         mp = strchr(cp, '/');
370         if (mp) {
371                 *mp = '\0';
372                 mp++;
373         }
374
375         /*
376          * Convert the IP-address part of the prefix
377          */
378         ip_addr.s_addr = inet_addr(cp);
379         if (ip_addr.s_addr == -1)
380                 return(-1);
381
382         /*
383          * Set the default mask length
384          */
385         if (IN_CLASSA(ntohl(ip_addr.s_addr)))
386                 len = 8;
387         else if (IN_CLASSB(ntohl(ip_addr.s_addr)))
388                 len = 16;
389         else if (IN_CLASSC(ntohl(ip_addr.s_addr)))
390                 len = 24;
391         else
392                 return(-1);
393
394         /*
395          * Get the mask length
396          */
397         if (mp) {
398                 len = atoi(mp);
399                 if (len < 1 || len > 32)
400                         return(-1);
401         }
402
403         /*
404          * Select the mask and copy the IP address into the
405          * result buffer, ANDing it with the mask
406          */
407         op[1].s_addr = htonl(masks[len]);
408         op[0].s_addr = ip_addr.s_addr & op[1].s_addr;
409
410         return(0);
411 }
412
413
414 /*
415  * Compress a list of IP network prefixes
416  *
417  * Arguments:
418  *      ipp     pointer to list of IP address/mask pairs
419  *      ipc     length of list
420  *
421  * Returns:
422  *      length of compressed list
423  *
424  */
425 int
426 compress_prefix_list(ipp, ilen)
427         struct in_addr  *ipp;
428         int             ilen;
429 {
430         int             i, j, n;
431         struct in_addr  *ip1, *ip2, *m1, *m2;
432
433         /*
434          * Figure out how many pairs there are
435          */
436         n = ilen / (sizeof(struct in_addr) * 2);
437
438         /*
439          * Check each pair of address/mask pairs to make sure
440          * none contains the other
441          */
442         for (i = 0; i < n; i++) {
443                 ip1 = &ipp[i*2];
444                 m1 = &ipp[i*2+1];
445
446                 /*
447                  * If we've already eliminated this address,
448                  * skip the checks
449                  */
450                 if (ip1->s_addr == 0)
451                         continue;
452
453                 /*
454                  * Try all possible second members of the pair
455                  */
456                 for (j = i + 1; j < n; j++) {
457                         ip2 = &ipp[j*2];
458                         m2 = &ipp[j*2+1];
459
460                         /*
461                          * If we've already eliminated the second
462                          * address, just skip the checks
463                          */
464                         if (ip2->s_addr == 0)
465                                 continue;
466
467                         /*
468                          * Compare the address/mask pairs
469                          */
470                         if (m1->s_addr == m2->s_addr) {
471                                 /*
472                                  * Masks are equal
473                                  */
474                                 if (ip1->s_addr == ip2->s_addr) {
475                                         ip2->s_addr = 0;
476                                         m2->s_addr = 0;
477                                 }
478                         } else if (ntohl(m1->s_addr) <
479                                         ntohl(m2->s_addr)) {
480                                 /*
481                                  * m1 is shorter
482                                  */
483                                 if ((ip2->s_addr & m1->s_addr) ==
484                                                 ip1->s_addr) {
485                                         ip2->s_addr = 0;
486                                         m2->s_addr = 0;
487                                 }
488                         } else {
489                                 /*
490                                  * m1 is longer
491                                  */
492                                 if ((ip1->s_addr & m2->s_addr) ==
493                                                 ip2->s_addr) {
494                                         ip1->s_addr = 0;
495                                         m1->s_addr = 0;
496                                         break;
497                                 }
498                         }
499                 }
500         }
501
502         /*
503          * Now pull up the list, eliminating zeroed entries
504          */
505         for (i = 0, j = 0; i < n; i++) {
506                 ip1 = &ipp[i*2];
507                 m1 = &ipp[i*2+1];
508                 ip2 = &ipp[j*2];
509                 m2 = &ipp[j*2+1];
510                 if (ip1->s_addr != 0) {
511                         if (i != j) {
512                                 *ip2 = *ip1;
513                                 *m2 = *m1;
514                         }
515                         j++;
516                 }
517         }
518
519         return(j * sizeof(struct in_addr) * 2);
520 }
521
522
523 /*
524  * Make sure a user-supplied parameter is a valid network interface
525  * name
526  *
527  * When a socket call fails, print an error message and exit
528  * 
529  * Arguments:
530  *      nif     pointer to network interface name
531  *
532  * Returns:
533  *      none    exits if name is not valid
534  *
535  */
536 void
537 check_netif_name(nif)
538         char    *nif;
539 {
540         int     rc;
541
542         /*
543          * Look up the name in the kernel
544          */
545         rc = verify_nif_name(nif);
546
547         /*
548          * Check the result
549          */
550         if (rc > 0) {
551                 /*
552                  * Name is OK
553                  */
554                 return;
555         } else if (rc == 0) {
556                 /*
557                  * Name is not valid
558                  */
559                 fprintf(stderr, "%s: Invalid network interface name %s\n",
560                                 prog, nif);
561         } else {
562                 /*
563                  * Error performing IOCTL
564                  */
565                 fprintf(stderr, "%s: ", prog);
566                 switch(errno) {
567                 case ENOPROTOOPT:
568                 case EOPNOTSUPP:
569                         perror("Internal error");
570                         break;
571                 case ENXIO:
572                         fprintf(stderr, "%s is not an ATM device\n",
573                                         nif);
574                         break;
575                 default:
576                         perror("ioctl (AIOCINFO)");
577                         break;
578                 }
579         }
580
581         exit(1);
582 }
583
584
585 /*
586  * Socket error handler
587  *
588  * When a socket call fails, print an error message and exit
589  * 
590  * Arguments:
591  *      err     an errno describing the error
592  *
593  * Returns:
594  *      none
595  *
596  */
597 void
598 sock_error(err)
599         int     err;
600 {
601         fprintf(stderr, "%s: ", prog);
602
603         switch (err) {
604
605         case EPROTONOSUPPORT:
606                 fprintf(stderr, "ATM protocol support not loaded\n");
607                 break;
608
609         default:
610                 perror("socket");
611                 break;
612         }
613
614         exit(1);
615 }