OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / Libnet / src / libnet_link_dlpi.c
1 /*
2  *  $Id: libnet_link_dlpi.c,v 1.1.1.1 2000/05/25 00:28:49 route Exp $
3  *
4  *  libnet
5  *  libnet_dlpi.c - dlpi routines
6  *
7  *  Copyright (c) 1998 - 2001 Mike D. Schiffman <mike@infonexus.com>
8  *  All rights reserved.
9  *
10  * Copyright (c) 1993, 1994, 1995, 1996, 1997
11  *      The Regents of the University of California.  All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that: (1) source code distributions
15  * retain the above copyright notice and this paragraph in its entirety, (2)
16  * distributions including binary code include the above copyright notice and
17  * this paragraph in its entirety in the documentation or other materials
18  * provided with the distribution, and (3) all advertising materials mentioning
19  * features or use of this software display the following acknowledgement:
20  * ``This product includes software developed by the University of California,
21  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
22  * the University nor the names of its contributors may be used to endorse
23  * or promote products derived from this software without specific prior
24  * written permission.
25  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
26  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28  *
29  * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
30  * University College London.
31  */
32
33
34 #if (HAVE_CONFIG_H)
35 #include "../include/config.h"
36 #endif
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #ifdef HAVE_SYS_BUFMOD_H
40 #include <sys/bufmod.h>
41 #endif
42 #include <sys/dlpi.h>
43 #ifdef HAVE_HPUX9
44 #include <sys/socket.h>
45 #endif
46 #ifdef DL_HP_PPA_ACK_OBS
47 #include <sys/stat.h>
48 #endif
49 #include <sys/stream.h>
50 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
51 #include <sys/systeminfo.h>
52 #endif
53
54 #ifdef HAVE_HPUX9
55 #include <net/if.h>
56 #endif
57
58 #include <ctype.h>
59 #ifdef HAVE_HPUX9
60 #include <nlist.h>
61 #endif
62 #include <errno.h>
63 #include <fcntl.h>
64 #include <memory.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <stropts.h>
69 #include <unistd.h>
70
71 #include "../include/libnet.h"
72 #include "../include/bpf.h"
73
74 #include "../include/gnuc.h"
75 #ifdef HAVE_OS_PROTO_H
76 #include "../include/os-proto.h"
77 #endif
78
79 #ifndef DLPI_DEV_PREFIX
80 #define DLPI_DEV_PREFIX "/dev"
81 #endif
82
83 #define MAXDLBUF 8192
84
85 /* Forwards */
86 static int dlattachreq(int, bpf_u_int32, char *);
87 static int dlbindack(int, char *, char *);
88 static int dlbindreq(int, bpf_u_int32, char *);
89 static int dlinfoack(int, char *, char *);
90 static int dlinforeq(int, char *);
91 static int dlokack(int, const char *, char *, char *);
92 static int recv_ack(int, int, const char *, char *, char *);
93 static int send_request(int, char *, int, char *, char *, int);
94 #ifdef HAVE_SYS_BUFMOD_H
95 static int strioctl(int, int, int, char *);
96 #endif
97 #ifdef HAVE_HPUX9
98 static int dlpi_kread(int, off_t, void *, u_int, char *);
99 #endif
100 #ifdef HAVE_DEV_DLPI
101 static int get_dlpi_ppa(int, const char *, int, char *);
102 #endif
103
104 /* XXX Needed by HP-UX (at least) */
105 static bpf_u_int32 ctlbuf[MAXDLBUF];
106
107
108 struct libnet_link_int *
109 libnet_open_link_interface(char *device, char *ebuf)
110 {
111     register char *cp;
112     char *eos;
113     register struct libnet_link_int *l;
114     register int ppa;
115     register dl_info_ack_t *infop;
116     bpf_u_int32 buf[MAXDLBUF];
117     char dname[100];
118 #ifndef HAVE_DEV_DLPI
119     char dname2[100];
120 #endif
121
122     l = (struct libnet_link_int *)malloc(sizeof(*l));
123     if (l == NULL)
124     {
125         strcpy(ebuf, ll_strerror(errno));
126         return (NULL);
127     }
128     memset(l, 0, sizeof(*l));
129
130     /*
131      *  Determine device and ppa
132      */
133     cp = strpbrk(device, "0123456789");
134     if (cp == NULL)
135     {
136         sprintf(ebuf, "%s missing unit number", device);
137         goto bad;
138     }
139     ppa = strtol(cp, &eos, 10);
140     if (*eos != '\0')
141     {
142         sprintf(ebuf, "%s bad unit number", device);
143         goto bad;
144     }
145
146     if (*device == '/')
147     {
148         memset(&dname, 0, sizeof(dname));
149         strncpy(dname, device, sizeof(dname) - 1);
150     }
151     else
152     {
153         sprintf(dname, "%s/%s", DLPI_DEV_PREFIX, device);
154     }
155 #ifdef HAVE_DEV_DLPI
156     /*
157      *  Map network device to /dev/dlpi unit
158      */
159     cp = "/dev/dlpi";
160
161     l->fd = open(cp, O_RDWR);
162     if (l->fd == -1)
163     {
164         sprintf(ebuf, "%s: %s", cp, ll_strerror(errno));
165         goto bad;
166     }
167
168     /*
169      *  Map network interface to /dev/dlpi unit
170      */
171     ppa = get_dlpi_ppa(l->fd, dname, ppa, ebuf);
172     if (ppa < 0)
173     {
174         goto bad;
175     }
176 #else
177     /*
178      *  Try device without unit number
179      */
180     strcpy(dname2, dname);
181     cp = strchr(dname, *cp);
182     *cp = '\0';
183
184     l->fd = open(dname, O_RDWR);
185     if (l->fd == -1)
186     {
187         if (errno != ENOENT)
188         {
189             sprintf(ebuf, "%s: %s", dname, ll_strerror(errno));
190             goto bad;
191         }
192
193         /*
194          *  Try again with unit number
195          */
196         l->fd = open(dname2, O_RDWR);
197         if (l->fd == -1)
198         {
199             sprintf(ebuf, "%s: %s", dname2, ll_strerror(errno));
200             goto bad;
201         }
202
203         cp = dname2;
204         while (*cp && !isdigit((int)*cp)) cp++;
205         if (*cp) ppa = atoi(cp);
206         else
207         /*
208          *  XXX Assume unit zero
209          */
210         ppa = 0;
211     }
212 #endif
213     /*
214      *  Attach if "style 2" provider
215      */
216     if (dlinforeq(l->fd, ebuf) < 0 || dlinfoack(l->fd, (char *)buf, ebuf) < 0)
217     {
218         goto bad;
219     }
220     infop = &((union DL_primitives *)buf)->info_ack;
221     if (infop->dl_provider_style == DL_STYLE2 && (dlattachreq(l->fd, ppa, ebuf)
222         < 0 || dlokack(l->fd, "attach", (char *)buf, ebuf) < 0))
223     {
224         goto bad;
225     }
226
227     /*
228      *  Bind HP-UX 9 and HP-UX 10.20
229      */
230 #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20) || defined(HAVE_SOLARIS)
231     if (dlbindreq(l->fd, 0, ebuf) < 0 || dlbindack(l->fd, (char *)buf, ebuf) < 0)
232     {
233         goto bad;
234     }
235 #endif
236
237     /*
238      *  Determine link type
239      */
240     if (dlinforeq(l->fd, ebuf) < 0 || dlinfoack(l->fd, (char *)buf, ebuf) < 0)
241     {
242         goto bad;
243     }
244
245     infop = &((union DL_primitives *)buf)->info_ack;
246     switch (infop->dl_mac_type)
247     {
248         case DL_CSMACD:
249         case DL_ETHER:
250             l->linktype = DLT_EN10MB;
251             break;
252         case DL_FDDI:
253             l->linktype = DLT_FDDI;
254             break;
255         default:
256             sprintf(ebuf, "unknown mac type 0x%lu", infop->dl_mac_type);
257             goto bad;
258     }
259
260 #ifdef  DLIOCRAW
261     /*
262      *  This is a non standard SunOS hack to get the ethernet header.
263      */
264     if (strioctl(l->fd, DLIOCRAW, 0, NULL) < 0)
265     {
266         sprintf(ebuf, "DLIOCRAW: %s", ll_strerror(errno));
267         goto bad;
268     }
269 #endif
270
271     return (l);
272 bad:
273     free(l);
274     return (NULL);
275 }
276
277
278 static int
279 send_request(int fd, char *ptr, int len, char *what, char *ebuf, int flags)
280 {
281     struct strbuf ctl;
282
283     ctl.maxlen = 0;
284     ctl.len = len;
285     ctl.buf = ptr;
286
287     if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0)
288     {
289         sprintf(ebuf, "send_request: putmsg \"%s\": %s", what, ll_strerror(errno));
290         return (-1);
291     }
292     return (0);
293 }
294
295 static int
296 recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
297 {
298     union DL_primitives *dlp;
299     struct strbuf ctl;
300     int flags;
301
302     ctl.maxlen = MAXDLBUF;
303     ctl.len = 0;
304     ctl.buf = bufp;
305
306     flags = 0;
307     if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0)
308     {
309         sprintf(ebuf, "recv_ack: %s getmsg: %s", what, ll_strerror(errno));
310         return (-1);
311     }
312
313     dlp = (union DL_primitives *)ctl.buf;
314     switch (dlp->dl_primitive)
315     {
316         case DL_INFO_ACK:
317         case DL_PHYS_ADDR_ACK:
318         case DL_BIND_ACK:
319         case DL_OK_ACK:
320 #ifdef DL_HP_PPA_ACK
321         case DL_HP_PPA_ACK:
322 #endif
323         /*
324          *  These are OK
325          */
326         break;
327
328         case DL_ERROR_ACK:
329             switch (dlp->error_ack.dl_errno)
330             {
331                 case DL_BADPPA:
332                     sprintf(ebuf, "recv_ack: %s bad ppa (device unit)", what);
333                     break;
334                 case DL_SYSERR:
335                     sprintf(ebuf, "recv_ack: %s: %s",
336                         what, ll_strerror(dlp->error_ack.dl_unix_errno));
337                     break;
338                 case DL_UNSUPPORTED:
339                     sprintf(ebuf,
340                         "recv_ack: %s: Service not supplied by provider", what);
341                     break;
342                 default:
343                     sprintf(ebuf, "recv_ack: %s error 0x%x", what,
344                         (bpf_u_int32)dlp->error_ack.dl_errno);
345                     break;
346             }
347             return (-1);
348
349         default:
350             sprintf(ebuf, "recv_ack: %s unexpected primitive ack 0x%x ",
351                 what, (bpf_u_int32)dlp->dl_primitive);
352             return (-1);
353     }
354
355     if (ctl.len < size)
356     {
357         sprintf(ebuf, "recv_ack: %s ack too small (%d < %d)",
358             what, ctl.len, size);
359         return (-1);
360     }
361     return (ctl.len);
362 }
363
364 static int
365 dlpromiscoffreq(int fd, bpf_u_int32 level, char *ebuf)
366 {
367     dl_promiscon_req_t req;
368
369     req.dl_primitive = DL_PROMISCOFF_REQ;
370     req.dl_level     = level;
371
372     return (send_request(fd, (char *)&req, sizeof(req), "promiscoff", ebuf, 0));
373 }
374
375 static int
376 dlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
377 {
378     dl_promiscon_req_t req;
379
380     req.dl_primitive = DL_PROMISCON_REQ;
381     req.dl_level     = level;
382
383     return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf, 0));
384 }
385
386
387 static int
388 dlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
389 {
390     dl_attach_req_t req;
391
392     req.dl_primitive = DL_ATTACH_REQ;
393     req.dl_ppa       = ppa;
394
395     return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf, 0));
396 }
397
398 static int
399 dlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
400 {
401
402     dl_bind_req_t       req;
403
404     memset((char *)&req, 0, sizeof(req));
405     req.dl_primitive = DL_BIND_REQ;
406 #ifdef DL_HP_RAWDLS
407     req.dl_max_conind = 1;  /* XXX magic number */
408     /*
409      *  22 is INSAP as per the HP-UX DLPI Programmer's Guide
410      */
411     req.dl_sap = 22;
412     req.dl_service_mode = DL_HP_RAWDLS;
413 #else
414     req.dl_sap = sap;
415 #ifdef DL_CLDLS
416     req.dl_service_mode = DL_CLDLS;
417 #endif
418 #endif
419     return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf, 0));
420 }
421
422
423 static int
424 dlbindack(int fd, char *bufp, char *ebuf)
425 {
426     return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
427 }
428
429
430 static int
431 dlokack(int fd, const char *what, char *bufp, char *ebuf)
432 {
433     return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
434 }
435
436
437 static int
438 dlinforeq(int fd, char *ebuf)
439 {
440     dl_info_req_t req;
441
442     req.dl_primitive = DL_INFO_REQ;
443
444     return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf, RS_HIPRI));
445 }
446
447 static int
448 dlinfoack(int fd, char *bufp, char *ebuf)
449 {
450     return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
451 }
452
453
454 #ifdef HAVE_SYS_BUFMOD_H
455 static int
456 strioctl(int fd, int cmd, int len, char *dp)
457 {
458     struct strioctl str;
459     int rc;
460
461     str.ic_cmd    = cmd;
462     str.ic_timout = -1;
463     str.ic_len    = len;
464     str.ic_dp     = dp;
465     
466     rc = ioctl(fd, I_STR, &str);
467     if (rc < 0)
468     {
469         return (rc);
470     }
471     else
472     {
473         return (str.ic_len);
474     }
475 }
476 #endif
477
478
479 #ifdef DL_HP_PPA_ACK_OBS
480 /*
481  * Under HP-UX 10, we can ask for the ppa
482  */
483 static int
484 get_dlpi_ppa(register int fd, register const char *device, register int unit,
485     register char *ebuf)
486 {
487     register dl_hp_ppa_ack_t *ap;
488     register dl_hp_ppa_info_t *ip;
489     register int i;
490     register u_long majdev;
491     dl_hp_ppa_req_t     req;
492     struct stat statbuf;
493     bpf_u_int32 buf[MAXDLBUF];
494
495     if (stat(device, &statbuf) < 0)
496     {
497         sprintf(ebuf, "stat: %s: %s", device, ll_strerror(errno));
498         return (-1);
499     }
500     majdev = major(statbuf.st_rdev);
501
502     memset((char *)&req, 0, sizeof(req));
503     req.dl_primitive = DL_HP_PPA_REQ;
504
505     memset((char *)buf, 0, sizeof(buf));
506     if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf, 0) < 0 ||
507         recv_ack(fd, DL_HP_PPA_ACK_SIZE, "hpppa", (char *)buf, ebuf) < 0)
508     {
509         return (-1);
510     }
511
512     ap = (dl_hp_ppa_ack_t *)buf;
513     ip = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset);
514
515     for (i = 0; i < ap->dl_count; i++)
516     {
517         if (ip->dl_mjr_num == majdev && ip->dl_instance_num == unit)
518         break;
519
520         ip = (dl_hp_ppa_info_t *)((u_char *)ip + ip->dl_next_offset);
521     }
522
523     if (i == ap->dl_count)
524     {
525         sprintf(ebuf, "can't find PPA for %s", device);
526         return (-1);
527     }
528
529     if (ip->dl_hdw_state == HDW_DEAD)
530     {
531         sprintf(ebuf, "%s: hardware state: DOWN\n", device);
532         return (-1);
533     }
534     return ((int)ip->dl_ppa);
535 }
536 #endif
537
538 #ifdef HAVE_HPUX9
539 /*
540  * Under HP-UX 9, there is no good way to determine the ppa.
541  * So punt and read it from /dev/kmem.
542  */
543 static struct nlist nl[] =
544 {
545 #define NL_IFNET 0
546     { "ifnet" },
547     { "" }
548 };
549
550 static char path_vmunix[] = "/hp-ux";
551
552 /*
553  *  Determine ppa number that specifies ifname
554  */
555 static int
556 get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
557     register char *ebuf)
558 {
559     register const char *cp;
560     register int kd;
561     void *addr;
562     struct ifnet ifnet;
563     char if_name[sizeof(ifnet.if_name)], tifname[32];
564
565     cp = strrchr(ifname, '/');
566     if (cp != NULL)
567     {
568         ifname = cp + 1;
569     }
570     if (nlist(path_vmunix, &nl) < 0)
571     {
572         sprintf(ebuf, "nlist %s failed", path_vmunix);
573         return (-1);
574     }
575
576     if (nl[NL_IFNET].n_value == 0)
577     {
578         sprintf(ebuf, "could't find %s kernel symbol", nl[NL_IFNET].n_name);
579         return (-1);
580     }
581
582     kd = open("/dev/kmem", O_RDONLY);
583     if (kd < 0)
584     {
585         sprintf(ebuf, "kmem open: %s", ll_strerror(errno));
586         return (-1);
587     }
588
589     if (dlpi_kread(kd, nl[NL_IFNET].n_value, &addr, sizeof(addr), ebuf) < 0)
590     {
591         close(kd);
592         return (-1);
593     }
594     for (; addr != NULL; addr = ifnet.if_next)
595     {
596         if (dlpi_kread(kd, (off_t)addr, &ifnet, sizeof(ifnet), ebuf) < 0 ||
597             dlpi_kread(kd, (off_t)ifnet.if_name,
598             if_name, sizeof(if_name), ebuf) < 0)
599             {
600                 close(kd);
601                 return (-1);
602             }
603             sprintf(tifname, "%.*s%d",
604                 (int)sizeof(if_name), if_name, ifnet.if_unit);
605             if (strcmp(tifname, ifname) == 0)
606             {
607                 return (ifnet.if_index);
608             }
609     }
610
611     sprintf(ebuf, "Can't find %s", ifname);
612     return (-1);
613 }
614
615 static int
616 dlpi_kread(register int fd, register off_t addr,
617     register void *buf, register u_int len, register char *ebuf)
618 {
619     register int cc;
620
621     if (lseek(fd, addr, SEEK_SET) < 0)
622     {
623         sprintf(ebuf, "lseek: %s", ll_strerror(errno));
624         return (-1);
625     }
626     cc = read(fd, buf, len);
627     if (cc < 0)
628     {
629         sprintf(ebuf, "read: %s", ll_strerror(errno));
630         return (-1);
631     }
632     else if (cc != len)
633     {
634         sprintf(ebuf, "short read (%d != %d)", cc, len);
635         return (-1);
636     }
637     return (cc);
638 }
639 #endif
640
641 /*#include <netinet/if_ether.h>*/
642 #define ETHERADDRL 6
643 struct  EnetHeaderInfo
644 {
645     struct ether_addr   DestEtherAddr;
646     u_short             EtherFrameType;
647 };
648
649
650 int
651 libnet_close_link_interface(struct libnet_link_int *l)
652 {
653     if (close(l->fd) == 0)  
654     {
655         return (1);
656     }
657     else
658     {
659         return (-1);
660     }
661 }
662
663
664 struct EnetHeaderInfo ArpHeader =
665 {
666     {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, ETHERTYPE_ARP
667 };
668
669
670 int
671 libnet_write_link_layer(struct libnet_link_int *l, const char *device,
672             u_char *buf, int len)
673 {
674     struct strbuf data, ctl;
675     union DL_primitives *dlp;
676     int c;
677     struct EnetHeaderInfo *EnetHeaderInfoP;
678
679     dlp = (union DL_primitives*) ctlbuf;
680     dlp->unitdata_req.dl_primitive        = DL_UNITDATA_REQ;
681     dlp->unitdata_req.dl_priority.dl_min  = 0;
682     dlp->unitdata_req.dl_priority.dl_max  = 0;
683     dlp->unitdata_req.dl_dest_addr_length = (sizeof(struct ether_addr) +
684                                             sizeof(u_short));
685     dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
686
687     EnetHeaderInfoP = (struct EnetHeaderInfo *)(ctlbuf + DL_UNITDATA_REQ_SIZE);
688     memcpy(EnetHeaderInfoP, (char *)&(ArpHeader), (sizeof(struct ether_addr) +
689                                                   sizeof(u_short)));
690
691     /* Send it */
692     ctl.len = DL_UNITDATA_REQ_SIZE + sizeof (struct EnetHeaderInfo);
693     ctl.buf = (char *)dlp;
694
695     data.maxlen = len;
696     data.len    = len;
697     data.buf    = buf;
698
699     c = putmsg(l->fd, NULL, &data, 0);
700     if (c == -1)
701     {
702 #if (__DEBUG)
703         fprintf(stderr, "write_link_layer: (%s)\n", strerror(errno));
704 #endif
705         return (-1);
706     }
707     return (len);
708 }
709
710
711 struct ether_addr *
712 libnet_get_hwaddr(struct libnet_link_int *l, const char *device, char *ebuf)
713 {
714     char    buf[2048];
715     union DL_primitives *dlp;
716     struct ether_addr *eap;
717
718     dlp = (union DL_primitives*) buf;
719
720     dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
721     dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;
722
723     if (send_request(l->fd, (char *)dlp, DL_PHYS_ADDR_REQ_SIZE, "physaddr",
724                     ebuf, 0) < 0)
725     {
726         sprintf(ebuf, "get_hwaddr %s", strerror(errno));
727         return (NULL);
728     }
729     if (recv_ack(l->fd, DL_PHYS_ADDR_ACK_SIZE, "physaddr", (char *)dlp, ebuf)
730         < 0)
731     {
732         sprintf(ebuf, "get_hwaddr %s", strerror(errno));
733         return (NULL);
734     }
735
736     eap = (struct ether_addr *)
737         ((char *) dlp + dlp->physaddr_ack.dl_addr_offset);
738     return (eap);
739 }   
740
741 /* EOF */