📄 main.c
字号:
kill_link = 0; } if (get_loop_output()) break; if (got_sigchld) reap_kids(0); } remove_fd(fd_loop); if (kill_link && !persist) break; /* * Now we want to bring up the link. */ demand_block(); info("Starting link"); } new_phase(PHASE_SERIALCONN); /* * Get a pty master/slave pair if the pty, notty, or record * options were specified. */ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam)); pty_master = -1; pty_slave = -1; if (ptycommand != NULL || notty || record_file != NULL) { if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) { error("Couldn't allocate pseudo-tty"); status = EXIT_FATAL_ERROR; goto fail; } set_up_tty(pty_slave, 1); } /* * Lock the device if we've been asked to. */ status = EXIT_LOCK_FAILED; if (lockflag && !privopen) { if (lock(devnam) < 0) goto fail; locked = 1; } /* * Open the serial device and set it up to be the ppp interface. * First we open it in non-blocking mode so we can set the * various termios flags appropriately. If we aren't dialling * out and we want to use the modem lines, we reopen it later * in order to wait for the carrier detect signal from the modem. */ hungup = 0; kill_link = 0; connector = doing_callback? callback_script: connect_script; if (devnam[0] != 0) { for (;;) { /* If the user specified the device name, become the user before opening it. */ int err; if (!devnam_info.priv && !privopen) seteuid(uid); ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0); err = errno; if (!devnam_info.priv && !privopen) seteuid(0); if (ttyfd >= 0) break; errno = err; if (err != EINTR) { error("Failed to open %s: %m", devnam); status = EXIT_OPEN_FAILED; } if (!persist || err != EINTR) goto fail; } if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1 || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) warn("Couldn't reset non-blocking mode on device: %m"); /* * Do the equivalent of `mesg n' to stop broadcast messages. */ if (fstat(ttyfd, &statbuf) < 0 || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) { warn("Couldn't restrict write permissions to %s: %m", devnam); } else tty_mode = statbuf.st_mode; /* * Set line speed, flow control, etc. * If we have a non-null connection or initializer script, * on most systems we set CLOCAL for now so that we can talk * to the modem before carrier comes up. But this has the * side effect that we might miss it if CD drops before we * get to clear CLOCAL below. On systems where we can talk * successfully to the modem with CLOCAL clear and CD down, * we could clear CLOCAL at this point. */ set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0) || initializer != NULL)); real_ttyfd = ttyfd; } /* * If the notty and/or record option was specified, * start up the character shunt now. */ status = EXIT_PTYCMD_FAILED; if (ptycommand != NULL) { if (record_file != NULL) { int ipipe[2], opipe[2], ok; if (pipe(ipipe) < 0 || pipe(opipe) < 0) fatal("Couldn't create pipes for record option: %m"); ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0 && start_charshunt(ipipe[0], opipe[1]); close(ipipe[0]); close(ipipe[1]); close(opipe[0]); close(opipe[1]); if (!ok) goto fail; } else { if (device_script(ptycommand, pty_master, pty_master, 1) < 0) goto fail; ttyfd = pty_slave; close(pty_master); pty_master = -1; } } else if (notty) { if (!start_charshunt(0, 1)) goto fail; } else if (record_file != NULL) { if (!start_charshunt(ttyfd, ttyfd)) goto fail; } /* run connection script */ if ((connector && connector[0]) || initializer) { if (real_ttyfd != -1) { /* XXX do this if doing_callback == CALLBACK_DIALIN? */ if (!default_device && modem) { setdtr(real_ttyfd, 0); /* in case modem is off hook */ sleep(1); setdtr(real_ttyfd, 1); } } if (initializer && initializer[0]) { if (device_script(initializer, ttyfd, ttyfd, 0) < 0) { error("Initializer script failed"); status = EXIT_INIT_FAILED; goto fail; } if (kill_link) goto disconnect; info("Serial port initialized."); } if (connector && connector[0]) { if (device_script(connector, ttyfd, ttyfd, 0) < 0) { error("Connect script failed"); status = EXIT_CONNECT_FAILED; goto fail; } if (kill_link) goto disconnect; info("Serial connection established."); } /* set line speed, flow control, etc.; clear CLOCAL if modem option */ if (real_ttyfd != -1) set_up_tty(real_ttyfd, 0); if (doing_callback == CALLBACK_DIALIN) connector = NULL; } /* reopen tty if necessary to wait for carrier */ if (connector == NULL && modem && devnam[0] != 0) { for (;;) { if ((i = open(devnam, O_RDWR)) >= 0) break; if (errno != EINTR) { error("Failed to reopen %s: %m", devnam); status = EXIT_OPEN_FAILED; } if (!persist || errno != EINTR || hungup || kill_link) goto fail; } close(i); } slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); script_setenv("SPEED", numbuf); /* run welcome script, if any */ if (welcomer && welcomer[0]) { if (device_script(welcomer, ttyfd, ttyfd, 0) < 0) warn("Welcome script failed"); } /* set up the serial device as a ppp interface */ fd_ppp = establish_ppp(ttyfd); if (fd_ppp < 0) { status = EXIT_FATAL_ERROR; goto disconnect; } if (!demand) { info("Using interface ppp%d", ifunit); slprintf(ifname, sizeof(ifname), "ppp%d", ifunit); script_setenv("IFNAME", ifname); create_pidfile(); /* write pid to file */ } /* * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ notice("Connect: %s <--> %s", ifname, ppp_devnam); gettimeofday(&start_time, NULL); link_stats_valid = 0; script_unsetenv("CONNECT_TIME"); script_unsetenv("BYTES_SENT"); script_unsetenv("BYTES_RCVD"); lcp_lowerup(0); /* * If we are initiating this connection, wait for a short * time for something from the peer. This can avoid bouncing * our packets off his tty before he has it set up. */ add_fd(fd_ppp); if (connect_delay != 0 && (connector != NULL || ptycommand != NULL)) { struct timeval t; t.tv_sec = connect_delay / 1000; t.tv_usec = connect_delay % 1000; wait_input(&t); } lcp_open(0); /* Start protocol */ open_ccp_flag = 0; status = EXIT_NEGOTIATION_FAILED; new_phase(PHASE_ESTABLISH); while (phase != PHASE_DEAD) { if (sigsetjmp(sigjmp, 1) == 0) { sigprocmask(SIG_BLOCK, &mask, NULL); if (kill_link || open_ccp_flag || got_sigchld) { sigprocmask(SIG_UNBLOCK, &mask, NULL); } else { waiting = 1; sigprocmask(SIG_UNBLOCK, &mask, NULL); wait_input(timeleft(&timo)); } } waiting = 0; calltimeout(); get_input(); if (kill_link) { lcp_close(0, "User request"); kill_link = 0; } if (open_ccp_flag) { if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) { ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); } open_ccp_flag = 0; } if (got_sigchld) reap_kids(0); /* Don't leave dead kids lying around */ } /* * Print connect time and statistics. */ if (link_stats_valid) { int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ info("Connect time %d.%d minutes.", t/10, t%10); info("Sent %d bytes, received %d bytes.", link_stats.bytes_out, link_stats.bytes_in); } /* * Delete pid file before disestablishing ppp. Otherwise it * can happen that another pppd gets the same unit and then * we delete its pid file. */ if (!demand) { if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) warn("unable to delete pid file %s: %m", pidfilename); pidfilename[0] = 0; } /* * If we may want to bring the link up again, transfer * the ppp unit back to the loopback. Set the * real serial device back to its normal mode of operation. */ remove_fd(fd_ppp); clean_check(); if (demand) restore_loop(); disestablish_ppp(ttyfd); fd_ppp = -1; if (!hungup) lcp_lowerdown(0); /* * Run disconnector script, if requested. * XXX we may not be able to do this if the line has hung up! */ disconnect: if (disconnect_script && !hungup) { new_phase(PHASE_DISCONNECT); if (real_ttyfd >= 0) set_up_tty(real_ttyfd, 1); if (device_script(disconnect_script, ttyfd, ttyfd, 0) < 0) { warn("disconnect script failed"); } else { info("Serial link disconnected."); } } fail: if (pty_master >= 0) close(pty_master); if (pty_slave >= 0) close(pty_slave); if (real_ttyfd >= 0) close_tty(); if (locked) { unlock(); locked = 0; } if (!demand) { if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) warn("unable to delete pid file %s: %m", pidfilename); pidfilename[0] = 0; } if (!persist || (maxfail > 0 && unsuccess >= maxfail)) break; kill_link = 0; if (demand) demand_discard(); t = need_holdoff? holdoff: 0; if (holdoff_hook) t = (*holdoff_hook)(); if (t > 0) { new_phase(PHASE_HOLDOFF); TIMEOUT(holdoff_end, NULL, t); do { if (sigsetjmp(sigjmp, 1) == 0) { sigprocmask(SIG_BLOCK, &mask, NULL); if (kill_link || got_sigchld) { sigprocmask(SIG_UNBLOCK, &mask, NULL); } else { waiting = 1; sigprocmask(SIG_UNBLOCK, &mask, NULL); wait_input(timeleft(&timo)); } } waiting = 0; calltimeout(); if (kill_link) { kill_link = 0; new_phase(PHASE_DORMANT); /* allow signal to end holdoff */ } if (got_sigchld) reap_kids(0); } while (phase == PHASE_HOLDOFF); if (!persist) break; } } /* Wait for scripts to finish */ /* XXX should have a timeout here */ while (n_children > 0) { if (debug) { struct subprocess *chp; dbglog("Waiting for %d child processes...", n_children); for (chp = children; chp != NULL; chp = chp->next) dbglog(" script %s, pid %d", chp->prog, chp->pid); } if (reap_kids(1) < 0) break; } die(status); return 0;}/* * detach - detach us from the controlling terminal. */voiddetach(){ int pid; if (detached) return; if ((pid = fork()) < 0) { error("Couldn't detach (fork failed: %m)"); die(1); /* or just return? */ } if (pid != 0) { /* parent */ if (locked) relock(pid); exit(0); /* parent dies */ } setsid(); chdir("/"); close(0); close(1); close(2); detached = 1; log_to_fd = -1; /* update pid files if they have been written already */ if (pidfilename[0]) create_pidfile(); if (linkpidfile[0]) create_linkpidfile();}/* * reopen_log - (re)open our connection to syslog. */voidreopen_log(){#ifdef ULTRIX openlog("pppd", LOG_PID);#else openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); setlogmask(LOG_UPTO(LOG_INFO));#endif}/* * Create a file containing our process ID. */static voidcreate_pidfile(){ FILE *pidfile; char numbuf[16]; slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid", _PATH_VARRUN, ifname); if ((pidfile = fopen(pidfilename, "w")) != NULL) { fprintf(pidfile, "%d\n", getpid()); (void) fclose(pidfile); } else { error("Failed to create pid file %s: %m", pidfilename); pidfilename[0] = 0; } slprintf(numbuf, sizeof(numbuf), "%d", getpid()); script_setenv("PPPD_PID", numbuf); if (linkpidfile[0]) create_linkpidfile();}static voidcreate_linkpidfile(){ FILE *pidfile; if (linkname[0] == 0) return; slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid", _PATH_VARRUN, linkname); if ((pidfile = fopen(linkpidfile, "w")) != NULL) { fprintf(pidfile, "%d\n", getpid()); if (pidfilename[0]) fprintf(pidfile, "%s\n", ifname); (void) fclose(pidfile); } else { error("Failed to create pid file %s: %m", linkpidfile); linkpidfile[0] = 0; } script_setenv("LINKNAME", linkname);}/* * holdoff_end - called via a timeout when the holdoff period ends. */static voidholdoff_end(arg) void *arg;{ new_phase(PHASE_DORMANT);}/* List of protocol names, to make our messages a little more informative. */struct protocol_list { u_short proto; const char *name;} protocol_list[] = { { 0x21, "IP" }, { 0x23, "OSI Network Layer" }, { 0x25, "Xerox NS IDP" }, { 0x27, "DECnet Phase IV" }, { 0x29, "Appletalk" }, { 0x2b, "Novell IPX" }, { 0x2d, "VJ compressed TCP/IP" }, { 0x2f, "VJ uncompressed TCP/IP" }, { 0x31, "Bridging PDU" }, { 0x33, "Stream Protocol ST-II" }, { 0x35, "Banyan Vines" }, { 0x39, "AppleTalk EDDP" }, { 0x3b, "AppleTalk SmartBuffered" }, { 0x3d, "Multi-Link" }, { 0x3f, "NETBIOS Framing" }, { 0x41, "Cisco Systems" }, { 0x43, "Ascom Timeplex" }, { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, { 0x47, "DCA Remote Lan" }, { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, { 0x4b, "SNA over 802.2" }, { 0x4d, "SNA" }, { 0x4f, "IP6 Header Compression" }, { 0x6f, "Stampede Bridging" }, { 0xfb, "single-link compression" }, { 0xfd, "1st choice compression" }, { 0x0201, "802.1d Hello Packets" }, { 0x0203, "IBM Source Routing BPDU" }, { 0x0205, "DEC LANBridge100 Spanning Tree" }, { 0x0231, "Luxcom" }, { 0x0233, "Sigma Network Systems" }, { 0x8021, "Internet Protocol Control Protocol" }, { 0x8023, "OSI Network Layer Control Protocol" }, { 0x8025, "Xerox NS IDP Control Protocol" }, { 0x8027, "DECnet Phase IV Control Protocol" }, { 0x8029, "Appletalk Control Protocol" }, { 0x802b, "Novell IPX Control Protocol" }, { 0x8031, "Bridging NCP" }, { 0x8033, "Stream Protocol Control Protocol" }, { 0x8035, "Banyan Vines Control Protocol" }, { 0x803d, "Multi-Link Control Protocol" }, { 0x803f, "NETBIOS Framing Control Protocol" }, { 0x8041, "Cisco Systems Control Protocol" },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -