1 /***********************************************************************
5 * Implementation of user-space PPPoE redirector for Linux.
7 * Functions for opening a raw socket and reading/writing raw Ethernet frames.
9 * Copyright (C) 2000-2012 by Roaring Penguin Software Inc.
11 * This program may be distributed according to the terms of the GNU
12 * General Public License, version 2 or (at your option) any later version.
16 ***********************************************************************/
18 static char const RCSID
[] =
27 #ifdef HAVE_NETPACKET_PACKET_H
28 #include <netpacket/packet.h>
29 #elif defined(HAVE_LINUX_IF_PACKET_H)
30 #include <linux/if_packet.h>
33 #ifdef HAVE_NET_ETHERNET_H
34 #include <net/ethernet.h>
37 #ifdef HAVE_ASM_TYPES_H
38 #include <asm/types.h>
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
53 #ifdef HAVE_NET_IF_ARP_H
54 #include <net/if_arp.h>
62 #include <sys/types.h>
64 #include <sys/stream.h>
65 #include <sys/stropts.h>
67 #include <sys/bufmod.h>
72 /* function declarations */
74 static void dlpromisconreq( int fd
, u_long level
);
75 void dlinforeq(int fd
);
76 void dlunitdatareq(int fd
, u_char
*addrp
, int addrlen
, u_long minpri
, u_long maxpri
, u_char
*datap
, int datalen
);
77 void dlinfoack(int fd
, char *bufp
);
78 void dlbindreq(int fd
, u_long sap
, u_long max_conind
, u_long service_mode
, u_long conn_mgmt
, u_long xidtest
);
79 void dlattachreq(int fd
, u_long ppa
);
80 void dlokack(int fd
, char *bufp
);
81 void dlbindack(int fd
, char *bufp
);
82 int strioctl(int fd
, int cmd
, int timout
, int len
, char *dp
);
83 void strgetmsg(int fd
, struct strbuf
*ctlp
, struct strbuf
*datap
, int *flagsp
, char *caller
);
84 void sigalrm(int sig
);
85 void expecting(int prim
, union DL_primitives
*dlp
);
86 static char *dlprim(u_long prim
);
88 /* #define DL_DEBUG */
90 static int dl_abssaplen
;
92 static int dl_addrlen
;
100 static unsigned char *bpfBuffer
; /* Packet filter buffer */
101 static int bpfLength
= 0; /* Packet filter buffer length */
102 int bpfSize
= 0; /* Number of unread bytes in buffer */
103 static int bpfOffset
= 0; /* Current offset in bpfBuffer */
106 /* Initialize frame types to RFC 2516 values. Some broken peers apparently
107 use different frame types... sigh... */
109 UINT16_t Eth_PPPOE_Discovery
= ETH_PPPOE_DISCOVERY
;
110 UINT16_t Eth_PPPOE_Session
= ETH_PPPOE_SESSION
;
112 /**********************************************************************
113 *%FUNCTION: etherType
115 * packet -- a received PPPoE packet
117 * ethernet packet type (see /usr/include/net/ethertypes.h)
119 * Checks the ethernet packet header to determine its type.
120 * We should only be receveing DISCOVERY and SESSION types if the BPF
121 * is set up correctly. Logs an error if an unexpected type is received.
122 * Note that the ethernet type names come from "pppoe.h" and the packet
123 * packet structure names use the LINUX dialect to maintain consistency
124 * with the rest of this file. See the BSD section of "pppoe.h" for
125 * translations of the data structure names.
126 ***********************************************************************/
128 etherType(PPPoEPacket
*packet
)
130 UINT16_t type
= (UINT16_t
) ntohs(packet
->ethHdr
.h_proto
);
131 if (type
!= Eth_PPPOE_Discovery
&& type
!= Eth_PPPOE_Session
) {
132 syslog(LOG_ERR
, "Invalid ether type 0x%x", type
);
138 /**********************************************************************
139 *%FUNCTION: getHWaddr
141 * ifname -- name of interface
142 * hwaddr -- buffer for ehthernet address
146 * Locates the Ethernet hardware address for an interface.
147 ***********************************************************************/
149 getHWaddr(int sock
, char const *ifname
, unsigned char *hwaddr
)
152 const struct sockaddr_dl
*sdl
;
154 struct ifreq ifreq
, *ifr
;
158 ifc
.ifc_len
= sizeof(inbuf
);
160 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0) {
161 fatalSys("SIOCGIFCONF");
164 ifreq
.ifr_name
[0] = '\0';
165 for (i
= 0; i
< ifc
.ifc_len
; ) {
166 ifr
= (struct ifreq
*)((caddr_t
)ifc
.ifc_req
+ i
);
167 i
+= sizeof(ifr
->ifr_name
) +
168 (ifr
->ifr_addr
.sa_len
> sizeof(struct sockaddr
)
169 ? ifr
->ifr_addr
.sa_len
170 : sizeof(struct sockaddr
));
171 if (ifr
->ifr_addr
.sa_family
== AF_LINK
) {
172 sdl
= (const struct sockaddr_dl
*) &ifr
->ifr_addr
;
173 if ((sdl
->sdl_type
== IFT_ETHER
) &&
174 (sdl
->sdl_alen
== ETH_ALEN
) &&
175 !strncmp(ifname
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
))) {
178 sprintf(buffer
, "interface %.16s has more than one ethernet address", ifname
);
182 memcpy(hwaddr
, LLADDR(sdl
), ETH_ALEN
);
189 sprintf(buffer
, "interface %.16s has no ethernet address", ifname
);
194 /**********************************************************************
195 *%FUNCTION: initFilter
197 * fd -- file descriptor of BSD device
198 * type -- Ethernet frame type (0 for watch mode)
199 * hwaddr -- buffer with ehthernet address
203 * Initializes the packet filter rules.
204 ***********************************************************************/
206 initFilter(int fd
, UINT16_t type
, unsigned char *hwaddr
)
208 /* Packet Filter Instructions:
209 * Note that the ethernet type names come from "pppoe.h" and are
210 * used here to maintain consistency with the rest of this file. */
211 static struct bpf_insn bpfRun
[] = { /* run PPPoE */
212 BPF_STMT(BPF_LD
+BPF_H
+BPF_ABS
, 12), /* ethernet type */
213 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, ETH_PPPOE_SESSION
, 5, 0),
214 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, ETH_PPPOE_DISCOVERY
, 0, 9),
215 BPF_STMT(BPF_LD
+BPF_W
+BPF_ABS
, 0), /* first word of dest. addr */
216 #define PPPOE_BCAST_CMPW 4 /* offset of word compare */
217 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, 0, 0, 2),
218 BPF_STMT(BPF_LD
+BPF_H
+BPF_ABS
, 4), /* next 1/2 word of dest. */
219 #define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
220 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, 0, 4, 0),
221 BPF_STMT(BPF_LD
+BPF_W
+BPF_ABS
, 0), /* first word of dest. addr */
222 #define PPPOE_FILTER_CMPW 8 /* offset of word compare */
223 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, 0, 0, 3),
224 BPF_STMT(BPF_LD
+BPF_H
+BPF_ABS
, 4), /* next 1/2 word of dest. */
225 #define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
226 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, 0, 0, 1),
227 BPF_STMT(BPF_RET
+BPF_K
, (u_int
) -1), /* keep packet */
228 BPF_STMT(BPF_RET
+BPF_K
, 0), /* drop packet */
231 /* Fix the potentially varying parts */
232 bpfRun
[1].code
= (u_short
) BPF_JMP
+BPF_JEQ
+BPF_K
;
235 bpfRun
[1].k
= Eth_PPPOE_Session
;
237 bpfRun
[2].code
= (u_short
) BPF_JMP
+BPF_JEQ
+BPF_K
;
240 bpfRun
[2].k
= Eth_PPPOE_Discovery
;
243 struct bpf_insn bpfInsn
[sizeof(bpfRun
) / sizeof(bpfRun
[0])];
244 struct bpf_program bpfProgram
;
245 memcpy(bpfInsn
, bpfRun
, sizeof(bpfRun
));
246 bpfInsn
[PPPOE_BCAST_CMPW
].k
= ((0xff << 24) | (0xff << 16) |
248 bpfInsn
[PPPOE_BCAST_CMPH
].k
= ((0xff << 8) | 0xff);
249 bpfInsn
[PPPOE_FILTER_CMPW
].k
= ((hwaddr
[0] << 24) | (hwaddr
[1] << 16) |
250 (hwaddr
[2] << 8) | hwaddr
[3]);
251 bpfInsn
[PPPOE_FILTER_CMPH
].k
= ((hwaddr
[4] << 8) | hwaddr
[5]);
252 bpfProgram
.bf_len
= (sizeof(bpfInsn
) / sizeof(bpfInsn
[0]));
253 bpfProgram
.bf_insns
= &bpfInsn
[0];
255 /* Apply the filter */
256 if (ioctl(fd
, BIOCSETF
, &bpfProgram
) < 0) {
257 fatalSys("ioctl(BIOCSETF)");
262 /**********************************************************************
263 *%FUNCTION: openInterface
265 * ifname -- name of interface
266 * type -- Ethernet frame type (0 for any frame type)
267 * hwaddr -- if non-NULL, set to the hardware address
269 * A file descriptor for talking with the Ethernet card. Exits on error.
270 * Note that the Linux version of this routine returns a socket instead.
272 * Opens a BPF on an interface for all PPPoE traffic (discovery and
273 * session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
274 * traffic on this network.
275 ***********************************************************************/
277 openInterface(char const *ifname
, UINT16_t type
, unsigned char *hwaddr
)
282 struct bpf_version bpf_ver
;
287 /* BSD only opens one socket for both Discovery and Session packets */
292 /* Find a free BPF device */
293 for (i
= 0; i
< 256; i
++) {
294 sprintf(bpfName
, "/dev/bpf%d", i
);
295 if (((fd
= open(bpfName
, O_RDWR
, 0)) >= 0) ||
302 case EACCES
: /* permission denied */
305 sprintf(buffer
, "Cannot open %.32s -- pppoe must be run as root.", bpfName
);
310 case ENOENT
: /* no such file */
312 rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
314 rp_fatal("All /dev/bpf* devices are in use");
321 if ((sock
= socket(AF_LOCAL
, SOCK_DGRAM
, 0)) < 0) {
325 /* Check that the interface is up */
326 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
327 if (ioctl(sock
, SIOCGIFFLAGS
, &ifr
) < 0) {
328 fatalSys("ioctl(SIOCGIFFLAGS)");
330 if ((ifr
.ifr_flags
& IFF_UP
) == 0) {
332 sprintf(buffer
, "Interface %.16s is not up", ifname
);
336 /* Fill in hardware address and initialize the packet filter rules */
337 if (hwaddr
== NULL
) {
338 rp_fatal("openInterface: no hwaddr arg.");
340 getHWaddr(sock
, ifname
, hwaddr
);
341 initFilter(fd
, type
, hwaddr
);
343 /* Sanity check on MTU -- apparently does not work on OpenBSD */
344 #if !defined(__OpenBSD__)
345 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
346 if (ioctl(sock
, SIOCGIFMTU
, &ifr
) < 0) {
347 fatalSys("ioctl(SIOCGIFMTU)");
349 if (ifr
.ifr_mtu
< ETH_DATA_LEN
) {
351 sprintf(buffer
, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
352 ifname
, ifr
.ifr_mtu
, ETH_DATA_LEN
);
357 /* done with the socket */
358 if (close(sock
) < 0) {
362 /* Check the BPF version number */
363 if (ioctl(fd
, BIOCVERSION
, &bpf_ver
) < 0) {
364 fatalSys("ioctl(BIOCVERSION)");
366 if ((bpf_ver
.bv_major
!= BPF_MAJOR_VERSION
) ||
367 (bpf_ver
.bv_minor
< BPF_MINOR_VERSION
)) {
369 sprintf(buffer
, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
370 BPF_MAJOR_VERSION
, BPF_MINOR_VERSION
,
371 bpf_ver
.bv_major
, bpf_ver
.bv_minor
);
375 /* allocate a receive packet buffer */
376 if (ioctl(fd
, BIOCGBLEN
, &bpfLength
) < 0) {
377 fatalSys("ioctl(BIOCGBLEN)");
379 if (!(bpfBuffer
= (unsigned char *) malloc(bpfLength
))) {
383 /* reads should return as soon as there is a packet available */
385 if (ioctl(fd
, BIOCIMMEDIATE
, &optval
) < 0) {
386 fatalSys("ioctl(BIOCIMMEDIATE)");
389 /* Bind the interface to the filter */
390 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
391 if (ioctl(fd
, BIOCSETIF
, &ifr
) < 0) {
393 sprintf(buffer
, "ioctl(BIOCSETIF) can't select interface %.16s",
398 syslog(LOG_INFO
, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
400 hwaddr
[0], hwaddr
[1], hwaddr
[2],
401 hwaddr
[3], hwaddr
[4], hwaddr
[5],
408 #ifdef USE_LINUX_PACKET
409 /**********************************************************************
410 *%FUNCTION: openInterface
412 * ifname -- name of interface
413 * type -- Ethernet frame type
414 * hwaddr -- if non-NULL, set to the hardware address
415 * mtu -- if non-NULL, set to the MTU
417 * A raw socket for talking to the Ethernet card. Exits on error.
419 * Opens a raw Ethernet socket
420 ***********************************************************************/
422 openInterface(char const *ifname
, UINT16_t type
, unsigned char *hwaddr
, UINT16_t
*mtu
)
429 #ifdef HAVE_STRUCT_SOCKADDR_LL
430 struct sockaddr_ll sa
;
435 memset(&sa
, 0, sizeof(sa
));
437 #ifdef HAVE_STRUCT_SOCKADDR_LL
445 if ((fd
= socket(domain
, stype
, htons(type
))) < 0) {
446 /* Give a more helpful message for the common error case */
447 if (errno
== EPERM
) {
448 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
453 if (setsockopt(fd
, SOL_SOCKET
, SO_BROADCAST
, &optval
, sizeof(optval
)) < 0) {
454 fatalSys("setsockopt");
457 /* Fill in hardware address */
459 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
460 if (ioctl(fd
, SIOCGIFHWADDR
, &ifr
) < 0) {
461 fatalSys("ioctl(SIOCGIFHWADDR)");
463 memcpy(hwaddr
, ifr
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
465 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
) {
467 sprintf(buffer
, "Interface %.16s is not Ethernet", ifname
);
471 if (NOT_UNICAST(hwaddr
)) {
474 "Interface %.16s has broadcast/multicast MAC address??",
480 /* Sanity check on MTU */
481 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
482 if (ioctl(fd
, SIOCGIFMTU
, &ifr
) < 0) {
483 fatalSys("ioctl(SIOCGIFMTU)");
485 if (ifr
.ifr_mtu
< ETH_DATA_LEN
) {
487 sprintf(buffer
, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
488 ifname
, ifr
.ifr_mtu
, ETH_DATA_LEN
);
491 if (mtu
) *mtu
= ifr
.ifr_mtu
;
493 #ifdef HAVE_STRUCT_SOCKADDR_LL
494 /* Get interface index */
495 sa
.sll_family
= AF_PACKET
;
496 sa
.sll_protocol
= htons(type
);
498 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
499 if (ioctl(fd
, SIOCGIFINDEX
, &ifr
) < 0) {
500 fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
502 sa
.sll_ifindex
= ifr
.ifr_ifindex
;
505 strcpy(sa
.sa_data
, ifname
);
508 /* We're only interested in packets on specified interface */
509 if (bind(fd
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0) {
516 #endif /* USE_LINUX */
518 /***********************************************************************
519 *%FUNCTION: sendPacket
521 * sock -- socket to send to
522 * pkt -- the packet to transmit
523 * size -- size of packet (in bytes)
525 * 0 on success; -1 on failure
528 ***********************************************************************/
530 sendPacket(PPPoEConnection
*conn
, int sock
, PPPoEPacket
*pkt
, int size
)
533 if (write(sock
, pkt
, size
) < 0) {
534 sysErr("write (sendPacket)");
537 #elif defined(HAVE_STRUCT_SOCKADDR_LL)
538 if (send(sock
, pkt
, size
, 0) < 0 && (errno
!= ENOBUFS
)) {
539 sysErr("send (sendPacket)");
545 #define ABS(x) ((x) < 0 ? -(x) : (x))
547 u_char addr
[MAXDLADDR
];
548 u_char phys
[MAXDLADDR
];
549 u_char sap
[MAXDLADDR
];
550 u_char xmitbuf
[MAXDLBUF
];
555 tmp_sap
= htons(pkt
->ethHdr
.h_proto
);
556 data_size
= size
- sizeof(struct ethhdr
);
558 memcpy((char *)phys
, (char *)pkt
->ethHdr
.h_dest
, ETHERADDRL
);
559 memcpy((char *)sap
, (char *)&tmp_sap
, sizeof(ushort_t
));
560 memcpy((char *)xmitbuf
, (char *)pkt
+ sizeof(struct ethhdr
), data_size
);
562 if (dl_saplen
> 0) { /* order is sap+phys */
563 (void) memcpy((char*)addr
, (char*)&sap
, dl_abssaplen
);
564 (void) memcpy((char*)addr
+dl_abssaplen
, (char*)phys
, ETHERADDRL
);
565 } else { /* order is phys+sap */
566 (void) memcpy((char*)addr
, (char*)phys
, ETHERADDRL
);
567 (void) memcpy((char*)addr
+ETHERADDRL
, (char*)&sap
, dl_abssaplen
);
571 printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
572 addr
[0],addr
[1],addr
[2],addr
[3],addr
[4],addr
[5],
576 dlunitdatareq(sock
, addr
, dl_addrlen
, 0, 0, xmitbuf
, data_size
);
584 rp_fatal("relay and server not supported on Linux 2.0 kernels");
586 strcpy(sa
.sa_data
, conn
->ifName
);
587 if (sendto(sock
, pkt
, size
, 0, &sa
, sizeof(sa
)) < 0) {
588 sysErr("sendto (sendPacket)");
597 /***********************************************************************
598 *%FUNCTION: clearPacketHeader
600 * pkt -- packet that needs its head clearing
604 * Clears a PPPoE packet header after a truncated packet has been
605 * received. Insures that the packet will fail any integrity tests
606 * and will be discarded by upper level routines. Also resets the
607 * bpfSize and bpfOffset variables to force a new read on the next
608 * call to receivePacket().
609 ***********************************************************************/
611 clearPacketHeader(PPPoEPacket
*pkt
)
613 bpfSize
= bpfOffset
= 0;
614 memset(pkt
, 0, HDR_SIZE
);
618 /***********************************************************************
619 *%FUNCTION: receivePacket
621 * sock -- socket to read from
622 * pkt -- place to store the received packet
623 * size -- set to size of packet in bytes
625 * >= 0 if all OK; < 0 if error
628 ***********************************************************************/
630 receivePacket(int sock
, PPPoEPacket
*pkt
, int *size
)
638 if ((bpfSize
= read(sock
, bpfBuffer
, bpfLength
)) < 0) {
639 sysErr("read (receivePacket)");
643 if (bpfSize
< sizeof(hdr
)) {
644 syslog(LOG_ERR
, "Truncated bpf packet header: len=%d", bpfSize
);
645 clearPacketHeader(pkt
); /* resets bpfSize and bpfOffset */
648 memcpy(&hdr
, bpfBuffer
+ bpfOffset
, sizeof(hdr
));
649 if (hdr
.bh_caplen
!= hdr
.bh_datalen
) {
650 syslog(LOG_ERR
, "Truncated bpf packet: caplen=%d, datalen=%d",
651 hdr
.bh_caplen
, hdr
.bh_datalen
);
652 clearPacketHeader(pkt
); /* resets bpfSize and bpfOffset */
655 seglen
= hdr
.bh_hdrlen
+ hdr
.bh_caplen
;
656 if (seglen
> bpfSize
) {
657 syslog(LOG_ERR
, "Truncated bpf packet: seglen=%d, bpfSize=%d",
659 clearPacketHeader(pkt
); /* resets bpfSize and bpfOffset */
662 seglen
= BPF_WORDALIGN(seglen
);
663 *size
= copylen
= ((hdr
.bh_caplen
< sizeof(PPPoEPacket
)) ?
664 hdr
.bh_caplen
: sizeof(PPPoEPacket
));
665 memcpy(pkt
, bpfBuffer
+ bpfOffset
+ hdr
.bh_hdrlen
, copylen
);
666 if (seglen
>= bpfSize
) {
667 bpfSize
= bpfOffset
= 0;
678 data
.buf
= (char *) pkt
;
679 data
.maxlen
= MAXDLBUF
;
682 if ((retval
= getmsg(sock
, NULL
, &data
, &flags
)) < 0) {
683 sysErr("read (receivePacket)");
690 if ((*size
= recv(sock
, pkt
, sizeof(PPPoEPacket
), 0)) < 0) {
691 sysErr("recv (receivePacket)");
700 /**********************************************************************
701 *%FUNCTION: openInterface
703 * ifname -- name of interface
704 * type -- Ethernet frame type
705 * hwaddr -- if non-NULL, set to the hardware address
707 * A raw socket for talking to the Ethernet card. Exits on error.
709 * Opens a raw Ethernet socket
710 ***********************************************************************/
712 openInterface(char const *ifname
, UINT16_t type
, unsigned char *hwaddr
)
717 union DL_primitives
*dlp
;
719 char base_dev
[PATH_MAX
];
722 if(strlen(ifname
) > PATH_MAX
) {
723 rp_fatal("socket: Interface name too long");
726 if (strlen(ifname
) < 2) {
727 rp_fatal("socket: Interface name too short");
730 ppa
= atoi(&ifname
[strlen(ifname
)-1]);
731 strncpy(base_dev
, ifname
, PATH_MAX
);
732 base_dev
[strlen(base_dev
)-1] = '\0';
734 /* rearranged order of DLPI code - delphys 20010803 */
735 dlp
= (union DL_primitives
*) buf
;
737 if ( (fd
= open(base_dev
, O_RDWR
)) < 0) {
738 /* Give a more helpful message for the common error case */
739 if (errno
== EPERM
) {
740 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
742 /* Common error is to omit /dev/ */
743 if (errno
== ENOENT
) {
745 snprintf(ifname
, sizeof(ifname
), "/dev/%s", base_dev
);
746 if ((fd
= open(ifname
, O_RDWR
)) < 0) {
747 if (errno
== EPERM
) {
748 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
757 /* rearranged order of DLPI code - delphys 20010803 */
758 dlattachreq(fd
, ppa
);
759 dlokack(fd
, (char *)buf
);
761 dlbindreq(fd
, type
, 0, DL_CLDLS
, 0, 0);
762 dlbindack(fd
, (char *)buf
);
765 dlinfoack(fd
, (char *)buf
);
767 dl_abssaplen
= ABS(dlp
->info_ack
.dl_sap_length
);
768 dl_saplen
= dlp
->info_ack
.dl_sap_length
;
769 if (ETHERADDRL
!= (dlp
->info_ack
.dl_addr_length
- dl_abssaplen
))
770 fatalSys("invalid destination physical address length");
771 dl_addrlen
= dl_abssaplen
+ ETHERADDRL
;
773 /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */
774 memcpy(hwaddr
, (u_char
*)((char*)(dlp
) + (int)(dlp
->info_ack
.dl_addr_offset
)), ETHERADDRL
);
776 if ( strioctl(fd
, DLIOCRAW
, -1, 0, NULL
) < 0 ) {
777 fatalSys("DLIOCRAW");
780 if (ioctl(fd
, I_FLUSH
, FLUSHR
) < 0) fatalSys("I_FLUSH");
785 /* cloned from dlcommon.c */
788 dlpromisconreq(int fd
, u_long level
)
790 dl_promiscon_req_t promiscon_req
;
794 promiscon_req
.dl_primitive
= DL_PROMISCON_REQ
;
795 promiscon_req
.dl_level
= level
;
798 ctl
.len
= sizeof (promiscon_req
);
799 ctl
.buf
= (char *) &promiscon_req
;
803 if (putmsg(fd
, &ctl
, (struct strbuf
*) NULL
, flags
) < 0)
804 fatalSys("dlpromiscon: putmsg");
808 void dlinforeq(int fd
)
810 dl_info_req_t info_req
;
814 info_req
.dl_primitive
= DL_INFO_REQ
;
817 ctl
.len
= sizeof (info_req
);
818 ctl
.buf
= (char *) &info_req
;
822 if (putmsg(fd
, &ctl
, (struct strbuf
*) NULL
, flags
) < 0)
823 fatalSys("dlinforeq: putmsg");
826 void dlunitdatareq(int fd
, u_char
*addrp
, int addrlen
, u_long minpri
, u_long maxpri
, u_char
*datap
, int datalen
)
829 union DL_primitives
*dlp
;
830 struct strbuf data
, ctl
;
832 dlp
= (union DL_primitives
*) buf
;
834 dlp
->unitdata_req
.dl_primitive
= DL_UNITDATA_REQ
;
835 dlp
->unitdata_req
.dl_dest_addr_length
= addrlen
;
836 dlp
->unitdata_req
.dl_dest_addr_offset
= sizeof (dl_unitdata_req_t
);
837 dlp
->unitdata_req
.dl_priority
.dl_min
= minpri
;
838 dlp
->unitdata_req
.dl_priority
.dl_max
= maxpri
;
840 (void) memcpy(OFFADDR(dlp
, sizeof (dl_unitdata_req_t
)), addrp
, addrlen
);
843 ctl
.len
= sizeof (dl_unitdata_req_t
) + addrlen
;
844 ctl
.buf
= (char *) buf
;
848 data
.buf
= (char *) datap
;
850 if (putmsg(fd
, &ctl
, &data
, 0) < 0)
851 fatalSys("dlunitdatareq: putmsg");
854 void dlinfoack(int fd
, char *bufp
)
856 union DL_primitives
*dlp
;
860 ctl
.maxlen
= MAXDLBUF
;
864 strgetmsg(fd
, &ctl
, (struct strbuf
*)NULL
, &flags
, "dlinfoack");
866 dlp
= (union DL_primitives
*) ctl
.buf
;
868 expecting(DL_INFO_ACK
, dlp
);
870 if (ctl
.len
< sizeof (dl_info_ack_t
)) {
872 sprintf(buffer
, "dlinfoack: response ctl.len too short: %d", ctl
.len
);
876 if (flags
!= RS_HIPRI
)
877 rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
879 if (ctl
.len
< sizeof (dl_info_ack_t
)) {
881 sprintf(buffer
, "dlinfoack: short response ctl.len: %d", ctl
.len
);
886 void dlbindreq(int fd
, u_long sap
, u_long max_conind
, u_long service_mode
, u_long conn_mgmt
, u_long xidtest
)
888 dl_bind_req_t bind_req
;
892 bind_req
.dl_primitive
= DL_BIND_REQ
;
893 bind_req
.dl_sap
= sap
;
894 bind_req
.dl_max_conind
= max_conind
;
895 bind_req
.dl_service_mode
= service_mode
;
896 bind_req
.dl_conn_mgmt
= conn_mgmt
;
897 bind_req
.dl_xidtest_flg
= xidtest
;
900 ctl
.len
= sizeof (bind_req
);
901 ctl
.buf
= (char *) &bind_req
;
905 if (putmsg(fd
, &ctl
, (struct strbuf
*) NULL
, flags
) < 0)
906 fatalSys("dlbindreq: putmsg");
909 void dlattachreq(int fd
, u_long ppa
)
911 dl_attach_req_t attach_req
;
915 attach_req
.dl_primitive
= DL_ATTACH_REQ
;
916 attach_req
.dl_ppa
= ppa
;
919 ctl
.len
= sizeof (attach_req
);
920 ctl
.buf
= (char *) &attach_req
;
924 if (putmsg(fd
, &ctl
, (struct strbuf
*) NULL
, flags
) < 0)
925 fatalSys("dlattachreq: putmsg");
928 void dlokack(int fd
, char *bufp
)
930 union DL_primitives
*dlp
;
934 ctl
.maxlen
= MAXDLBUF
;
938 strgetmsg(fd
, &ctl
, (struct strbuf
*)NULL
, &flags
, "dlokack");
940 dlp
= (union DL_primitives
*) ctl
.buf
;
942 expecting(DL_OK_ACK
, dlp
);
944 if (ctl
.len
< sizeof (dl_ok_ack_t
)) {
946 sprintf(buffer
, "dlokack: response ctl.len too short: %d", ctl
.len
);
950 if (flags
!= RS_HIPRI
)
951 rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
953 if (ctl
.len
< sizeof (dl_ok_ack_t
)) {
955 sprintf(buffer
, "dlokack: short response ctl.len: %d", ctl
.len
);
960 void dlbindack(int fd
, char *bufp
)
962 union DL_primitives
*dlp
;
966 ctl
.maxlen
= MAXDLBUF
;
970 strgetmsg(fd
, &ctl
, (struct strbuf
*)NULL
, &flags
, "dlbindack");
972 dlp
= (union DL_primitives
*) ctl
.buf
;
974 expecting(DL_BIND_ACK
, dlp
);
976 if (flags
!= RS_HIPRI
)
977 rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
979 if (ctl
.len
< sizeof (dl_bind_ack_t
)) {
981 sprintf(buffer
, "dlbindack: short response ctl.len: %d", ctl
.len
);
986 int strioctl(int fd
, int cmd
, int timout
, int len
, char *dp
)
988 struct strioctl sioc
;
992 sioc
.ic_timout
= timout
;
995 rc
= ioctl(fd
, I_STR
, &sioc
);
1000 return (sioc
.ic_len
);
1003 void strgetmsg(int fd
, struct strbuf
*ctlp
, struct strbuf
*datap
, int *flagsp
, char *caller
)
1006 static char errmsg
[80];
1011 (void) signal(SIGALRM
, sigalrm
);
1012 if (alarm(MAXWAIT
) < 0) {
1013 (void) sprintf(errmsg
, "%s: alarm", caller
);
1018 * Set flags argument and issue getmsg().
1021 if ((rc
= getmsg(fd
, ctlp
, datap
, flagsp
)) < 0) {
1022 (void) sprintf(errmsg
, "%s: getmsg", caller
);
1030 (void) sprintf(errmsg
, "%s: alarm", caller
);
1035 * Check for MOREDATA and/or MORECTL.
1037 if ((rc
& (MORECTL
| MOREDATA
)) == (MORECTL
| MOREDATA
)) {
1039 sprintf(buffer
, "%s: MORECTL|MOREDATA", caller
);
1045 sprintf(buffer
, "%s: MORECTL", caller
);
1049 if (rc
& MOREDATA
) {
1051 sprintf(buffer
, "%s: MOREDATA", caller
);
1056 * Check for at least sizeof (long) control data portion.
1058 if (ctlp
->len
< sizeof (long)) {
1060 sprintf(buffer
, "getmsg: control portion length < sizeof (long): %d", ctlp
->len
);
1065 void sigalrm(int sig
)
1067 (void) rp_fatal("sigalrm: TIMEOUT");
1070 void expecting(int prim
, union DL_primitives
*dlp
)
1072 if (dlp
->dl_primitive
!= (u_long
)prim
) {
1074 sprintf(buffer
, "expected %s got %s", dlprim(prim
), dlprim(dlp
->dl_primitive
));
1083 static char primbuf
[80];
1085 switch ((int)prim
) {
1086 CASERET(DL_INFO_REQ
);
1087 CASERET(DL_INFO_ACK
);
1088 CASERET(DL_ATTACH_REQ
);
1089 CASERET(DL_DETACH_REQ
);
1090 CASERET(DL_BIND_REQ
);
1091 CASERET(DL_BIND_ACK
);
1092 CASERET(DL_UNBIND_REQ
);
1094 CASERET(DL_ERROR_ACK
);
1095 CASERET(DL_SUBS_BIND_REQ
);
1096 CASERET(DL_SUBS_BIND_ACK
);
1097 CASERET(DL_UNITDATA_REQ
);
1098 CASERET(DL_UNITDATA_IND
);
1099 CASERET(DL_UDERROR_IND
);
1100 CASERET(DL_UDQOS_REQ
);
1101 CASERET(DL_CONNECT_REQ
);
1102 CASERET(DL_CONNECT_IND
);
1103 CASERET(DL_CONNECT_RES
);
1104 CASERET(DL_CONNECT_CON
);
1105 CASERET(DL_TOKEN_REQ
);
1106 CASERET(DL_TOKEN_ACK
);
1107 CASERET(DL_DISCONNECT_REQ
);
1108 CASERET(DL_DISCONNECT_IND
);
1109 CASERET(DL_RESET_REQ
);
1110 CASERET(DL_RESET_IND
);
1111 CASERET(DL_RESET_RES
);
1112 CASERET(DL_RESET_CON
);
1114 (void) sprintf(primbuf
, "unknown primitive 0x%lx", prim
);
1119 #endif /* USE_DLPI */