/* SPDX-License-Identifier: GPL-2.0 */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PPP_DEV "/dev/ppp" extern char **environ; int main(int argc, char *argv[]) { const char *usage = "usage: pppdlite TTY [PROG...]\n" "\n" "Options:\n" "\n" " -h Print this help text.\n" " -s BAUDRATE Configure the TTY to use this baudrate. (Default: 115200)\n" "\n" "Initialize and hold open a PPP connection on TTY with the baudrate\n" "BAUDRATE.\n" "If [PROG...] is specified it is executed once the connection is initialized\n" "with the environment variable PPPDLITE_IFNAME set to the interface name\n" "of the newly created network interface."; int tty_fd, ppp_ch_fd, ppp_unit_fd; int ppp_disc = N_PPP; int ch_idx; int unit = -1; const char *tty; speed_t speed = B115200; int opt, rv; while ((opt = getopt(argc, argv, "hs:")) > 0) { switch (opt) { case 'h': fprintf(stderr, "%s\n", usage); exit(0); break; case 's': if (term_speed_parse(optarg, &speed) < 0) errx(EXIT_FAIL_USAGE, "fatal: unable to parse the command line: unknown argument to -s: %s\n%s", optarg, usage); break; default: errx(EXIT_FAIL_USAGE, "fatal: unable to parse the command line: unknown option: '%c'\n%s", opt, usage); break; } } argv += optind; argc -= optind; if (argc < 1) { errx(EXIT_FAIL_USAGE, "fatal: unable to parse the command line: not enough arguments\n%s", usage); } tty = argv[0]; argv += 1; argc -= 1; /* 1. tty */ tty_fd = open(tty, O_RDWR|O_CLOEXEC); if (tty_fd < 0) err(EXIT_FAIL_USAGE, "fatal: unable to open %s", tty); /* set exclusive mode */ if (ioctl(tty_fd, TIOCEXCL, 0) < 0 && errno != EIO) err(EXIT_FAIL_USAGE, "fatal: unable to open %s exclusively", tty); /* tty setting */ if (term_setconf_init() < 0 || term_setconf_raw(tty_fd, speed) < 0) err(EXIT_FAIL_MISC, "fatal: unable to configure the terminal"); /* set tty to ppp line discipline */ if (ioctl(tty_fd, TIOCSETD, &ppp_disc)) err(EXIT_FAIL_MISC, "fatal: unable to enable the PPP line discipline on %s", tty); /* get channel index */ if (ioctl(tty_fd, PPPIOCGCHAN, &ch_idx) < 0) err(EXIT_FAIL_MISC, "fatal: unable to get a PPP channel index from %s", tty); /* 2. ppp channel */ ppp_ch_fd = open(PPP_DEV, O_RDWR); if (ppp_ch_fd < 0) err(EXIT_FAIL_MISC, "fatal: unable to open %s", PPP_DEV); /* connect attach tty to channel */ if (ioctl(ppp_ch_fd, PPPIOCATTCHAN, &ch_idx) < 0) err(EXIT_FAIL_MISC, "fatal: unable to attach %s to the ppp channel", tty); /* 3. ppp unit */ ppp_unit_fd = open(PPP_DEV, O_RDWR); if (ppp_unit_fd < 0) err(EXIT_FAIL_MISC, "fatal: unable to open %s", PPP_DEV); if (ioctl(ppp_unit_fd, PPPIOCNEWUNIT, &unit) < 0) err(EXIT_FAIL_MISC, "fatal: unable to create a new PPP instance"); /* connect ppp channel to ppp unit */ if (ioctl(ppp_ch_fd, PPPIOCCONNECT, &unit) < 0) err(EXIT_FAIL_MISC, "fatal: unable to connect the PPP channel to the PPP unit"); if (argc) { char ifname[IFNAMSIZ]; pid_t pid; int status; rv = snprintf(ifname, sizeof(ifname), "ppp%d", unit); if (rv < 0) err(EXIT_FAIL_MISC, "fatal: unable to set $PPPDLITE_IFNAME"); if ((size_t)rv >= sizeof(ifname)) errx(EXIT_FAIL_MISC, "fatal: unable to set $PPPDLITE_IFNAME: the name ppp%d is too long", unit); if (setenv("PPPDLITE_IFNAME", ifname, 1) < 0) err(EXIT_FAIL_MISC, "fatal: unable to set $PPPDLITE_IFNAME"); errno = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); if (errno) err(EXIT_FAIL_MISC, "fatal: unable to spawn %s", argv[0]); if (waitpid(pid, &status, 0) < 0) err(EXIT_FAIL_MISC, "fatal: unable to wait on a child process"); if (WIFEXITED(status)) { if (WEXITSTATUS(status)) errx(EXIT_FAIL_MISC, "fatal: unable to run %s: the subprocess returned %d", argv[0], WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { errx(EXIT_FAIL_MISC, "fatal: unable to run %s: the subprocess was killed by signal %d", argv[0], WTERMSIG(status)); } else { errx(EXIT_FAIL_MISC, "fatal: unable to run %s: the subprocess died with status %d", argv[0], status); } } for (;;) { uint8_t buf[2048]; long i; long len = read(ppp_unit_fd, buf, sizeof(buf)); if (len < 0) break; printf("rx: len %ld", len); for (i = 0; i < len; i++) { switch (i % 16) { case 0: printf("\n"); break; case 4: case 8: case 12: printf(" "); break; } printf("%02x", buf[i]); } printf("\n"); } return 0; }