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 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.
14 ***********************************************************************/
16 static char const RCSID[] =
17 "$Id: if.c,v 1.1 2001/12/14 02:55:20 mostrows Exp $";
25 #ifdef HAVE_NETPACKET_PACKET_H
26 #include <netpacket/packet.h>
27 #elif defined(HAVE_LINUX_IF_PACKET_H)
28 #include <linux/if_packet.h>
31 #ifdef HAVE_NET_ETHERNET_H
32 #include <net/ethernet.h>
35 #ifdef HAVE_ASM_TYPES_H
36 #include <asm/types.h>
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
51 #ifdef HAVE_NET_IF_ARP_H
52 #include <net/if_arp.h>
60 #include <sys/types.h>
62 #include <sys/stream.h>
63 #include <sys/stropts.h>
65 #include <sys/bufmod.h>
70 /* function declarations */
72 void dlpromisconreq( int fd, u_long level);
73 void dlinforeq(int fd);
74 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
75 void dlinfoack(int fd, char *bufp);
76 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
77 void dlattachreq(int fd, u_long ppa);
78 void dlokack(int fd, char *bufp);
79 void dlbindack(int fd, char *bufp);
80 int strioctl(int fd, int cmd, int timout, int len, char *dp);
81 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
82 void sigalrm(int sig);
83 void expecting(int prim, union DL_primitives *dlp);
84 char *dlprim(u_long prim);
86 /* #define DL_DEBUG */
88 static int dl_abssaplen;
90 static int dl_addrlen;
98 unsigned char *bpfBuffer; /* Packet filter buffer */
99 int bpfLength = 0; /* Packet filter buffer length */
100 int bpfSize = 0; /* Number of unread bytes in buffer */
101 int bpfOffset = 0; /* Current offset in bpfBuffer */
104 /* Initialize frame types to RFC 2516 values. Some broken peers apparently
105 use different frame types... sigh... */
107 UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
108 UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
110 /**********************************************************************
111 *%FUNCTION: etherType
113 * packet -- a received PPPoE packet
115 * ethernet packet type (see /usr/include/net/ethertypes.h)
117 * Checks the ethernet packet header to determine its type.
118 * We should only be receveing DISCOVERY and SESSION types if the BPF
119 * is set up correctly. Logs an error if an unexpected type is received.
120 * Note that the ethernet type names come from "pppoe.h" and the packet
121 * packet structure names use the LINUX dialect to maintain consistency
122 * with the rest of this file. See the BSD section of "pppoe.h" for
123 * translations of the data structure names.
124 ***********************************************************************/
126 etherType(PPPoEPacket *packet)
128 UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
129 if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
130 syslog(LOG_ERR, "Invalid ether type 0x%x", type);
136 /**********************************************************************
137 *%FUNCTION: getHWaddr
139 * ifname -- name of interface
140 * hwaddr -- buffer for ehthernet address
144 * Locates the Ethernet hardware address for an interface.
145 ***********************************************************************/
147 getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
150 const struct sockaddr_dl *sdl;
152 struct ifreq ifreq, *ifr;
156 ifc.ifc_len = sizeof(inbuf);
158 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
159 fatalSys("SIOCGIFCONF");
162 ifreq.ifr_name[0] = '\0';
163 for (i = 0; i < ifc.ifc_len; ) {
164 ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
165 i += sizeof(ifr->ifr_name) +
166 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
167 ? ifr->ifr_addr.sa_len
168 : sizeof(struct sockaddr));
169 if (ifr->ifr_addr.sa_family == AF_LINK) {
170 sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
171 if ((sdl->sdl_type == IFT_ETHER) &&
172 (sdl->sdl_alen == ETH_ALEN) &&
173 !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
176 sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
180 memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
187 sprintf(buffer, "interface %.16s has no ethernet address", ifname);
192 /**********************************************************************
193 *%FUNCTION: initFilter
195 * fd -- file descriptor of BSD device
196 * type -- Ethernet frame type (0 for watch mode)
197 * hwaddr -- buffer with ehthernet address
201 * Initializes the packet filter rules.
202 ***********************************************************************/
204 initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
206 /* Packet Filter Instructions:
207 * Note that the ethernet type names come from "pppoe.h" and are
208 * used here to maintain consistency with the rest of this file. */
209 static struct bpf_insn bpfRun[] = { /* run PPPoE */
210 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
211 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
212 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
213 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
214 #define PPPOE_BCAST_CMPW 4 /* offset of word compare */
215 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
216 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
217 #define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
218 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
219 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
220 #define PPPOE_FILTER_CMPW 8 /* offset of word compare */
221 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
222 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
223 #define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
224 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
225 BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
226 BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
229 /* Fix the potentially varying parts */
230 bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
233 bpfRun[1].k = Eth_PPPOE_Session;
235 bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
238 bpfRun[2].k = Eth_PPPOE_Discovery;
241 struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
242 struct bpf_program bpfProgram;
243 memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
244 bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
246 bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
247 bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
248 (hwaddr[2] << 8) | hwaddr[3]);
249 bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
250 bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
251 bpfProgram.bf_insns = &bpfInsn[0];
253 /* Apply the filter */
254 if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
255 fatalSys("ioctl(BIOCSETF)");
260 /**********************************************************************
261 *%FUNCTION: openInterface
263 * ifname -- name of interface
264 * type -- Ethernet frame type (0 for any frame type)
265 * hwaddr -- if non-NULL, set to the hardware address
267 * A file descriptor for talking with the Ethernet card. Exits on error.
268 * Note that the Linux version of this routine returns a socket instead.
270 * Opens a BPF on an interface for all PPPoE traffic (discovery and
271 * session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
272 * traffic on this network.
273 ***********************************************************************/
275 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
280 struct bpf_version bpf_ver;
285 /* BSD only opens one socket for both Discovery and Session packets */
290 /* Find a free BPF device */
291 for (i = 0; i < 256; i++) {
292 sprintf(bpfName, "/dev/bpf%d", i);
293 if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
300 case EACCES: /* permission denied */
303 sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
308 case ENOENT: /* no such file */
310 rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
312 rp_fatal("All /dev/bpf* devices are in use");
319 if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
323 /* Check that the interface is up */
324 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
325 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
326 fatalSys("ioctl(SIOCGIFFLAGS)");
328 if ((ifr.ifr_flags & IFF_UP) == 0) {
330 sprintf(buffer, "Interface %.16s is not up\n", ifname);
334 /* Fill in hardware address and initialize the packet filter rules */
335 if (hwaddr == NULL) {
336 rp_fatal("openInterface: no hwaddr arg.");
338 getHWaddr(sock, ifname, hwaddr);
339 initFilter(fd, type, hwaddr);
341 /* Sanity check on MTU -- apparently does not work on OpenBSD */
342 #if !defined(__OpenBSD__)
343 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
344 if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
345 fatalSys("ioctl(SIOCGIFMTU)");
347 if (ifr.ifr_mtu < ETH_DATA_LEN) {
349 sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
350 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
355 /* done with the socket */
356 if (close(sock) < 0) {
360 /* Check the BPF version number */
361 if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
362 fatalSys("ioctl(BIOCVERSION)");
364 if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
365 (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
367 sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
368 BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
369 bpf_ver.bv_major, bpf_ver.bv_minor);
373 /* allocate a receive packet buffer */
374 if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
375 fatalSys("ioctl(BIOCGBLEN)");
377 if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
381 /* reads should return as soon as there is a packet available */
383 if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
384 fatalSys("ioctl(BIOCIMMEDIATE)");
387 /* Bind the interface to the filter */
388 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
389 if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
391 sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
396 syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
398 hwaddr[0], hwaddr[1], hwaddr[2],
399 hwaddr[3], hwaddr[4], hwaddr[5],
406 #ifdef USE_LINUX_PACKET
407 /**********************************************************************
408 *%FUNCTION: openInterface
410 * ifname -- name of interface
411 * type -- Ethernet frame type
412 * hwaddr -- if non-NULL, set to the hardware address
414 * A raw socket for talking to the Ethernet card. Exits on error.
416 * Opens a raw Ethernet socket
417 ***********************************************************************/
419 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
426 #ifdef HAVE_STRUCT_SOCKADDR_LL
427 struct sockaddr_ll sa;
432 memset(&sa, 0, sizeof(sa));
434 #ifdef HAVE_STRUCT_SOCKADDR_LL
442 if ((fd = socket(domain, stype, htons(type))) < 0) {
443 /* Give a more helpful message for the common error case */
444 if (errno == EPERM) {
445 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
450 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
451 fatalSys("setsockopt");
454 /* Fill in hardware address */
456 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
457 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
458 fatalSys("ioctl(SIOCGIFHWADDR)");
460 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
462 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
464 sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
468 if (NOT_UNICAST(hwaddr)) {
471 "Interface %.16s has broadcast/multicast MAC address??",
477 /* Sanity check on MTU */
478 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
479 if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
480 fatalSys("ioctl(SIOCGIFMTU)");
482 if (ifr.ifr_mtu < ETH_DATA_LEN) {
484 sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
485 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
489 #ifdef HAVE_STRUCT_SOCKADDR_LL
490 /* Get interface index */
491 sa.sll_family = AF_PACKET;
492 sa.sll_protocol = htons(type);
494 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
495 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
496 fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
498 sa.sll_ifindex = ifr.ifr_ifindex;
501 strcpy(sa.sa_data, ifname);
504 /* We're only interested in packets on specified interface */
505 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
512 #endif /* USE_LINUX */
514 /***********************************************************************
515 *%FUNCTION: sendPacket
517 * sock -- socket to send to
518 * pkt -- the packet to transmit
519 * size -- size of packet (in bytes)
521 * 0 on success; -1 on failure
524 ***********************************************************************/
526 sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
529 if (write(sock, pkt, size) < 0) {
530 sysErr("write (sendPacket)");
533 #elif defined(HAVE_STRUCT_SOCKADDR_LL)
534 if (send(sock, pkt, size, 0) < 0) {
535 sysErr("send (sendPacket)");
541 #define ABS(x) ((x) < 0 ? -(x) : (x))
543 u_char addr[MAXDLADDR];
544 u_char phys[MAXDLADDR];
545 u_char sap[MAXDLADDR];
546 u_char xmitbuf[MAXDLBUF];
551 tmp_sap = htons(pkt->ethHdr.h_proto);
552 data_size = size - sizeof(struct ethhdr);
554 memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
555 memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
556 memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
558 if (dl_saplen > 0) { /* order is sap+phys */
559 (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
560 (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
561 } else { /* order is phys+sap */
562 (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
563 (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
567 printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
568 addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
572 dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
580 rp_fatal("relay and server not supported on Linux 2.0 kernels");
582 strcpy(sa.sa_data, conn->ifName);
583 if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
584 sysErr("sendto (sendPacket)");
593 /***********************************************************************
594 *%FUNCTION: clearPacketHeader
596 * pkt -- packet that needs its head clearing
600 * Clears a PPPoE packet header after a truncated packet has been
601 * received. Insures that the packet will fail any integrity tests
602 * and will be discarded by upper level routines. Also resets the
603 * bpfSize and bpfOffset variables to force a new read on the next
604 * call to receivePacket().
605 ***********************************************************************/
607 clearPacketHeader(PPPoEPacket *pkt)
609 bpfSize = bpfOffset = 0;
610 memset(pkt, 0, HDR_SIZE);
614 /***********************************************************************
615 *%FUNCTION: receivePacket
617 * sock -- socket to read from
618 * pkt -- place to store the received packet
619 * size -- set to size of packet in bytes
621 * >= 0 if all OK; < 0 if error
624 ***********************************************************************/
626 receivePacket(int sock, PPPoEPacket *pkt, int *size)
634 if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
635 sysErr("read (receivePacket)");
639 if (bpfSize < sizeof(hdr)) {
640 syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
641 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
644 memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
645 if (hdr.bh_caplen != hdr.bh_datalen) {
646 syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
647 hdr.bh_caplen, hdr.bh_datalen);
648 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
651 seglen = hdr.bh_hdrlen + hdr.bh_caplen;
652 if (seglen > bpfSize) {
653 syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
655 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
658 seglen = BPF_WORDALIGN(seglen);
659 *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
660 hdr.bh_caplen : sizeof(PPPoEPacket));
661 memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
662 if (seglen >= bpfSize) {
663 bpfSize = bpfOffset = 0;
674 data.buf = (char *) pkt;
675 data.maxlen = MAXDLBUF;
678 if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
679 sysErr("read (receivePacket)");
686 if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
687 sysErr("recv (receivePacket)");
696 /**********************************************************************
697 *%FUNCTION: openInterface
699 * ifname -- name of interface
700 * type -- Ethernet frame type
701 * hwaddr -- if non-NULL, set to the hardware address
703 * A raw socket for talking to the Ethernet card. Exits on error.
705 * Opens a raw Ethernet socket
706 ***********************************************************************/
708 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
713 union DL_primitives *dlp;
715 char base_dev[PATH_MAX];
718 if(strlen(ifname) > PATH_MAX) {
719 rp_fatal("socket: string to long");
722 ppa = atoi(&ifname[strlen(ifname)-1]);
723 strncpy(base_dev, ifname, PATH_MAX);
724 base_dev[strlen(base_dev)-1] = '\0';
726 /* rearranged order of DLPI code - delphys 20010803 */
727 dlp = (union DL_primitives*) buf;
729 if (( fd = open(base_dev, O_RDWR)) < 0) {
730 /* Give a more helpful message for the common error case */
731 if (errno == EPERM) {
732 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
737 /* rearranged order of DLPI code - delphys 20010803 */
738 dlattachreq(fd, ppa);
739 dlokack(fd, (char *)buf);
741 dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
742 dlbindack(fd, (char *)buf);
745 dlinfoack(fd, (char *)buf);
747 dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
748 dl_saplen = dlp->info_ack.dl_sap_length;
749 if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
750 fatalSys("invalid destination physical address length");
751 dl_addrlen = dl_abssaplen + ETHERADDRL;
753 /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */
754 memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL);
756 if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
757 fatalSys("DLIOCRAW");
760 if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
765 /* cloned from dlcommon.c */
767 void dlpromisconreq(int fd, u_long level)
769 dl_promiscon_req_t promiscon_req;
773 promiscon_req.dl_primitive = DL_PROMISCON_REQ;
774 promiscon_req.dl_level = level;
777 ctl.len = sizeof (promiscon_req);
778 ctl.buf = (char *) &promiscon_req;
782 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
783 fatalSys("dlpromiscon: putmsg");
787 void dlinforeq(int fd)
789 dl_info_req_t info_req;
793 info_req.dl_primitive = DL_INFO_REQ;
796 ctl.len = sizeof (info_req);
797 ctl.buf = (char *) &info_req;
801 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
802 fatalSys("dlinforeq: putmsg");
805 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
808 union DL_primitives *dlp;
809 struct strbuf data, ctl;
811 dlp = (union DL_primitives*) buf;
813 dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
814 dlp->unitdata_req.dl_dest_addr_length = addrlen;
815 dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
816 dlp->unitdata_req.dl_priority.dl_min = minpri;
817 dlp->unitdata_req.dl_priority.dl_max = maxpri;
819 (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
822 ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
823 ctl.buf = (char *) buf;
827 data.buf = (char *) datap;
829 if (putmsg(fd, &ctl, &data, 0) < 0)
830 fatalSys("dlunitdatareq: putmsg");
833 void dlinfoack(int fd, char *bufp)
835 union DL_primitives *dlp;
839 ctl.maxlen = MAXDLBUF;
843 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
845 dlp = (union DL_primitives *) ctl.buf;
847 expecting(DL_INFO_ACK, dlp);
849 if (ctl.len < sizeof (dl_info_ack_t)) {
851 sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
855 if (flags != RS_HIPRI)
856 rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
858 if (ctl.len < sizeof (dl_info_ack_t)) {
860 sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
865 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
867 dl_bind_req_t bind_req;
871 bind_req.dl_primitive = DL_BIND_REQ;
872 bind_req.dl_sap = sap;
873 bind_req.dl_max_conind = max_conind;
874 bind_req.dl_service_mode = service_mode;
875 bind_req.dl_conn_mgmt = conn_mgmt;
876 bind_req.dl_xidtest_flg = xidtest;
879 ctl.len = sizeof (bind_req);
880 ctl.buf = (char *) &bind_req;
884 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
885 fatalSys("dlbindreq: putmsg");
888 void dlattachreq(int fd, u_long ppa)
890 dl_attach_req_t attach_req;
894 attach_req.dl_primitive = DL_ATTACH_REQ;
895 attach_req.dl_ppa = ppa;
898 ctl.len = sizeof (attach_req);
899 ctl.buf = (char *) &attach_req;
903 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
904 fatalSys("dlattachreq: putmsg");
907 void dlokack(int fd, char *bufp)
909 union DL_primitives *dlp;
913 ctl.maxlen = MAXDLBUF;
917 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
919 dlp = (union DL_primitives *) ctl.buf;
921 expecting(DL_OK_ACK, dlp);
923 if (ctl.len < sizeof (dl_ok_ack_t)) {
925 sprintf(buffer, "dlokack: response ctl.len too short: %d", ctl.len);
929 if (flags != RS_HIPRI)
930 rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
932 if (ctl.len < sizeof (dl_ok_ack_t)) {
934 sprintf(buffer, "dlokack: short response ctl.len: %d", ctl.len);
939 void dlbindack(int fd, char *bufp)
941 union DL_primitives *dlp;
945 ctl.maxlen = MAXDLBUF;
949 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
951 dlp = (union DL_primitives *) ctl.buf;
953 expecting(DL_BIND_ACK, dlp);
955 if (flags != RS_HIPRI)
956 rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
958 if (ctl.len < sizeof (dl_bind_ack_t)) {
960 sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len);
965 int strioctl(int fd, int cmd, int timout, int len, char *dp)
967 struct strioctl sioc;
971 sioc.ic_timout = timout;
974 rc = ioctl(fd, I_STR, &sioc);
979 return (sioc.ic_len);
982 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
985 static char errmsg[80];
990 (void) signal(SIGALRM, sigalrm);
991 if (alarm(MAXWAIT) < 0) {
992 (void) sprintf(errmsg, "%s: alarm", caller);
997 * Set flags argument and issue getmsg().
1000 if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
1001 (void) sprintf(errmsg, "%s: getmsg", caller);
1009 (void) sprintf(errmsg, "%s: alarm", caller);
1014 * Check for MOREDATA and/or MORECTL.
1016 if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
1018 sprintf(buffer, "%s: MORECTL|MOREDATA", caller);
1024 sprintf(buffer, "%s: MORECTL", caller);
1028 if (rc & MOREDATA) {
1030 sprintf(buffer, "%s: MOREDATA", caller);
1035 * Check for at least sizeof (long) control data portion.
1037 if (ctlp->len < sizeof (long)) {
1039 sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len);
1044 void sigalrm(int sig)
1046 (void) rp_fatal("sigalrm: TIMEOUT");
1049 void expecting(int prim, union DL_primitives *dlp)
1051 if (dlp->dl_primitive != (u_long)prim) {
1053 sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
1059 char *dlprim(u_long prim)
1061 static char primbuf[80];
1063 switch ((int)prim) {
1064 CASERET(DL_INFO_REQ);
1065 CASERET(DL_INFO_ACK);
1066 CASERET(DL_ATTACH_REQ);
1067 CASERET(DL_DETACH_REQ);
1068 CASERET(DL_BIND_REQ);
1069 CASERET(DL_BIND_ACK);
1070 CASERET(DL_UNBIND_REQ);
1072 CASERET(DL_ERROR_ACK);
1073 CASERET(DL_SUBS_BIND_REQ);
1074 CASERET(DL_SUBS_BIND_ACK);
1075 CASERET(DL_UNITDATA_REQ);
1076 CASERET(DL_UNITDATA_IND);
1077 CASERET(DL_UDERROR_IND);
1078 CASERET(DL_UDQOS_REQ);
1079 CASERET(DL_CONNECT_REQ);
1080 CASERET(DL_CONNECT_IND);
1081 CASERET(DL_CONNECT_RES);
1082 CASERET(DL_CONNECT_CON);
1083 CASERET(DL_TOKEN_REQ);
1084 CASERET(DL_TOKEN_ACK);
1085 CASERET(DL_DISCONNECT_REQ);
1086 CASERET(DL_DISCONNECT_IND);
1087 CASERET(DL_RESET_REQ);
1088 CASERET(DL_RESET_IND);
1089 CASERET(DL_RESET_RES);
1090 CASERET(DL_RESET_CON);
1092 (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
1097 #endif /* USE_DLPI */