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.16 2000/09/11 16:12:19 dfs 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>
56 #include <sys/types.h>
58 #include <sys/stream.h>
59 #include <sys/stropts.h>
61 #include <sys/bufmod.h>
66 /* function declarations */
68 void dlpromisconreq( int fd, u_long level);
69 void dlinforeq(int fd);
70 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
71 void dlinfoack(int fd, char *bufp);
72 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
73 void dlattachreq(int fd, u_long ppa);
74 void dlokack(int fd, char *bufp);
75 void dlbindack(int fd, char *bufp);
76 int strioctl(int fd, int cmd, int timout, int len, char *dp);
77 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
78 void sigalrm(int sig);
79 void expecting(int prim, union DL_primitives *dlp);
80 char *dlprim(u_long prim);
82 /* #define DL_DEBUG */
84 static int dl_abssaplen;
86 static int dl_addrlen;
94 unsigned char *bpfBuffer; /* Packet filter buffer */
95 int bpfLength = 0; /* Packet filter buffer length */
96 int bpfSize = 0; /* Number of unread bytes in buffer */
97 int bpfOffset = 0; /* Current offset in bpfBuffer */
100 extern char *IfName; /* For brain-dead Linux 2.0-kernel SOCK_PACKET */
102 /* Initialize frame types to RFC 2516 values. Some broken peers apparently
103 use different frame types... sigh... */
105 UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
106 UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
108 /**********************************************************************
109 *%FUNCTION: etherType
111 * packet -- a received PPPoE packet
113 * ethernet packet type (see /usr/include/net/ethertypes.h)
115 * Checks the ethernet packet header to determine its type.
116 * We should only be receveing DISCOVERY and SESSION types if the BPF
117 * is set up correctly. Logs an error if an unexpected type is received.
118 * Note that the ethernet type names come from "pppoe.h" and the packet
119 * packet structure names use the LINUX dialect to maintain consistency
120 * with the rest of this file. See the BSD section of "pppoe.h" for
121 * translations of the data structure names.
122 ***********************************************************************/
124 etherType(struct PPPoEPacket *packet)
126 UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
127 if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
128 syslog(LOG_ERR, "Invalid ether type 0x%x", type);
134 /**********************************************************************
135 *%FUNCTION: getHWaddr
137 * ifname -- name of interface
138 * hwaddr -- buffer for ehthernet address
142 * Locates the Ethernet hardware address for an interface.
143 ***********************************************************************/
145 getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
148 const struct sockaddr_dl *sdl;
150 struct ifreq ifreq, *ifr;
154 ifc.ifc_len = sizeof(inbuf);
156 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
157 fatalSys("SIOCGIFCONF");
160 ifreq.ifr_name[0] = '\0';
161 for (i = 0; i < ifc.ifc_len; ) {
162 ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
163 i += sizeof(ifr->ifr_name) +
164 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
165 ? ifr->ifr_addr.sa_len
166 : sizeof(struct sockaddr));
167 if (ifr->ifr_addr.sa_family == AF_LINK) {
168 sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
169 if ((sdl->sdl_type == IFT_ETHER) &&
170 (sdl->sdl_alen == ETH_ALEN) &&
171 !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
174 sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
178 memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
185 sprintf(buffer, "interface %.16s has no ethernet address", ifname);
190 /**********************************************************************
191 *%FUNCTION: initFilter
193 * fd -- file descriptor of BSD device
194 * type -- Ethernet frame type (0 for watch mode)
195 * hwaddr -- buffer with ehthernet address
199 * Initializes the packet filter rules.
200 ***********************************************************************/
202 initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
204 /* Packet Filter Instructions:
205 * Note that the ethernet type names come from "pppoe.h" and are
206 * used here to maintain consistency with the rest of this file. */
207 static struct bpf_insn bpfRun[] = { /* run PPPoE */
208 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
209 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 1, 0),
210 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 5),
211 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
212 #define PPPOE_FILTER_CMPW 4 /* offset of word compare */
213 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
214 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
215 #define PPPOE_FILTER_CMPH 6 /* offset of 1/2 word compare */
216 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
217 BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
218 BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
221 /* Fix the potentially varying parts */
222 bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
225 bpfRun[1].k = Eth_PPPOE_Session;
227 bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
230 bpfRun[2].k = Eth_PPPOE_Discovery;
233 struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
234 struct bpf_program bpfProgram;
235 memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
236 bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
237 (hwaddr[2] << 8) | hwaddr[3]);
238 bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
239 bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
240 bpfProgram.bf_insns = &bpfInsn[0];
242 /* Apply the filter */
243 if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
244 fatalSys("ioctl(BIOCSETF)");
249 /**********************************************************************
250 *%FUNCTION: openInterface
252 * ifname -- name of interface
253 * type -- Ethernet frame type (0 for any frame type)
254 * hwaddr -- if non-NULL, set to the hardware address
256 * A file descriptor for talking with the Ethernet card. Exits on error.
257 * Note that the Linux version of this routine returns a socket instead.
259 * Opens a BPF on an interface for all PPPoE traffic (discovery and
260 * session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
261 * traffic on this network.
262 ***********************************************************************/
264 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
269 struct bpf_version bpf_ver;
274 /* BSD only opens one socket for both Discovery and Session packets */
279 /* Find a free BPF device */
280 for (i = 0; i < 256; i++) {
281 sprintf(bpfName, "/dev/bpf%d", i);
282 if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
289 case EACCES: /* permission denied */
292 sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
297 case ENOENT: /* no such file */
299 fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
301 fatal("All /dev/bpf* devices are in use");
308 if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
312 /* Check that the interface is up */
313 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
314 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
315 fatalSys("ioctl(SIOCGIFFLAGS)");
317 if ((ifr.ifr_flags & IFF_UP) == 0) {
319 sprintf(buffer, "Interface %.16s is not up\n", ifname);
323 /* Fill in hardware address and initialize the packet filter rules */
324 if (hwaddr == NULL) {
325 fatal("openInterface: no hwaddr arg.");
327 getHWaddr(sock, ifname, hwaddr);
328 initFilter(fd, type, hwaddr);
330 /* Sanity check on MTU -- apparently does not work on OpenBSD */
331 #if !defined(__OpenBSD__)
332 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
333 if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
334 fatalSys("ioctl(SIOCGIFMTU)");
336 if (ifr.ifr_mtu < ETH_DATA_LEN) {
338 sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
339 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
344 /* done with the socket */
345 if (close(sock) < 0) {
349 /* Check the BPF version number */
350 if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
351 fatalSys("ioctl(BIOCVERSION)");
353 if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
354 (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
356 sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
357 BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
358 bpf_ver.bv_major, bpf_ver.bv_minor);
362 /* allocate a receive packet buffer */
363 if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
364 fatalSys("ioctl(BIOCGBLEN)");
366 if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
370 /* reads should return as soon as there is a packet available */
372 if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
373 fatalSys("ioctl(BIOCIMMEDIATE)");
376 /* Bind the interface to the filter */
377 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
378 if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
380 sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
385 syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
387 hwaddr[0], hwaddr[1], hwaddr[2],
388 hwaddr[3], hwaddr[4], hwaddr[5],
395 #ifdef USE_LINUX_PACKET
396 /**********************************************************************
397 *%FUNCTION: openInterface
399 * ifname -- name of interface
400 * type -- Ethernet frame type
401 * hwaddr -- if non-NULL, set to the hardware address
403 * A raw socket for talking to the Ethernet card. Exits on error.
405 * Opens a raw Ethernet socket
406 ***********************************************************************/
408 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
415 #ifdef HAVE_STRUCT_SOCKADDR_LL
416 struct sockaddr_ll sa;
421 memset(&sa, 0, sizeof(sa));
423 #ifdef HAVE_STRUCT_SOCKADDR_LL
431 if ((fd = socket(domain, stype, htons(type))) < 0) {
432 /* Give a more helpful message for the common error case */
433 if (errno == EPERM) {
434 fatal("Cannot create raw socket -- pppoe must be run as root.");
439 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
440 fatalSys("setsockopt");
443 /* Fill in hardware address */
445 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
446 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
447 fatalSys("ioctl(SIOCGIFHWADDR)");
449 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
452 /* Sanity check on MTU */
453 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
454 if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
455 fatalSys("ioctl(SIOCGIFMTU)");
457 if (ifr.ifr_mtu < ETH_DATA_LEN) {
459 sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
460 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
464 #ifdef HAVE_STRUCT_SOCKADDR_LL
465 /* Get interface index */
466 sa.sll_family = AF_PACKET;
467 sa.sll_protocol = htons(type);
469 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
470 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
471 fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
473 sa.sll_ifindex = ifr.ifr_ifindex;
476 strcpy(sa.sa_data, ifname);
479 /* We're only interested in packets on specified interface */
480 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
487 #endif /* USE_LINUX */
489 /***********************************************************************
490 *%FUNCTION: sendPacket
492 * sock -- socket to send to
493 * pkt -- the packet to transmit
494 * size -- size of packet (in bytes)
499 ***********************************************************************/
501 sendPacket(int sock, struct PPPoEPacket *pkt, int size)
504 if (write(sock, pkt, size) < 0) {
505 fatalSys("write (sendPacket)");
507 #elif defined(HAVE_STRUCT_SOCKADDR_LL)
508 if (send(sock, pkt, size, 0) < 0) {
509 fatalSys("send (sendPacket)");
514 #define ABS(x) ((x) < 0 ? -(x) : (x))
516 u_char addr[MAXDLADDR];
517 u_char phys[MAXDLADDR];
518 u_char sap[MAXDLADDR];
519 u_char xmitbuf[MAXDLBUF];
524 tmp_sap = htons(pkt->ethHdr.h_proto);
525 data_size = size - sizeof(struct ethhdr);
527 memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
528 memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
529 memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
531 if (dl_saplen > 0) { /* order is sap+phys */
532 (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
533 (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
534 } else { /* order is phys+sap */
535 (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
536 (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
540 printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
541 addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
545 dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
551 strcpy(sa.sa_data, IfName);
552 if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
553 fatalSys("sendto (sendPacket)");
560 /***********************************************************************
561 *%FUNCTION: clearPacketHeader
563 * pkt -- packet that needs its head clearing
567 * Clears a PPPoE packet header after a truncated packet has been
568 * received. Insures that the packet will fail any integrity tests
569 * and will be discarded by upper level routines. Also resets the
570 * bpfSize and bpfOffset variables to force a new read on the next
571 * call to receivePacket().
572 ***********************************************************************/
574 clearPacketHeader(struct PPPoEPacket *pkt)
576 bpfSize = bpfOffset = 0;
577 memset(pkt, 0, HDR_SIZE);
581 /***********************************************************************
582 *%FUNCTION: receivePacket
584 * sock -- socket to read from
585 * pkt -- place to store the received packet
586 * size -- set to size of packet in bytes
591 ***********************************************************************/
593 receivePacket(int sock, struct PPPoEPacket *pkt, int *size)
601 if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
602 fatalSys("read (receivePacket)");
605 if (bpfSize < sizeof(hdr)) {
606 syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
607 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
610 memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
611 if (hdr.bh_caplen != hdr.bh_datalen) {
612 syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
613 hdr.bh_caplen, hdr.bh_datalen);
614 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
617 seglen = hdr.bh_hdrlen + hdr.bh_caplen;
618 if (seglen > bpfSize) {
619 syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
621 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
624 seglen = BPF_WORDALIGN(seglen);
625 *size = copylen = ((hdr.bh_caplen < sizeof(struct PPPoEPacket)) ?
626 hdr.bh_caplen : sizeof(struct PPPoEPacket));
627 memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
628 if (seglen >= bpfSize) {
629 bpfSize = bpfOffset = 0;
640 data.buf = (char *) pkt;
641 data.maxlen = MAXDLBUF;
644 if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
645 fatalSys("read (receivePacket)");
651 if ((*size = recv(sock, pkt, sizeof(struct PPPoEPacket), 0)) < 0) {
652 fatalSys("recv (receivePacket)");
659 /**********************************************************************
660 *%FUNCTION: openInterface
662 * ifname -- name of interface
663 * type -- Ethernet frame type
664 * hwaddr -- if non-NULL, set to the hardware address
666 * A raw socket for talking to the Ethernet card. Exits on error.
668 * Opens a raw Ethernet socket
669 ***********************************************************************/
671 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
676 union DL_primitives *dlp;
678 char base_dev[PATH_MAX];
681 if(strlen(ifname) > PATH_MAX) {
682 fatal("socket: string to long");
685 ppa = atoi(&ifname[strlen(ifname)-1]);
686 strncpy(base_dev, ifname, PATH_MAX);
687 base_dev[strlen(base_dev)-1] = '\0';
689 if (( fd = open(base_dev, O_RDWR)) < 0) {
690 /* Give a more helpful message for the common error case */
691 if (errno == EPERM) {
692 fatal("Cannot create raw socket -- pppoe must be run as root.");
698 dlinfoack(fd, (char *)buf);
700 dlp = (union DL_primitives*) buf;
702 dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
703 dl_saplen = dlp->info_ack.dl_sap_length;
704 if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
705 fatalSys("invalid destination physical address length");
706 dl_addrlen = dl_abssaplen + ETHERADDRL;
708 dlattachreq(fd, ppa);
709 dlokack(fd, (char *)buf);
711 dlbindreq(fd, htons(type), 0, DL_CLDLS, 0, 0);
712 dlbindack(fd, (char *)buf);
714 dlpromisconreq(fd, DL_PROMISC_PHYS);
715 dlokack(fd, (char *)buf);
717 if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
718 fatalSys("DLIOCRAW");
721 if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
726 /* cloned from dlcommon.c */
728 void dlpromisconreq(int fd, u_long level)
730 dl_promiscon_req_t promiscon_req;
734 promiscon_req.dl_primitive = DL_PROMISCON_REQ;
735 promiscon_req.dl_level = level;
738 ctl.len = sizeof (promiscon_req);
739 ctl.buf = (char *) &promiscon_req;
743 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
744 fatalSys("dlpromiscon: putmsg");
748 void dlinforeq(int fd)
750 dl_info_req_t info_req;
754 info_req.dl_primitive = DL_INFO_REQ;
757 ctl.len = sizeof (info_req);
758 ctl.buf = (char *) &info_req;
762 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
763 fatalSys("dlinforeq: putmsg");
766 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
769 union DL_primitives *dlp;
770 struct strbuf data, ctl;
772 dlp = (union DL_primitives*) buf;
774 dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
775 dlp->unitdata_req.dl_dest_addr_length = addrlen;
776 dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
777 dlp->unitdata_req.dl_priority.dl_min = minpri;
778 dlp->unitdata_req.dl_priority.dl_max = maxpri;
780 (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
783 ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
784 ctl.buf = (char *) buf;
788 data.buf = (char *) datap;
790 if (putmsg(fd, &ctl, &data, 0) < 0)
791 fatalSys("dlunitdatareq: putmsg");
794 void dlinfoack(int fd, char *bufp)
796 union DL_primitives *dlp;
800 ctl.maxlen = MAXDLBUF;
804 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
806 dlp = (union DL_primitives *) ctl.buf;
808 expecting(DL_INFO_ACK, dlp);
810 if (ctl.len < sizeof (dl_info_ack_t)) {
812 sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
816 if (flags != RS_HIPRI)
817 fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
819 if (ctl.len < sizeof (dl_info_ack_t)) {
821 sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
826 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
828 dl_bind_req_t bind_req;
832 bind_req.dl_primitive = DL_BIND_REQ;
833 bind_req.dl_sap = sap;
834 bind_req.dl_max_conind = max_conind;
835 bind_req.dl_service_mode = service_mode;
836 bind_req.dl_conn_mgmt = conn_mgmt;
837 bind_req.dl_xidtest_flg = xidtest;
840 ctl.len = sizeof (bind_req);
841 ctl.buf = (char *) &bind_req;
845 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
846 fatalSys("dlbindreq: putmsg");
849 void dlattachreq(int fd, u_long ppa)
851 dl_attach_req_t attach_req;
855 attach_req.dl_primitive = DL_ATTACH_REQ;
856 attach_req.dl_ppa = ppa;
859 ctl.len = sizeof (attach_req);
860 ctl.buf = (char *) &attach_req;
864 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
865 fatalSys("dlattachreq: putmsg");
868 void dlokack(int fd, char *bufp)
870 union DL_primitives *dlp;
874 ctl.maxlen = MAXDLBUF;
878 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
880 dlp = (union DL_primitives *) ctl.buf;
882 expecting(DL_OK_ACK, dlp);
884 if (ctl.len < sizeof (dl_ok_ack_t)) {
886 sprintf(buffer, "dlokack: response ctl.len too short: %d", ctl.len);
890 if (flags != RS_HIPRI)
891 fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
893 if (ctl.len < sizeof (dl_ok_ack_t)) {
895 sprintf(buffer, "dlokack: short response ctl.len: %d", ctl.len);
900 void dlbindack(int fd, char *bufp)
902 union DL_primitives *dlp;
906 ctl.maxlen = MAXDLBUF;
910 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
912 dlp = (union DL_primitives *) ctl.buf;
914 expecting(DL_BIND_ACK, dlp);
916 if (flags != RS_HIPRI)
917 fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
919 if (ctl.len < sizeof (dl_bind_ack_t)) {
921 sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len);
926 int strioctl(int fd, int cmd, int timout, int len, char *dp)
928 struct strioctl sioc;
932 sioc.ic_timout = timout;
935 rc = ioctl(fd, I_STR, &sioc);
940 return (sioc.ic_len);
943 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
946 static char errmsg[80];
951 (void) signal(SIGALRM, sigalrm);
952 if (alarm(MAXWAIT) < 0) {
953 (void) sprintf(errmsg, "%s: alarm", caller);
958 * Set flags argument and issue getmsg().
961 if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
962 (void) sprintf(errmsg, "%s: getmsg", caller);
970 (void) sprintf(errmsg, "%s: alarm", caller);
975 * Check for MOREDATA and/or MORECTL.
977 if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
979 sprintf(buffer, "%s: MORECTL|MOREDATA", caller);
985 sprintf(buffer, "%s: MORECTL", caller);
991 sprintf(buffer, "%s: MOREDATA", caller);
996 * Check for at least sizeof (long) control data portion.
998 if (ctlp->len < sizeof (long)) {
1000 sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len);
1005 void sigalrm(int sig)
1007 (void) fatal("sigalrm: TIMEOUT");
1010 void expecting(int prim, union DL_primitives *dlp)
1012 if (dlp->dl_primitive != (u_long)prim) {
1014 sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
1020 char *dlprim(u_long prim)
1022 static char primbuf[80];
1024 switch ((int)prim) {
1025 CASERET(DL_INFO_REQ);
1026 CASERET(DL_INFO_ACK);
1027 CASERET(DL_ATTACH_REQ);
1028 CASERET(DL_DETACH_REQ);
1029 CASERET(DL_BIND_REQ);
1030 CASERET(DL_BIND_ACK);
1031 CASERET(DL_UNBIND_REQ);
1033 CASERET(DL_ERROR_ACK);
1034 CASERET(DL_SUBS_BIND_REQ);
1035 CASERET(DL_SUBS_BIND_ACK);
1036 CASERET(DL_UNITDATA_REQ);
1037 CASERET(DL_UNITDATA_IND);
1038 CASERET(DL_UDERROR_IND);
1039 CASERET(DL_UDQOS_REQ);
1040 CASERET(DL_CONNECT_REQ);
1041 CASERET(DL_CONNECT_IND);
1042 CASERET(DL_CONNECT_RES);
1043 CASERET(DL_CONNECT_CON);
1044 CASERET(DL_TOKEN_REQ);
1045 CASERET(DL_TOKEN_ACK);
1046 CASERET(DL_DISCONNECT_REQ);
1047 CASERET(DL_DISCONNECT_IND);
1048 CASERET(DL_RESET_REQ);
1049 CASERET(DL_RESET_IND);
1050 CASERET(DL_RESET_RES);
1051 CASERET(DL_RESET_CON);
1053 (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
1058 #endif /* USE_DLPI */