/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* bos720 src/bos/usr/samples/dlpi/sdlpi.c 1.4 */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* COPYRIGHT International Business Machines Corp. 1994,1995 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ static char sccsid[] = "@(#)31 1.4 src/bos/usr/samples/dlpi/sdlpi.c, sysxpse, bos720 2/13/95 15:44:01"; /* * COMPONENT_NAME: SYSXPSE * * FUNCTIONS: * * ORIGINS: 27 * * (C) COPYRIGHT International Business Machines Corp. 1994, 1995 * All Rights Reserved * Licensed Materials - Property of IBM * * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * * * NOTICE TO USERS OF THE SOURCE CODE EXAMPLES * * INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THE SOURCE CODE * EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, "AS IS" WITHOUT * WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT * LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE * OF THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, * IS WITH YOU. SHOULD ANY PART OF THE SOURCE CODE EXAMPLES PROVE * DEFECTIVE, YOU (AND NOT IBM OR AN AUTHORIZED RISC System/6000* WORKSTATION * DEALER) ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR * CORRECTION. * * * RISC System/6000 is a trademark of International Business Machines * Corporation. */ /* * This file contains sample source code for sdlpi, a server process that * communicates with the STREAMS Data Link Protocol Interface (DLPI) driver. * The companion client source code, cdlpi.c, is shipped in the same directory. * * The usage statement for this server process, sdlpi, is: * * sdlpi -n Node -s SAP [-b PeerSAP]... [-c] [-f PktFormat] [-m MultiAddr]... [-p Level] [-v] * where: * Flags: * b PeerSAP Indicates that the peer Service Access Point (SAP) * specified by the PeerSap parameter should be bound to * this stream. The PeerSap must be specified in * hexadecimal in the following format: "xx:", "xx:xx", * or "xx:xx:xx:xx:xx", for 802.2, ethernet, or SNAP. * This flag can be specified more than once. See the * DL_SUBS_BIND_REQ primitive manpage for more information. * * c Indicates that the global (for all streams) and local * (per stream) statistical counts should be diplayed. * See the DL_GET_STATISTICS_REQ primitive manpage for * more information. * * f PktFormat Indicates that the packet format is to be set to the * type specified by the PktFormat parameter. PktFormat * must be one of the following integer values: * 1 NS_PROTO * 2 NS_PROTO_SNAP * 4 NS_INCLUDE_LLC * 8 NS_INCLUDE_MAC * If this parameter is not specified, the default packet * format is NS_PROTO. See the infoExplorer article, * "DLPI Specific Information" for more information on * packet formats. * * n Node Indicates that the network interface specified by the * Node parameter is to be used for communication. * This parameter is absolutely required. * The Node parameter must be specified in the following * format: /dev/dlpi/tr * /dev/dlpi/en * /dev/dlpi/et * /dev/dlpi/fddi * * m MultiAddr Indicates that the multicast address specified by the * MultiAddr parameter should be enabled. This flag can * be specified more than once. * See the DL_ENABMULTI_REQ Primitive manpage in * infoExplorer for more information on this primitive. * * p Level Indicates that promiscuous mode should be enabled * at the level specified by the Level parameter. * Level must be one of the following integer values: * 1 DL_PROMISC_SAP * 2 DL_PROMISC_PHYS * 3 DL_PROMISC_MULTI * See the DL_PROMISCON_REQ Primitive manpage in * infoExplorer for more information on this primitive. * * s SAP Indicates the stream is to bound to the Service Access * Point (SAP) specified by the SAP parameter. This value * must be specified as a hexadecimal number, for example, * 0x3. This parameter is absolutely required. * * v Indicates that the server process is to run in verbose * mode. * * An example of the usage for standard ethernet is: * * sdlpi -s 0x660 -n /dev/dlpi/en -p 2 -f 1 -v * */ /* * sdlpi - dlpi server */ #include #include #include #include #include #include #include #include #include typedef struct address { char address[6]; int len; struct address *next; } addr_t; addr_t *mcastlist = NULL; addr_t *psaplist = NULL; char data[4096]; /* data portion of response */ char buf[4096]; /* proto portion of response */ char *Prog; int Verbose=0; static int bar = 0; char src_address[64]; ulong src_addr_sap_len; void peerbind(); int conv(); close_prog() { printf("total number of packets received = %d\n", bar); exit(0); } main(ac, av) int ac; char **av; { int fd; int pkt_format = NS_PROTO; /* default */ struct strioctl strioctl; char *p, *node; unsigned long sap; addr_t *address; char buf1[4096]; int peersap=0; addr_t *m, *ps; int multicast=0; int promiscuous=0, prom_level=0; int stats=0; int c; extern int optind; extern char *optarg; struct strbuf ctl, dat; int flags, nflag=0, sflag=0, fflag=0; /* static so init to all zeros */ static dl_attach_req_t attach; static dl_info_req_t info; static dl_promiscon_req_t promiscon; static dl_enabmulti_req_t *emultireq; dl_unitdata_req_t *udreq; dl_unitdata_ind_t *udind; dl_ok_ack_t *okack; dl_info_ack_t *infoack; if (Prog = strrchr(av[0], '/')) av[0] = ++Prog; else Prog = av[0]; if (ac < 3) usage(); while ((c = getopt(ac, av, "b:cf:m:n:p:s:v")) != EOF) { switch (c) { case 'b': peersap++; address = (addr_t *)malloc(sizeof(addr_t)); bzero(address, sizeof(addr_t)); address->len = conv(optarg, address->address); if (!psaplist) psaplist = address; else { for (ps=psaplist; ps->next; ps=ps->next) ; ps->next = address; } break; case 'c': stats++; break; case 'f': fflag++; pkt_format = atoi(optarg); switch (pkt_format) { case 1: pkt_format = NS_PROTO; break; case 2: pkt_format = NS_PROTO_SNAP; break; case 4: pkt_format = NS_INCLUDE_LLC; break; case 8: pkt_format = NS_INCLUDE_MAC; break; default: printf("%s: Invalid packet format specified\n", optarg); usage(); } break; case 'm': multicast++; address = (addr_t *)malloc(sizeof(addr_t)); bzero(address, sizeof(addr_t)); address->len = conv(optarg, address->address); if (!mcastlist) mcastlist = address; else { for (m=mcastlist; m->next; m=m->next) ; m->next = address; } break; case 'n': node = optarg; nflag++; break; case 'p': promiscuous++; prom_level = atoi(optarg); switch (prom_level) { case 1: case 2: case 3: break; default: printf("%s: Invalid promiscuous level specified\n", optarg); usage(); } break; case 's': sap = strtoul(optarg, 0, 0); sflag++; break; case 'v': Verbose = 1; break; default: usage(); } } if (fflag > 1) { printf("%s: You can supply only one packet format flag and parameter\n", Prog); usage(); } if (!sflag) { printf("%s: You must supply a SAP flag and parameter\n", Prog); usage(); } if (!nflag) { printf("%s: You must supply a node flag and parameter\n", Prog); usage(); } signal(SIGINT, close_prog); if ((fd = open(node, O_RDWR)) < 0) die(node); /* * attach to interface */ attach.dl_primitive = DL_ATTACH_REQ; attach.dl_ppa = 0; (void)request(fd, &attach, sizeof attach, buf, sizeof buf); okack = (dl_ok_ack_t *)buf; if (okack->dl_primitive != DL_OK_ACK) errorack(buf, "cannot attach"); printf("%s: attached\n", Prog); /* * Set up the packet format registration. This must be specified after * the attach and before the bind. NS_PROTO is the default packet type, * so we do not need to do anything if we are using the default. */ if (pkt_format != NS_PROTO) { strioctl.ic_dp = (char *)&pkt_format; strioctl.ic_cmd = DL_PKT_FORMAT; strioctl.ic_timout = 0; strioctl.ic_len = sizeof(long); if (ioctl(fd, I_STR, &strioctl) < 0) { perror("ioctl I_STR failed"); exit(1); } } /* * bind to sap, unbind, and bind again */ bindsap(fd, sap); unbindsap(fd); bindsap(fd, sap); /* * get info */ info.dl_primitive = DL_INFO_REQ; (void)request(fd, &info, sizeof info, buf, sizeof buf); infoack = (dl_info_ack_t *)buf; if (infoack->dl_primitive != DL_INFO_ACK) errorack(buf, "cannot get info"); /* printf("%s: provider info:\n", Prog); printf(" max sdu = %d\n", infoack->dl_max_sdu); printf(" min sdu = %d\n", infoack->dl_min_sdu); printf(" mac type = %d\n", infoack->dl_mac_type); printf(" addr length = %d\n", infoack->dl_addr_length); printf(" current state = %d\n", infoack->dl_current_state); printf(" service mode = %d\n", infoack->dl_service_mode); printf("\n"); */ if (promiscuous) { /* enable promiscuous mode */ promiscon.dl_primitive = DL_PROMISCON_REQ; switch (prom_level) { case 1: promiscon.dl_level = DL_PROMISC_SAP; break; case 2: promiscon.dl_level = DL_PROMISC_PHYS; break; case 3: promiscon.dl_level = DL_PROMISC_MULTI; break; } (void)request(fd, &promiscon, sizeof promiscon, buf, sizeof buf); okack = (dl_ok_ack_t *)buf; if (okack->dl_primitive != DL_OK_ACK) errorack(buf, "cannot enable promiscuous mode"); } if (multicast) { /* enable multicast */ emultireq = (dl_enabmulti_req_t *) buf1; emultireq->dl_primitive = DL_ENABMULTI_REQ; emultireq->dl_addr_length = 6; emultireq->dl_addr_offset = sizeof(dl_enabmulti_req_t); for (m = mcastlist; m; m=m->next) { memcpy(buf1 + emultireq->dl_addr_offset, m->address, emultireq->dl_addr_length); (void)request(fd, emultireq, sizeof(*emultireq)+6, buf, sizeof buf); okack = (dl_ok_ack_t *)buf; if (okack->dl_primitive != DL_OK_ACK) errorack(buf, "cannot enable multicast"); } } /* * peer bind */ if (peersap) peerbind(fd); /* * unbind peer sap */ if (peersap) { dl_subs_unbind_req_t *peer; peer = (dl_subs_unbind_req_t *)buf; peer->dl_primitive = DL_SUBS_UNBIND_REQ; peer->dl_subs_sap_offset = sizeof(*peer); for (ps = psaplist; ps; ps=ps->next) { peer->dl_subs_sap_length = ps->len; bcopy(ps->address, &peer[1], ps->len); (void)request(fd, peer, sizeof(*peer)+ps->len, buf, sizeof buf); okack = (dl_ok_ack_t *)buf; if (okack->dl_primitive != DL_OK_ACK) errorack(buf, "cannot unbind sap"); } printf("unbind sap okay\n"); } /* * peer bind */ if (peersap) peerbind(fd); /* * print out statistics */ if (stats) { dl_stat(fd); } /* * server loop - wait for query, respond with data */ ctl.buf = buf; ctl.maxlen = sizeof buf; dat.buf = data; dat.maxlen = sizeof data; flags = 0; while (getmsg(fd, &ctl, &dat, &flags) != -1) { char buf2[1000]; char dat2[100]; if (Verbose) dump(0, &ctl, &dat); udind = (dl_unitdata_ind_t *)(ctl.buf); if (udind->dl_primitive != DL_UNITDATA_IND) { warn("bad primitive (%x)", udind->dl_primitive); continue; } if (pkt_format != NS_INCLUDE_MAC && pkt_format != NS_INCLUDE_LLC) { if (dat.buf[0] != 'q' || dat.buf[1] != 0) { /* warn("bad query"); */ continue; } } query(&dat); udreq = (dl_unitdata_req_t *)buf2; udreq->dl_primitive = DL_UNITDATA_REQ; udreq->dl_dest_addr_offset = sizeof(dl_unitdata_req_t); udreq->dl_priority.dl_min = udreq->dl_priority.dl_max = 0; if (pkt_format == NS_INCLUDE_MAC) { udreq->dl_dest_addr_length = 0; /* place the destination address in the data portion */ p = dat2; bcopy(ctl.buf + udind->dl_src_addr_offset, p, 6); p += 6; bcopy(src_address, p, src_addr_sap_len); p += src_addr_sap_len; bcopy(dat.buf, p, dat.len); ctl.len = sizeof(dl_unitdata_req_t); dat.len += 6 + src_addr_sap_len; dat.buf = dat2; } else { udreq->dl_dest_addr_length = 6; memcpy(buf2 + udreq->dl_dest_addr_offset, ctl.buf + udind->dl_src_addr_offset, 6); ctl.len = sizeof(dl_unitdata_req_t) + 6; } ctl.buf = buf2; if (Verbose) dump("responding with:", 0, &dat); if (putmsg(fd, &ctl, &dat, 0)) die("putmsg"); ctl.buf = buf; ctl.maxlen = sizeof buf; flags = 0; if (pkt_format == NS_INCLUDE_MAC) { dat.buf = data; dat.maxlen = sizeof data; } } die("getmsg"); close(fd); exit(0); } errorack(p, msg) dl_error_ack_t *p; char *msg; { extern int errno; if (p->dl_errno != DL_SYSERR) fprintf(stderr, "%s: dl_errno %d\n", msg, p->dl_errno); else { errno = p->dl_unix_errno; perror(msg); } exit(1); } dump(msg, ctl, dat) char *msg; struct strbuf *ctl; struct strbuf *dat; { if (msg) { printf("%s\n", msg); } if (ctl) { printf("ctlbuf:\n"); hexdump(ctl->buf, ctl->len); } if (dat) { printf("datbuf:\n"); hexdump(dat->buf, dat->len); } } hexdump(p, len) char *p; int len; { int count = 0; while (len-- > 0) { if (count++ % 16 == 0 && count != 1) printf("\n"); printf("%02x ", *p++); } printf("\n"); } /* * request - make a DLPI request * * returns length of user data * stores proto data in res, user data in data[] */ int request(fd, req, req_len, res, res_len) int fd; caddr_t req; int req_len; caddr_t res; int res_len; { struct strbuf ctl, dat; int flags = 0; ctl.buf = req; ctl.len = req_len; if (putmsg(fd, &ctl, 0, 0)) die("putmsg"); ctl.buf = res; ctl.maxlen = res_len; dat.buf = data; dat.maxlen = sizeof data; dat.len = 0; if (getmsg(fd, &ctl, &dat, &flags) != 0) die("getmsg"); return dat.len; } /* * bind to sap */ bindsap(fd, sap) int fd; unsigned long sap; { dl_bind_ack_t *bindack; static dl_bind_req_t bind; char *p; int i; bind.dl_primitive = DL_BIND_REQ; bind.dl_sap = sap; bind.dl_max_conind = 0; bind.dl_service_mode = DL_CLDLS; bind.dl_conn_mgmt = 0; bind.dl_xidtest_flg = 0; (void)request(fd, &bind, sizeof bind, buf, sizeof buf); bindack = (dl_bind_ack_t *)buf; if (bindack->dl_primitive != DL_BIND_ACK) errorack(buf, "cannot bind"); bcopy(buf + bindack->dl_addr_offset, src_address, bindack->dl_addr_length); src_addr_sap_len = bindack->dl_addr_length; printf("%s: bound to:\n", Prog); printf(" sap = %x\n", bindack->dl_sap); printf(" address = "); p = buf + bindack->dl_addr_offset; for (i = bindack->dl_addr_length; i--;) printf("%02x:", *p++); printf("\n"); } /* * unbind */ unbindsap (fd) int fd; { static dl_unbind_req_t unbind; dl_ok_ack_t *okack; unbind.dl_primitive = DL_UNBIND_REQ; (void)request(fd, &unbind, sizeof unbind, buf, sizeof buf); okack = (dl_ok_ack_t *)buf; if (okack->dl_primitive != DL_OK_ACK) errorack(buf, "cannot unbind"); } /* * peer bind */ void peerbind(fd) int fd; { dl_subs_bind_req_t *peer; addr_t *ps; dl_ok_ack_t *okack; dl_error_ack_t *err_ack; peer = (dl_subs_bind_req_t *)buf; peer->dl_primitive = DL_SUBS_BIND_REQ; peer->dl_subs_bind_class = DL_PEER_BIND; peer->dl_subs_sap_offset = sizeof(*peer); for (ps = psaplist; ps; ps=ps->next) { peer->dl_subs_sap_length = ps->len; bcopy(ps->address, &peer[1], ps->len); (void)request(fd, peer, sizeof(*peer)+ps->len, buf, sizeof buf); err_ack = (dl_error_ack_t *)buf; if (err_ack->dl_primitive != DL_SUBS_BIND_ACK) { errno = err_ack->dl_unix_errno; die("cannot peer bind, dlerror %d", err_ack->dl_errno); } } printf("peer bind okay\n"); } int dl_stat(fd) int fd; { dl_get_statistics_req_t stat; dl_get_statistics_ack_t *statack; struct statistics *local; struct statistics *global; dl_ok_ack_t *okack; stat.dl_primitive = DL_GET_STATISTICS_REQ; (void)request(fd, &stat, sizeof stat, buf, sizeof buf); statack = (dl_get_statistics_ack_t *)buf; if (statack->dl_primitive != DL_GET_STATISTICS_ACK) errorack(buf, "cannot get statistics"); if (!statack->dl_stat_length || statack->dl_stat_length != 2*sizeof(struct statistics)) { printf("No statistics available\n"); return; } local = (struct statistics *)(buf + statack->dl_stat_offset); global = (struct statistics *)(buf + statack->dl_stat_offset + sizeof(struct statistics)); printf("\n%s: provider local (Per Stream) statistics:\n", Prog); printf("Number of received packets = %d\n", local->rx_pkts); printf("Number of transmitted packets = %d\n", local->tx_pkts); printf("Number of received bytes = %d\n", local->rx_bytes); printf("Number of transmitted bytes = %d\n", local->tx_bytes); printf("Number of incoming pkts discard = %d\n", local->rx_discards); printf("Number of outgoing pkts discard = %d\n", local->tx_discards); printf("Number of times no buffers = %d\n", local->no_bufs); printf("Number of successful binds = %d\n", local->binds); printf("Number of unknown message types = %d\n", local->unknown_msgs); printf("Status of phys level promisc = %d\n", local->promisc_phys); printf("Status of sap level promisc = %d\n", local->promisc_sap); printf("Status of multi level promisc = %d\n", local->promisc_multi); printf("Number of enab_multi addresses = %d\n",local->multicast_addrs); printf("\n%s: provider global (All Streams) statistics:\n", Prog); printf("Number of received packets = %d\n", global->rx_pkts); printf("Number of transmitted packets = %d\n", global->tx_pkts); printf("Number of received bytes = %d\n", global->rx_bytes); printf("Number of transmitted bytes = %d\n", global->tx_bytes); printf("Number of incoming pkts discard = %d\n", global->rx_discards); printf("Number of outgoing pkts discard = %d\n", global->tx_discards); printf("Number of times no buffers = %d\n", global->no_bufs); printf("Number of successful binds = %d\n", global->binds); printf("Number of unknown message types = %d\n", global->unknown_msgs); printf("Status of phys level promisc = %d\n", global->promisc_phys); printf("Status of sap level promisc = %d\n", global->promisc_sap); printf("Status of multi level promisc = %d\n", global->promisc_multi); printf("Number of enab_multi addresses = %d\n", global->multicast_addrs ); } /* * query - queries how many times we've done this */ query(dat) struct strbuf *dat; { (void)sprintf(data, "%05d", ++bar); dat->buf = data; dat->len = strlen(data)+1; dat->maxlen = sizeof data; } warn(s, a, b, c) char *s; int a, b, c; { extern int errno; char buf[200]; sprintf(buf, s, a, b, c); if (errno) perror(buf); else fprintf(stderr, "%s\n", buf); } die(s, a, b, c) char *s; int a, b, c; { warn(s, a, b, c); exit(1); } int conv(cp, buf) char *cp; char *buf; { char *p; char *addr; addr = buf; for (p = strtok(cp, ":"); p; p = strtok(0, ":")) { *addr++ = strtoul(p, 0, 16); } return ((int)addr - (int)buf); } usage() { fprintf(stderr, "usage: %s -n Node -s SAP [-b PeerSAP]... [-c] [-f PktFormat] [-m MultiAddr]... [-p Level] [-v]\n", Prog); exit(1); }