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