1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * sppptun.c - Solaris STREAMS PPP multiplexing tunnel driver 24*0Sstevel@tonic-gate * installer. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * Copyright (c) 2000-2001 by Sun Microsystems, Inc. 27*0Sstevel@tonic-gate * All rights reserved. 28*0Sstevel@tonic-gate */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <stdio.h> 33*0Sstevel@tonic-gate #include <stdlib.h> 34*0Sstevel@tonic-gate #include <unistd.h> 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <ctype.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate #include <signal.h> 39*0Sstevel@tonic-gate #include <alloca.h> 40*0Sstevel@tonic-gate #include <stropts.h> 41*0Sstevel@tonic-gate #include <fcntl.h> 42*0Sstevel@tonic-gate #include <locale.h> 43*0Sstevel@tonic-gate #include <sys/dlpi.h> 44*0Sstevel@tonic-gate #include <sys/fcntl.h> 45*0Sstevel@tonic-gate #include <sys/stropts.h> 46*0Sstevel@tonic-gate #include <sys/socket.h> 47*0Sstevel@tonic-gate #include <net/if.h> 48*0Sstevel@tonic-gate #include <netinet/in.h> 49*0Sstevel@tonic-gate #include <netinet/if_ether.h> 50*0Sstevel@tonic-gate #include <net/sppptun.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate static char *myname; /* Copied from argv[0] */ 53*0Sstevel@tonic-gate static int verbose; /* -v on command line */ 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate /* Data gathered during per-style attach routine. */ 56*0Sstevel@tonic-gate struct attach_data { 57*0Sstevel@tonic-gate ppptun_lname appstr; /* String to append to interface name (PPA) */ 58*0Sstevel@tonic-gate ppptun_atype localaddr; /* Local interface address */ 59*0Sstevel@tonic-gate int locallen; /* Length of local address */ 60*0Sstevel@tonic-gate }; 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* Per-protocol plumbing data */ 63*0Sstevel@tonic-gate struct protos { 64*0Sstevel@tonic-gate const char *name; 65*0Sstevel@tonic-gate const char *desc; 66*0Sstevel@tonic-gate int (*attach)(struct protos *prot, char *ifname, 67*0Sstevel@tonic-gate struct attach_data *adata); 68*0Sstevel@tonic-gate int protval; 69*0Sstevel@tonic-gate int style; 70*0Sstevel@tonic-gate }; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * Print a usage string and terminate. Used for command line argument 74*0Sstevel@tonic-gate * errors. Does not return. 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate static void 77*0Sstevel@tonic-gate usage(void) 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 80*0Sstevel@tonic-gate "Usage:\n\t%s plumb [<protocol> <device>]\n" 81*0Sstevel@tonic-gate "\t%s unplumb <interface-name>\n" 82*0Sstevel@tonic-gate "\t%s query\n"), myname, myname, myname); 83*0Sstevel@tonic-gate exit(1); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * Await a DLPI response to a previous driver command. "etype" is set 88*0Sstevel@tonic-gate * to the expected response primitive. "rptr" and "rlen" may point to 89*0Sstevel@tonic-gate * a buffer to hold returned data, if desired. Otherwise, "rptr" is 90*0Sstevel@tonic-gate * NULL. Returns -1 on error, 0 on success. 91*0Sstevel@tonic-gate * 92*0Sstevel@tonic-gate * If "rlen" is a positive number, then it indicates the number of 93*0Sstevel@tonic-gate * bytes expected in return, and any longer response is truncated to 94*0Sstevel@tonic-gate * that value, and any shorter response generates a warning message. 95*0Sstevel@tonic-gate * If it's a negative number, then it indicates the maximum number of 96*0Sstevel@tonic-gate * bytes expected, and no warning is printed if fewer are received. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate static int 99*0Sstevel@tonic-gate dlpi_reply(int fd, int etype, void *rptr, int rlen) 100*0Sstevel@tonic-gate { 101*0Sstevel@tonic-gate /* Align 'buf' on natural boundary for aggregates. */ 102*0Sstevel@tonic-gate uintptr_t buf[BUFSIZ/sizeof (uintptr_t)]; 103*0Sstevel@tonic-gate int flags; 104*0Sstevel@tonic-gate union DL_primitives *dlp = (union DL_primitives *)buf; 105*0Sstevel@tonic-gate struct strbuf ctl; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* read reply */ 108*0Sstevel@tonic-gate ctl.buf = (caddr_t)dlp; 109*0Sstevel@tonic-gate ctl.len = 0; 110*0Sstevel@tonic-gate ctl.maxlen = BUFSIZ; 111*0Sstevel@tonic-gate flags = 0; 112*0Sstevel@tonic-gate if (getmsg(fd, &ctl, NULL, &flags) < 0) { 113*0Sstevel@tonic-gate perror("getmsg"); 114*0Sstevel@tonic-gate return (-1); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate /* Validate reply. */ 118*0Sstevel@tonic-gate if (ctl.len < sizeof (t_uscalar_t)) { 119*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: request: short reply\n"), 120*0Sstevel@tonic-gate myname); 121*0Sstevel@tonic-gate return (-1); 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate if (dlp->dl_primitive == DL_ERROR_ACK) { 125*0Sstevel@tonic-gate (void) fprintf(stderr, 126*0Sstevel@tonic-gate gettext("%s: request: dl_errno %lu errno %lu\n"), myname, 127*0Sstevel@tonic-gate dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno); 128*0Sstevel@tonic-gate return (-1); 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate if (dlp->dl_primitive != etype) { 131*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: request: unexpected " 132*0Sstevel@tonic-gate "dl_primitive %lu received\n"), myname, dlp->dl_primitive); 133*0Sstevel@tonic-gate return (-1); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate if (rptr == NULL) 136*0Sstevel@tonic-gate return (0); 137*0Sstevel@tonic-gate if (ctl.len < rlen) { 138*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: request: short information" 139*0Sstevel@tonic-gate " received %d < %d\n"), myname, ctl.len, rlen); 140*0Sstevel@tonic-gate return (-1); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate if (rlen < 0) 143*0Sstevel@tonic-gate rlen = -rlen; 144*0Sstevel@tonic-gate (void) memcpy(rptr, buf, rlen); 145*0Sstevel@tonic-gate return (0); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate /* 149*0Sstevel@tonic-gate * Send a DLPI Info-Request message and return the response in the 150*0Sstevel@tonic-gate * provided buffer. Returns -1 on error, 0 on success. 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate static int 153*0Sstevel@tonic-gate dlpi_info_req(int fd, dl_info_ack_t *info_ack) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate dl_info_req_t info_req; 156*0Sstevel@tonic-gate struct strbuf ctl; 157*0Sstevel@tonic-gate int flags; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate (void) memset(&info_req, '\0', sizeof (info_req)); 160*0Sstevel@tonic-gate info_req.dl_primitive = DL_INFO_REQ; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate ctl.maxlen = 0; 163*0Sstevel@tonic-gate ctl.len = DL_INFO_REQ_SIZE; 164*0Sstevel@tonic-gate ctl.buf = (char *)&info_req; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate flags = 0; 167*0Sstevel@tonic-gate if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) { 168*0Sstevel@tonic-gate perror("putmsg DL_INFO_REQ"); 169*0Sstevel@tonic-gate return (-1); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate return (dlpi_reply(fd, DL_INFO_ACK, info_ack, sizeof (*info_ack))); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * Send a DLPI Attach-Request message for the indicated PPA. Returns 176*0Sstevel@tonic-gate * -1 on error, 0 for success. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate static int 179*0Sstevel@tonic-gate dlpi_attach_req(int fd, int ppa) 180*0Sstevel@tonic-gate { 181*0Sstevel@tonic-gate dl_attach_req_t attach_req; 182*0Sstevel@tonic-gate struct strbuf ctl; 183*0Sstevel@tonic-gate int flags; 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate (void) memset(&attach_req, '\0', sizeof (attach_req)); 186*0Sstevel@tonic-gate attach_req.dl_primitive = DL_ATTACH_REQ; 187*0Sstevel@tonic-gate attach_req.dl_ppa = ppa; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate ctl.maxlen = 0; 190*0Sstevel@tonic-gate ctl.len = DL_ATTACH_REQ_SIZE; 191*0Sstevel@tonic-gate ctl.buf = (char *)&attach_req; 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate flags = 0; 194*0Sstevel@tonic-gate if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) { 195*0Sstevel@tonic-gate perror("putmsg DL_ATTACH_REQ"); 196*0Sstevel@tonic-gate return (-1); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate return (dlpi_reply(fd, DL_OK_ACK, NULL, 0)); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate /* 202*0Sstevel@tonic-gate * Send a DLPI Bind-Request message for the requested SAP and set the 203*0Sstevel@tonic-gate * local address. Returns -1 for error. Otherwise, the length of the 204*0Sstevel@tonic-gate * local address is returned. 205*0Sstevel@tonic-gate */ 206*0Sstevel@tonic-gate static int 207*0Sstevel@tonic-gate dlpi_bind_req(int fd, int sap, uint8_t *localaddr, int maxaddr) 208*0Sstevel@tonic-gate { 209*0Sstevel@tonic-gate dl_bind_req_t bind_req; 210*0Sstevel@tonic-gate dl_bind_ack_t *back; 211*0Sstevel@tonic-gate struct strbuf ctl; 212*0Sstevel@tonic-gate int flags, repsize, rsize; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate (void) memset(&bind_req, '\0', sizeof (*&bind_req)); 215*0Sstevel@tonic-gate bind_req.dl_primitive = DL_BIND_REQ; 216*0Sstevel@tonic-gate /* DLPI SAPs are in host byte order! */ 217*0Sstevel@tonic-gate bind_req.dl_sap = sap; 218*0Sstevel@tonic-gate bind_req.dl_service_mode = DL_CLDLS; 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate ctl.maxlen = 0; 221*0Sstevel@tonic-gate ctl.len = DL_BIND_REQ_SIZE; 222*0Sstevel@tonic-gate ctl.buf = (char *)&bind_req; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate flags = 0; 225*0Sstevel@tonic-gate if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) { 226*0Sstevel@tonic-gate perror("putmsg DL_BIND_REQ"); 227*0Sstevel@tonic-gate return (-1); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate repsize = sizeof (*back) + maxaddr; 231*0Sstevel@tonic-gate back = (dl_bind_ack_t *)alloca(repsize); 232*0Sstevel@tonic-gate if (dlpi_reply(fd, DL_BIND_ACK, (void *)back, -repsize) < 0) 233*0Sstevel@tonic-gate return (-1); 234*0Sstevel@tonic-gate rsize = back->dl_addr_length; 235*0Sstevel@tonic-gate if (rsize > maxaddr || back->dl_addr_offset+rsize > repsize) { 236*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Bad hardware address size " 237*0Sstevel@tonic-gate "from driver; %d > %d or %lu+%d > %d\n"), myname, 238*0Sstevel@tonic-gate rsize, maxaddr, back->dl_addr_offset, rsize, repsize); 239*0Sstevel@tonic-gate return (-1); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate (void) memcpy(localaddr, (char *)back + back->dl_addr_offset, rsize); 242*0Sstevel@tonic-gate return (rsize); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* 246*0Sstevel@tonic-gate * Return a printable string for a DLPI style number. (Unfortunately, 247*0Sstevel@tonic-gate * these style numbers aren't just simple integer values, and printing 248*0Sstevel@tonic-gate * with %d gives ugly output.) 249*0Sstevel@tonic-gate */ 250*0Sstevel@tonic-gate static const char * 251*0Sstevel@tonic-gate styleof(int dlstyle) 252*0Sstevel@tonic-gate { 253*0Sstevel@tonic-gate static char buf[32]; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate switch (dlstyle) { 256*0Sstevel@tonic-gate case DL_STYLE1: 257*0Sstevel@tonic-gate return ("1"); 258*0Sstevel@tonic-gate case DL_STYLE2: 259*0Sstevel@tonic-gate return ("2"); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext("Unknown (0x%04X)"), 262*0Sstevel@tonic-gate dlstyle); 263*0Sstevel@tonic-gate return ((const char *)buf); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * General DLPI attach function. This is called indirectly through 268*0Sstevel@tonic-gate * the protos structure for the selected lower stream protocol. 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate static int 271*0Sstevel@tonic-gate dlpi_attach(struct protos *prot, char *ifname, struct attach_data *adata) 272*0Sstevel@tonic-gate { 273*0Sstevel@tonic-gate int devfd, ppa, dlstyle, retv; 274*0Sstevel@tonic-gate dl_info_ack_t dl_info; 275*0Sstevel@tonic-gate char tname[MAXPATHLEN], *cp; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate cp = ifname + strlen(ifname) - 1; 278*0Sstevel@tonic-gate while (cp > ifname && isdigit(*cp)) 279*0Sstevel@tonic-gate cp--; 280*0Sstevel@tonic-gate cp++; 281*0Sstevel@tonic-gate ppa = strtol(cp, NULL, 10); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* 284*0Sstevel@tonic-gate * Try once for the exact device name as a node. If it's 285*0Sstevel@tonic-gate * there, then this should be a DLPI style 1 driver (one node 286*0Sstevel@tonic-gate * per instance). If it's not, then it should be a style 2 287*0Sstevel@tonic-gate * driver (attach specifies instance number). 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate dlstyle = DL_STYLE1; 290*0Sstevel@tonic-gate (void) strlcpy(tname, ifname, MAXPATHLEN-1); 291*0Sstevel@tonic-gate if ((devfd = open(tname, O_RDWR)) < 0) { 292*0Sstevel@tonic-gate if (cp < ifname + MAXPATHLEN) 293*0Sstevel@tonic-gate tname[cp - ifname] = '\0'; 294*0Sstevel@tonic-gate if ((devfd = open(tname, O_RDWR)) < 0) { 295*0Sstevel@tonic-gate perror(ifname); 296*0Sstevel@tonic-gate return (-1); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate dlstyle = DL_STYLE2; 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate if (verbose) 302*0Sstevel@tonic-gate (void) printf(gettext("requesting device info on %s\n"), 303*0Sstevel@tonic-gate tname); 304*0Sstevel@tonic-gate if (dlpi_info_req(devfd, &dl_info)) 305*0Sstevel@tonic-gate return (-1); 306*0Sstevel@tonic-gate if (dl_info.dl_provider_style != dlstyle) { 307*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unexpected DLPI provider " 308*0Sstevel@tonic-gate "style on %s: got %s, "), myname, tname, 309*0Sstevel@tonic-gate styleof(dl_info.dl_provider_style)); 310*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("expected %s\n"), 311*0Sstevel@tonic-gate styleof(dlstyle)); 312*0Sstevel@tonic-gate if (ifname[0] != '\0' && 313*0Sstevel@tonic-gate !isdigit(ifname[strlen(ifname) - 1])) { 314*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("(did you forget an " 315*0Sstevel@tonic-gate "instance number?)\n")); 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate (void) close(devfd); 318*0Sstevel@tonic-gate return (-1); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate if (dlstyle == DL_STYLE2) { 322*0Sstevel@tonic-gate if (verbose) 323*0Sstevel@tonic-gate (void) printf(gettext("attaching to ppa %d\n"), ppa); 324*0Sstevel@tonic-gate if (dlpi_attach_req(devfd, ppa)) { 325*0Sstevel@tonic-gate (void) close(devfd); 326*0Sstevel@tonic-gate return (-1); 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (verbose) 331*0Sstevel@tonic-gate (void) printf(gettext("binding to Ethertype %04X\n"), 332*0Sstevel@tonic-gate prot->protval); 333*0Sstevel@tonic-gate retv = dlpi_bind_req(devfd, prot->protval, 334*0Sstevel@tonic-gate (uint8_t *)&adata->localaddr, sizeof (adata->localaddr)); 335*0Sstevel@tonic-gate if (retv < 0) { 336*0Sstevel@tonic-gate (void) close(devfd); 337*0Sstevel@tonic-gate return (-1); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate adata->locallen = retv; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate (void) snprintf(adata->appstr, sizeof (adata->appstr), "%d", ppa); 342*0Sstevel@tonic-gate return (devfd); 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate static struct protos proto_list[] = { 347*0Sstevel@tonic-gate { "pppoe", "RFC 2516 PPP over Ethernet", dlpi_attach, ETHERTYPE_PPPOES, 348*0Sstevel@tonic-gate PTS_PPPOE }, 349*0Sstevel@tonic-gate { "pppoed", "RFC 2516 PPP over Ethernet Discovery", dlpi_attach, 350*0Sstevel@tonic-gate ETHERTYPE_PPPOED, PTS_PPPOE }, 351*0Sstevel@tonic-gate { NULL } 352*0Sstevel@tonic-gate }; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Issue a STREAMS I_STR ioctl and fetch the result. Returns -1 on 356*0Sstevel@tonic-gate * error, or length of returned data on success. 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate static int 359*0Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen, const char *iocname) 360*0Sstevel@tonic-gate { 361*0Sstevel@tonic-gate struct strioctl str; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate str.ic_cmd = cmd; 364*0Sstevel@tonic-gate str.ic_timout = 0; 365*0Sstevel@tonic-gate str.ic_len = ilen; 366*0Sstevel@tonic-gate str.ic_dp = ptr; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate if (ioctl(fd, I_STR, &str) == -1) { 369*0Sstevel@tonic-gate perror(iocname); 370*0Sstevel@tonic-gate return (-1); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate if (olen >= 0) { 374*0Sstevel@tonic-gate if (str.ic_len > olen && verbose > 1) { 375*0Sstevel@tonic-gate (void) printf(gettext("%s:%s: extra data received; " 376*0Sstevel@tonic-gate "%d > %d\n"), myname, iocname, str.ic_len, olen); 377*0Sstevel@tonic-gate } else if (str.ic_len < olen) { 378*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s:%s: expected %d " 379*0Sstevel@tonic-gate "bytes, got %d\n"), myname, iocname, olen, 380*0Sstevel@tonic-gate str.ic_len); 381*0Sstevel@tonic-gate return (-1); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate return (str.ic_len); 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * Handle user request to plumb a new lower stream under the sppptun 390*0Sstevel@tonic-gate * driver. 391*0Sstevel@tonic-gate */ 392*0Sstevel@tonic-gate static int 393*0Sstevel@tonic-gate plumb_it(int argc, char **argv) 394*0Sstevel@tonic-gate { 395*0Sstevel@tonic-gate int devfd, muxfd, muxid; 396*0Sstevel@tonic-gate struct ppptun_info pti; 397*0Sstevel@tonic-gate char *cp, *ifname; 398*0Sstevel@tonic-gate struct protos *prot; 399*0Sstevel@tonic-gate char dname[MAXPATHLEN]; 400*0Sstevel@tonic-gate struct attach_data adata; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate /* If no protocol requested, then list known protocols. */ 403*0Sstevel@tonic-gate if (optind == argc) { 404*0Sstevel@tonic-gate (void) puts("Known tunneling protocols:"); 405*0Sstevel@tonic-gate for (prot = proto_list; prot->name != NULL; prot++) 406*0Sstevel@tonic-gate (void) printf("\t%s\t%s\n", prot->name, prot->desc); 407*0Sstevel@tonic-gate return (0); 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate /* If missing protocol or device, then abort. */ 411*0Sstevel@tonic-gate if (optind != argc-2) 412*0Sstevel@tonic-gate usage(); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* Look up requested protocol. */ 415*0Sstevel@tonic-gate cp = argv[optind++]; 416*0Sstevel@tonic-gate for (prot = proto_list; prot->name != NULL; prot++) 417*0Sstevel@tonic-gate if (strcasecmp(cp, prot->name) == 0) 418*0Sstevel@tonic-gate break; 419*0Sstevel@tonic-gate if (prot->name == NULL) { 420*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown protocol %s\n"), 421*0Sstevel@tonic-gate myname, cp); 422*0Sstevel@tonic-gate return (1); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate /* Get interface and make relative to /dev/ if necessary. */ 426*0Sstevel@tonic-gate ifname = argv[optind]; 427*0Sstevel@tonic-gate if (ifname[0] != '.' && ifname[0] != '/') { 428*0Sstevel@tonic-gate (void) snprintf(dname, sizeof (dname), "/dev/%s", ifname); 429*0Sstevel@tonic-gate ifname = dname; 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate /* Call per-protocol attach routine to open device */ 433*0Sstevel@tonic-gate if (verbose) 434*0Sstevel@tonic-gate (void) printf(gettext("opening %s\n"), ifname); 435*0Sstevel@tonic-gate devfd = (*prot->attach)(prot, ifname, &adata); 436*0Sstevel@tonic-gate if (devfd < 0) 437*0Sstevel@tonic-gate return (1); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* Open sppptun driver */ 440*0Sstevel@tonic-gate if (verbose) 441*0Sstevel@tonic-gate (void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME); 442*0Sstevel@tonic-gate if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) { 443*0Sstevel@tonic-gate perror("/dev/" PPP_TUN_NAME); 444*0Sstevel@tonic-gate return (1); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate /* Push sppptun module on top of lower driver. */ 448*0Sstevel@tonic-gate if (verbose) 449*0Sstevel@tonic-gate (void) printf(gettext("pushing %s on %s\n"), PPP_TUN_NAME, 450*0Sstevel@tonic-gate ifname); 451*0Sstevel@tonic-gate if (ioctl(devfd, I_PUSH, PPP_TUN_NAME) == -1) { 452*0Sstevel@tonic-gate perror("I_PUSH " PPP_TUN_NAME); 453*0Sstevel@tonic-gate return (1); 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate /* Get the name of the newly-created lower stream. */ 457*0Sstevel@tonic-gate if (verbose) 458*0Sstevel@tonic-gate (void) printf(gettext("getting new interface name\n")); 459*0Sstevel@tonic-gate if (strioctl(devfd, PPPTUN_GNAME, pti.pti_name, 0, 460*0Sstevel@tonic-gate sizeof (pti.pti_name), "PPPTUN_GNAME") < 0) 461*0Sstevel@tonic-gate return (1); 462*0Sstevel@tonic-gate if (verbose) 463*0Sstevel@tonic-gate (void) printf(gettext("got interface %s\n"), pti.pti_name); 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate /* Convert stream name to protocol-specific name. */ 466*0Sstevel@tonic-gate if ((cp = strchr(pti.pti_name, ':')) != NULL) 467*0Sstevel@tonic-gate *cp = '\0'; 468*0Sstevel@tonic-gate (void) snprintf(pti.pti_name+strlen(pti.pti_name), 469*0Sstevel@tonic-gate sizeof (pti.pti_name)-strlen(pti.pti_name), "%s:%s", adata.appstr, 470*0Sstevel@tonic-gate prot->name); 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate /* Change the lower stream name. */ 473*0Sstevel@tonic-gate if (verbose) 474*0Sstevel@tonic-gate (void) printf(gettext("resetting interface name to %s\n"), 475*0Sstevel@tonic-gate pti.pti_name); 476*0Sstevel@tonic-gate if (strioctl(devfd, PPPTUN_SNAME, pti.pti_name, 477*0Sstevel@tonic-gate sizeof (pti.pti_name), 0, "PPPTUN_SNAME") < 0) { 478*0Sstevel@tonic-gate if (errno == EEXIST) 479*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: %s already " 480*0Sstevel@tonic-gate "installed\n"), myname, pti.pti_name); 481*0Sstevel@tonic-gate return (1); 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate /* 485*0Sstevel@tonic-gate * Send down the local interface address to the lower stream 486*0Sstevel@tonic-gate * so that it can originate packets. 487*0Sstevel@tonic-gate */ 488*0Sstevel@tonic-gate if (verbose) 489*0Sstevel@tonic-gate (void) printf(gettext("send down local address\n")); 490*0Sstevel@tonic-gate if (strioctl(devfd, PPPTUN_LCLADDR, &adata.localaddr, adata.locallen, 491*0Sstevel@tonic-gate 0, "PPPTUN_LCLADDR") < 0) 492*0Sstevel@tonic-gate return (1); 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* Link the lower stream under the tunnel device. */ 495*0Sstevel@tonic-gate if (verbose) 496*0Sstevel@tonic-gate (void) printf(gettext("doing I_PLINK\n")); 497*0Sstevel@tonic-gate if ((muxid = ioctl(muxfd, I_PLINK, devfd)) == -1) { 498*0Sstevel@tonic-gate perror("I_PLINK"); 499*0Sstevel@tonic-gate return (1); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* 503*0Sstevel@tonic-gate * Give the tunnel driver the multiplex ID of the new lower 504*0Sstevel@tonic-gate * stream. This allows the unplumb function to find and 505*0Sstevel@tonic-gate * disconnect the lower stream. 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate if (verbose) 508*0Sstevel@tonic-gate (void) printf(gettext("sending muxid %d and style %d to " 509*0Sstevel@tonic-gate "driver\n"), muxid, prot->style); 510*0Sstevel@tonic-gate pti.pti_muxid = muxid; 511*0Sstevel@tonic-gate pti.pti_style = prot->style; 512*0Sstevel@tonic-gate if (strioctl(muxfd, PPPTUN_SINFO, &pti, sizeof (pti), 0, 513*0Sstevel@tonic-gate "PPPTUN_SINFO") < 0) 514*0Sstevel@tonic-gate return (1); 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (verbose) 517*0Sstevel@tonic-gate (void) printf(gettext("done; installed %s\n"), pti.pti_name); 518*0Sstevel@tonic-gate else 519*0Sstevel@tonic-gate (void) puts(pti.pti_name); 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate return (0); 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate /* 525*0Sstevel@tonic-gate * Handle user request to unplumb an existing lower stream from the 526*0Sstevel@tonic-gate * sppptun driver. 527*0Sstevel@tonic-gate */ 528*0Sstevel@tonic-gate static int 529*0Sstevel@tonic-gate unplumb_it(int argc, char **argv) 530*0Sstevel@tonic-gate { 531*0Sstevel@tonic-gate char *ifname; 532*0Sstevel@tonic-gate int muxfd; 533*0Sstevel@tonic-gate struct ppptun_info pti; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* 536*0Sstevel@tonic-gate * Need to have the name of the lower stream on the command 537*0Sstevel@tonic-gate * line. 538*0Sstevel@tonic-gate */ 539*0Sstevel@tonic-gate if (optind != argc-1) 540*0Sstevel@tonic-gate usage(); 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate ifname = argv[optind]; 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* Open the tunnel driver. */ 545*0Sstevel@tonic-gate if (verbose) 546*0Sstevel@tonic-gate (void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME); 547*0Sstevel@tonic-gate if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) { 548*0Sstevel@tonic-gate perror("/dev/" PPP_TUN_NAME); 549*0Sstevel@tonic-gate return (1); 550*0Sstevel@tonic-gate } 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate /* Get lower stream information; including multiplex ID. */ 553*0Sstevel@tonic-gate if (verbose) 554*0Sstevel@tonic-gate (void) printf(gettext("getting info from driver\n")); 555*0Sstevel@tonic-gate (void) strncpy(pti.pti_name, ifname, sizeof (pti.pti_name)); 556*0Sstevel@tonic-gate if (strioctl(muxfd, PPPTUN_GINFO, &pti, sizeof (pti), 557*0Sstevel@tonic-gate sizeof (pti), "PPPTUN_GINFO") < 0) 558*0Sstevel@tonic-gate return (1); 559*0Sstevel@tonic-gate if (verbose) 560*0Sstevel@tonic-gate (void) printf(gettext("got muxid %d from driver\n"), 561*0Sstevel@tonic-gate pti.pti_muxid); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate /* Unlink lower stream from driver. */ 564*0Sstevel@tonic-gate if (verbose) 565*0Sstevel@tonic-gate (void) printf(gettext("doing I_PUNLINK\n")); 566*0Sstevel@tonic-gate if (ioctl(muxfd, I_PUNLINK, pti.pti_muxid) < 0) { 567*0Sstevel@tonic-gate perror("I_PUNLINK"); 568*0Sstevel@tonic-gate return (1); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate if (verbose) 571*0Sstevel@tonic-gate (void) printf(gettext("done!\n")); 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate return (0); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * Handle user request to list lower streams plumbed under the sppptun 578*0Sstevel@tonic-gate * driver. 579*0Sstevel@tonic-gate */ 580*0Sstevel@tonic-gate /*ARGSUSED*/ 581*0Sstevel@tonic-gate static int 582*0Sstevel@tonic-gate query_interfaces(int argc, char **argv) 583*0Sstevel@tonic-gate { 584*0Sstevel@tonic-gate int muxfd, i; 585*0Sstevel@tonic-gate union ppptun_name ptn; 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate /* No other arguments permitted. */ 588*0Sstevel@tonic-gate if (optind != argc) 589*0Sstevel@tonic-gate usage(); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate /* Open the tunnel driver. */ 592*0Sstevel@tonic-gate if (verbose) 593*0Sstevel@tonic-gate (void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME); 594*0Sstevel@tonic-gate if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) { 595*0Sstevel@tonic-gate perror("/dev/" PPP_TUN_NAME); 596*0Sstevel@tonic-gate return (1); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* Read and print names of lower streams. */ 600*0Sstevel@tonic-gate for (i = 0; ; i++) { 601*0Sstevel@tonic-gate ptn.ptn_index = i; 602*0Sstevel@tonic-gate if (strioctl(muxfd, PPPTUN_GNNAME, &ptn, sizeof (ptn), 603*0Sstevel@tonic-gate sizeof (ptn), "PPPTUN_GNNAME") < 0) { 604*0Sstevel@tonic-gate perror("PPPTUN_GNNAME"); 605*0Sstevel@tonic-gate break; 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate /* Stop when we index off the end of the list. */ 608*0Sstevel@tonic-gate if (ptn.ptn_name[0] == '\0') 609*0Sstevel@tonic-gate break; 610*0Sstevel@tonic-gate (void) puts(ptn.ptn_name); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate return (0); 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate /* 616*0Sstevel@tonic-gate * Invoked by SIGALRM -- timer prevents problems in driver from 617*0Sstevel@tonic-gate * hanging the utility. 618*0Sstevel@tonic-gate */ 619*0Sstevel@tonic-gate /*ARGSUSED*/ 620*0Sstevel@tonic-gate static void 621*0Sstevel@tonic-gate toolong(int dummy) 622*0Sstevel@tonic-gate { 623*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: time-out in driver\n"), myname); 624*0Sstevel@tonic-gate exit(1); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate int 628*0Sstevel@tonic-gate main(int argc, char **argv) 629*0Sstevel@tonic-gate { 630*0Sstevel@tonic-gate int opt, errflag = 0; 631*0Sstevel@tonic-gate char *arg; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate myname = *argv; 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 639*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 640*0Sstevel@tonic-gate #endif 641*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate /* Parse command line flags */ 644*0Sstevel@tonic-gate while ((opt = getopt(argc, argv, "v")) != EOF) 645*0Sstevel@tonic-gate switch (opt) { 646*0Sstevel@tonic-gate case 'v': 647*0Sstevel@tonic-gate verbose++; 648*0Sstevel@tonic-gate break; 649*0Sstevel@tonic-gate default: 650*0Sstevel@tonic-gate errflag++; 651*0Sstevel@tonic-gate break; 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate if (errflag != 0 || optind >= argc) 654*0Sstevel@tonic-gate usage(); 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate /* Set alarm to avoid stalling on any driver errors. */ 657*0Sstevel@tonic-gate (void) signal(SIGALRM, toolong); 658*0Sstevel@tonic-gate (void) alarm(2); 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate /* Switch out based on user-requested function. */ 661*0Sstevel@tonic-gate arg = argv[optind++]; 662*0Sstevel@tonic-gate if (strcmp(arg, "plumb") == 0) 663*0Sstevel@tonic-gate return (plumb_it(argc, argv)); 664*0Sstevel@tonic-gate if (strcmp(arg, "unplumb") == 0) 665*0Sstevel@tonic-gate return (unplumb_it(argc, argv)); 666*0Sstevel@tonic-gate if (strcmp(arg, "query") == 0) 667*0Sstevel@tonic-gate return (query_interfaces(argc, argv)); 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate usage(); 670*0Sstevel@tonic-gate return (1); 671*0Sstevel@tonic-gate } 672