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