ncp.c revision 102500
181634Sbrian/*-
281634Sbrian * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
381634Sbrian * All rights reserved.
481634Sbrian *
581634Sbrian * Redistribution and use in source and binary forms, with or without
681634Sbrian * modification, are permitted provided that the following conditions
781634Sbrian * are met:
881634Sbrian * 1. Redistributions of source code must retain the above copyright
981634Sbrian *    notice, this list of conditions and the following disclaimer.
1081634Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1181634Sbrian *    notice, this list of conditions and the following disclaimer in the
1281634Sbrian *    documentation and/or other materials provided with the distribution.
1381634Sbrian *
1481634Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1581634Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1681634Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1781634Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1881634Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1981634Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2081634Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2181634Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2281634Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2381634Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2481634Sbrian * SUCH DAMAGE.
2581634Sbrian *
2681634Sbrian * $FreeBSD: head/usr.sbin/ppp/ncp.c 102500 2002-08-27 20:11:58Z brian $
2781634Sbrian */
2881634Sbrian
2981634Sbrian#include <sys/param.h>
3081634Sbrian#include <netinet/in_systm.h>
3181634Sbrian#include <netinet/in.h>
3281634Sbrian#include <netinet/ip.h>
3381634Sbrian#include <sys/socket.h>
3481634Sbrian#include <net/route.h>
3581634Sbrian#include <sys/un.h>
3681634Sbrian
3781634Sbrian#include <errno.h>
3881634Sbrian#include <resolv.h>
39102500Sbrian#include <stdarg.h>
4081634Sbrian#include <stdlib.h>
4181634Sbrian#include <string.h>
4281634Sbrian#include <termios.h>
4381634Sbrian
4481634Sbrian#include "layer.h"
4581634Sbrian#include "defs.h"
4681634Sbrian#include "command.h"
4781634Sbrian#include "mbuf.h"
4881634Sbrian#include "log.h"
4981634Sbrian#include "timer.h"
5081634Sbrian#include "fsm.h"
5181634Sbrian#include "iplist.h"
5281634Sbrian#include "throughput.h"
5381634Sbrian#include "slcompress.h"
5481634Sbrian#include "lqr.h"
5581634Sbrian#include "hdlc.h"
5681634Sbrian#include "lcp.h"
5781634Sbrian#include "ncpaddr.h"
5881634Sbrian#include "ipcp.h"
5981634Sbrian#include "filter.h"
6081634Sbrian#include "descriptor.h"
6181634Sbrian#include "async.h"
6281634Sbrian#include "ccp.h"
6381634Sbrian#include "link.h"
6481634Sbrian#include "physical.h"
6581634Sbrian#include "mp.h"
6681634Sbrian#ifndef NORADIUS
6781634Sbrian#include "radius.h"
6881634Sbrian#endif
6981634Sbrian#include "ipv6cp.h"
7081634Sbrian#include "ncp.h"
7181634Sbrian#include "bundle.h"
7281634Sbrian#include "prompt.h"
7381634Sbrian#include "route.h"
7481634Sbrian#include "iface.h"
7581634Sbrian#include "chat.h"
7681634Sbrian#include "auth.h"
7781634Sbrian#include "chap.h"
7881634Sbrian#include "cbcp.h"
7981634Sbrian#include "datalink.h"
8081634Sbrian
8181634Sbrian
8281634Sbrianstatic u_short default_urgent_tcp_ports[] = {
8381634Sbrian  21,	/* ftp */
8481634Sbrian  22,	/* ssh */
8581634Sbrian  23,	/* telnet */
8681634Sbrian  513,	/* login */
8781634Sbrian  514,	/* shell */
8881634Sbrian  543,	/* klogin */
8981634Sbrian  544	/* kshell */
9081634Sbrian};
9181634Sbrian
9281634Sbrianstatic u_short default_urgent_udp_ports[] = { };
9381634Sbrian
9481634Sbrian#define NDEFTCPPORTS \
9581634Sbrian  (sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
9681634Sbrian#define NDEFUDPPORTS \
9781634Sbrian  (sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0])
9881634Sbrian
9981634Sbrianvoid
10081634Sbrianncp_Init(struct ncp *ncp, struct bundle *bundle)
10181634Sbrian{
10281634Sbrian  ncp->afq = AF_INET;
10381634Sbrian  ncp->route = NULL;
10481634Sbrian
10581634Sbrian  ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
10681634Sbrian  ncp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
10781634Sbrian  memcpy(ncp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
10881634Sbrian         NDEFTCPPORTS * sizeof(u_short));
10981634Sbrian  ncp->cfg.urgent.tos = 1;
11081634Sbrian
11181634Sbrian  ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = NDEFUDPPORTS;
11281634Sbrian  ncp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short));
11381634Sbrian  memcpy(ncp->cfg.urgent.udp.port, default_urgent_udp_ports,
11481634Sbrian         NDEFUDPPORTS * sizeof(u_short));
11581634Sbrian
11681634Sbrian
11781634Sbrian  mp_Init(&ncp->mp, bundle);
11881634Sbrian
11981634Sbrian  /* Send over the first physical link by default */
12081634Sbrian  ipcp_Init(&ncp->ipcp, bundle, &bundle->links->physical->link,
12181634Sbrian            &bundle->fsm);
12281634Sbrian#ifndef NOINET6
12381897Sbrian  ipv6cp_Init(&ncp->ipv6cp, bundle, &bundle->links->physical->link,
12481897Sbrian              &bundle->fsm);
12581634Sbrian#endif
12681634Sbrian}
12781634Sbrian
12881634Sbrianvoid
12981634Sbrianncp_Destroy(struct ncp *ncp)
13081634Sbrian{
13181634Sbrian  ipcp_Destroy(&ncp->ipcp);
13281634Sbrian#ifndef NOINET6
13381897Sbrian  ipv6cp_Destroy(&ncp->ipv6cp);
13481634Sbrian#endif
13581634Sbrian
13681634Sbrian  if (ncp->cfg.urgent.tcp.maxports) {
13781634Sbrian    ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = 0;
13881634Sbrian    free(ncp->cfg.urgent.tcp.port);
13981634Sbrian    ncp->cfg.urgent.tcp.port = NULL;
14081634Sbrian  }
14181634Sbrian  if (ncp->cfg.urgent.udp.maxports) {
14281634Sbrian    ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
14381634Sbrian    free(ncp->cfg.urgent.udp.port);
14481634Sbrian    ncp->cfg.urgent.udp.port = NULL;
14581634Sbrian  }
14681634Sbrian}
14781634Sbrian
14881634Sbrianint
14981634Sbrianncp_fsmStart(struct ncp *ncp, struct bundle *bundle)
15081634Sbrian{
15181634Sbrian  int res = 0;
15281634Sbrian
15381634Sbrian#ifndef NOINET6
15481634Sbrian  if (Enabled(bundle, OPT_IPCP)) {
15581634Sbrian#endif
15681634Sbrian    fsm_Up(&ncp->ipcp.fsm);
15781634Sbrian    fsm_Open(&ncp->ipcp.fsm);
15881634Sbrian    res++;
15981634Sbrian#ifndef NOINET6
16081634Sbrian  }
16181634Sbrian
16281897Sbrian  if (Enabled(bundle, OPT_IPV6CP)) {
16381634Sbrian    fsm_Up(&ncp->ipv6cp.fsm);
16481634Sbrian    fsm_Open(&ncp->ipv6cp.fsm);
16581634Sbrian    res++;
16681634Sbrian  }
16781634Sbrian#endif
16881634Sbrian
16981634Sbrian  return res;
17081634Sbrian}
17181634Sbrian
17281634Sbrianvoid
17381634Sbrianncp_IfaceAddrAdded(struct ncp *ncp, const struct iface_addr *addr)
17481634Sbrian{
17581634Sbrian  switch (ncprange_family(&addr->ifa)) {
17681634Sbrian  case AF_INET:
17781634Sbrian    ipcp_IfaceAddrAdded(&ncp->ipcp, addr);
17881634Sbrian    break;
17981634Sbrian#ifndef NOINET6
18081634Sbrian  case AF_INET6:
18181634Sbrian    ipv6cp_IfaceAddrAdded(&ncp->ipv6cp, addr);
18281634Sbrian    break;
18381634Sbrian#endif
18481634Sbrian  }
18581634Sbrian}
18681634Sbrian
18781634Sbrianvoid
18881634Sbrianncp_IfaceAddrDeleted(struct ncp *ncp, const struct iface_addr *addr)
18981634Sbrian{
19081634Sbrian  if (ncprange_family(&addr->ifa) == AF_INET)
19181634Sbrian    ipcp_IfaceAddrDeleted(&ncp->ipcp, addr);
19281634Sbrian}
19381634Sbrian
19481634Sbrianvoid
19581634Sbrianncp_SetLink(struct ncp *ncp, struct link *l)
19681634Sbrian{
19781634Sbrian  ipcp_SetLink(&ncp->ipcp, l);
19881634Sbrian#ifndef NOINET6
19981897Sbrian  ipv6cp_SetLink(&ncp->ipv6cp, l);
20081634Sbrian#endif
20181634Sbrian}
20281634Sbrian
20381634Sbrian/*
20481634Sbrian * Enqueue a packet of the given address family.  Nothing will make it
20581634Sbrian * down to the physical link level 'till ncp_FillPhysicalQueues() is used.
20681634Sbrian */
20781634Sbrianvoid
20881634Sbrianncp_Enqueue(struct ncp *ncp, int af, int pri, char *ptr, int count)
20981634Sbrian{
21081634Sbrian#ifndef NOINET6
21181634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
21281634Sbrian#endif
21381634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
21481634Sbrian  struct mbuf *bp;
21581634Sbrian
21681634Sbrian  /*
21781634Sbrian   * We allocate an extra 6 bytes, four at the front and two at the end.
21881634Sbrian   * This is an optimisation so that we need to do less work in
21981634Sbrian   * m_prepend() in acf_LayerPush() and proto_LayerPush() and
22081634Sbrian   * appending in hdlc_LayerPush().
22181634Sbrian   */
22281634Sbrian
22381634Sbrian  switch (af) {
22481634Sbrian  case AF_INET:
22581634Sbrian    if (pri < 0 || pri >= IPCP_QUEUES(ipcp)) {
22681634Sbrian      log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
22781634Sbrian      break;
22881634Sbrian    }
22981634Sbrian
23081634Sbrian    bp = m_get(count + 6, MB_IPOUT);
23181634Sbrian    bp->m_offset += 4;
23281634Sbrian    bp->m_len -= 6;
23381634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
23481634Sbrian    m_enqueue(ipcp->Queue + pri, bp);
23581634Sbrian    break;
23681634Sbrian
23781634Sbrian#ifndef NOINET6
23881634Sbrian  case AF_INET6:
23981634Sbrian    if (pri < 0 || pri >= IPV6CP_QUEUES(ipcp)) {
24081634Sbrian      log_Printf(LogERROR, "Can't store in ipv6 queue %d\n", pri);
24181634Sbrian      break;
24281634Sbrian    }
24381634Sbrian
24481634Sbrian    bp = m_get(count + 6, MB_IPOUT);
24581634Sbrian    bp->m_offset += 4;
24681634Sbrian    bp->m_len -= 6;
24781634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
24881634Sbrian    m_enqueue(ipv6cp->Queue + pri, bp);
24981634Sbrian    break;
25081634Sbrian#endif
25181634Sbrian
25281634Sbrian  default:
25381634Sbrian      log_Printf(LogERROR, "Can't enqueue protocol family %d\n", af);
25481634Sbrian  }
25581634Sbrian}
25681634Sbrian
25781634Sbrian/*
25881634Sbrian * How many packets are queued to go out ?
25981634Sbrian */
26081634Sbriansize_t
26181634Sbrianncp_QueueLen(struct ncp *ncp)
26281634Sbrian{
26381634Sbrian  size_t result;
26481634Sbrian
26581634Sbrian  result = ipcp_QueueLen(&ncp->ipcp);
26681634Sbrian#ifndef NOINET6
26781897Sbrian  result += ipv6cp_QueueLen(&ncp->ipv6cp);
26881634Sbrian#endif
26981634Sbrian  result += mp_QueueLen(&ncp->mp);	/* Usually empty */
27081634Sbrian
27181634Sbrian  return result;
27281634Sbrian}
27381634Sbrian
27481634Sbrian/*
27581634Sbrian * Ditch all queued packets.  This is usually done after our choked timer
27681634Sbrian * has fired - which happens because we couldn't send any traffic over
27781634Sbrian * any links for some time.
27881634Sbrian */
27981634Sbrianvoid
28081634Sbrianncp_DeleteQueues(struct ncp *ncp)
28181634Sbrian{
28281634Sbrian#ifndef NOINET6
28381634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
28481634Sbrian#endif
28581634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
28681634Sbrian  struct mp *mp = &ncp->mp;
28781634Sbrian  struct mqueue *q;
28881634Sbrian
28981634Sbrian  for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
29081634Sbrian    while (q->top)
29181634Sbrian      m_freem(m_dequeue(q));
29281634Sbrian
29381634Sbrian#ifndef NOINET6
29481897Sbrian  for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
29581897Sbrian    while (q->top)
29681897Sbrian      m_freem(m_dequeue(q));
29781634Sbrian#endif
29881634Sbrian
29981634Sbrian  link_DeleteQueue(&mp->link);	/* Usually empty anyway */
30081634Sbrian}
30181634Sbrian
30281634Sbrian/*
30381634Sbrian * Arrange that each of our links has at least one packet.  We keep the
30481634Sbrian * number of packets queued at the link level to a minimum so that the
30581634Sbrian * loss of a link in multi-link mode results in the minimum number of
30681634Sbrian * dropped packets.
30781634Sbrian */
30881634Sbriansize_t
30981634Sbrianncp_FillPhysicalQueues(struct ncp *ncp, struct bundle *bundle)
31081634Sbrian{
31181634Sbrian  size_t total;
31281634Sbrian
31381634Sbrian  if (bundle->ncp.mp.active)
31481634Sbrian    total = mp_FillPhysicalQueues(bundle);
31581634Sbrian  else {
31681634Sbrian    struct datalink *dl;
31781634Sbrian    size_t add;
31881634Sbrian
31981634Sbrian    for (total = 0, dl = bundle->links; dl; dl = dl->next)
32081634Sbrian      if (dl->state == DATALINK_OPEN) {
32181634Sbrian        add = link_QueueLen(&dl->physical->link);
32281634Sbrian        if (add == 0 && dl->physical->out == NULL)
32381634Sbrian          add = ncp_PushPacket(ncp, &ncp->afq, &dl->physical->link);
32481634Sbrian        total += add;
32581634Sbrian      }
32681634Sbrian  }
32781634Sbrian
32881634Sbrian  return total + ncp_QueueLen(&bundle->ncp);
32981634Sbrian}
33081634Sbrian
33181634Sbrian/*
33281634Sbrian * Push a packet into the given link.  ``af'' is used as a persistent record
33381634Sbrian * of what is to be pushed next, coming either from mp->out or ncp->afq.
33481634Sbrian */
33581634Sbrianint
33681634Sbrianncp_PushPacket(struct ncp *ncp, int *af, struct link *l)
33781634Sbrian{
33881634Sbrian  struct bundle *bundle = l->lcp.fsm.bundle;
33981634Sbrian  int res;
34081634Sbrian
34181634Sbrian#ifndef NOINET6
34281897Sbrian  if (*af == AF_INET) {
34381634Sbrian    if ((res = ipcp_PushPacket(&bundle->ncp.ipcp, l)))
34481634Sbrian      *af = AF_INET6;
34581634Sbrian    else
34681634Sbrian      res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l);
34781634Sbrian  } else {
34881634Sbrian    if ((res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l)))
34981634Sbrian      *af = AF_INET;
35081634Sbrian    else
35181634Sbrian      res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
35281634Sbrian  }
35381634Sbrian#else
35481634Sbrian  res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
35581634Sbrian#endif
35681634Sbrian
35781634Sbrian  return res;
35881634Sbrian}
35981634Sbrian
36081634Sbrianint
36181634Sbrianncp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
36281634Sbrian{
36381634Sbrian  int f;
36481634Sbrian
36581634Sbrian  for (f = 0; f < range->nports; f++)
36681634Sbrian    if (range->port[f] == src || range->port[f] == dst)
36781634Sbrian      return 1;
36881634Sbrian
36981634Sbrian  return 0;
37081634Sbrian}
37181634Sbrian
37281634Sbrianvoid
37381634Sbrianncp_AddUrgentPort(struct port_range *range, u_short port)
37481634Sbrian{
37581634Sbrian  u_short *newport;
37681634Sbrian  int p;
37781634Sbrian
37881634Sbrian  if (range->nports == range->maxports) {
37981634Sbrian    range->maxports += 10;
38081634Sbrian    newport = (u_short *)realloc(range->port,
38181634Sbrian                                 range->maxports * sizeof(u_short));
38281634Sbrian    if (newport == NULL) {
38381634Sbrian      log_Printf(LogERROR, "ncp_AddUrgentPort: realloc: %s\n",
38481634Sbrian                 strerror(errno));
38581634Sbrian      range->maxports -= 10;
38681634Sbrian      return;
38781634Sbrian    }
38881634Sbrian    range->port = newport;
38981634Sbrian  }
39081634Sbrian
39181634Sbrian  for (p = 0; p < range->nports; p++)
39281634Sbrian    if (range->port[p] == port) {
39381634Sbrian      log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
39481634Sbrian      break;
39581634Sbrian    } else if (range->port[p] > port) {
39681634Sbrian      memmove(range->port + p + 1, range->port + p,
39781634Sbrian              (range->nports - p) * sizeof(u_short));
39881634Sbrian      range->port[p] = port;
39981634Sbrian      range->nports++;
40081634Sbrian      break;
40181634Sbrian    }
40281634Sbrian
40381634Sbrian  if (p == range->nports)
40481634Sbrian    range->port[range->nports++] = port;
40581634Sbrian}
40681634Sbrian
40781634Sbrianvoid
40881634Sbrianncp_RemoveUrgentPort(struct port_range *range, u_short port)
40981634Sbrian{
41081634Sbrian  int p;
41181634Sbrian
41281634Sbrian  for (p = 0; p < range->nports; p++)
41381634Sbrian    if (range->port[p] == port) {
41481634Sbrian      if (p != range->nports - 1)
41581634Sbrian        memmove(range->port + p, range->port + p + 1,
41681634Sbrian                (range->nports - p - 1) * sizeof(u_short));
41781634Sbrian      range->nports--;
41881634Sbrian      return;
41981634Sbrian    }
42081634Sbrian
42181634Sbrian  if (p == range->nports)
42281634Sbrian    log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
42381634Sbrian}
42481634Sbrian
42581634Sbrianvoid
42681634Sbrianncp_ClearUrgentPorts(struct port_range *range)
42781634Sbrian{
42881634Sbrian  range->nports = 0;
42981634Sbrian}
43081634Sbrian
43181634Sbrianint
43281634Sbrianncp_Show(struct cmdargs const *arg)
43381634Sbrian{
43481634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
43581634Sbrian  int p;
43681634Sbrian
43781634Sbrian#ifndef NOINET6
43881897Sbrian  prompt_Printf(arg->prompt, "Next queued AF: %s\n",
43981897Sbrian                ncp->afq == AF_INET6 ? "inet6" : "inet");
44081634Sbrian#endif
44181634Sbrian
44281634Sbrian  if (ncp->route) {
44381634Sbrian    prompt_Printf(arg->prompt, "\n");
44481634Sbrian    route_ShowSticky(arg->prompt, ncp->route, "Sticky routes", 1);
44581634Sbrian  }
44681634Sbrian
44781634Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
44881634Sbrian  prompt_Printf(arg->prompt, "  sendpipe:      ");
44981634Sbrian  if (ncp->cfg.sendpipe > 0)
45081634Sbrian    prompt_Printf(arg->prompt, "%-20ld\n", ncp->cfg.sendpipe);
45181634Sbrian  else
45281634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
45381634Sbrian  prompt_Printf(arg->prompt, "  recvpipe:      ");
45481634Sbrian  if (ncp->cfg.recvpipe > 0)
45581634Sbrian    prompt_Printf(arg->prompt, "%ld\n", ncp->cfg.recvpipe);
45681634Sbrian  else
45781634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
45881634Sbrian
45981634Sbrian  prompt_Printf(arg->prompt, "\n  Urgent ports\n");
46081634Sbrian  prompt_Printf(arg->prompt, "         TCP:    ");
46181634Sbrian  if (ncp->cfg.urgent.tcp.nports == 0)
46281634Sbrian    prompt_Printf(arg->prompt, "none");
46381634Sbrian  else
46481634Sbrian    for (p = 0; p < ncp->cfg.urgent.tcp.nports; p++) {
46581634Sbrian      if (p)
46681634Sbrian        prompt_Printf(arg->prompt, ", ");
46781634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.tcp.port[p]);
46881634Sbrian    }
46981634Sbrian
47081634Sbrian  prompt_Printf(arg->prompt, "\n         UDP:    ");
47181634Sbrian  if (ncp->cfg.urgent.udp.nports == 0)
47281634Sbrian    prompt_Printf(arg->prompt, "none");
47381634Sbrian  else
47481634Sbrian    for (p = 0; p < ncp->cfg.urgent.udp.nports; p++) {
47581634Sbrian      if (p)
47681634Sbrian        prompt_Printf(arg->prompt, ", ");
47781634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.udp.port[p]);
47881634Sbrian    }
47981634Sbrian  prompt_Printf(arg->prompt, "\n         TOS:    %s\n\n",
48081634Sbrian                ncp->cfg.urgent.tos ? "yes" : "no");
48181634Sbrian
48281634Sbrian  return 0;
48381634Sbrian}
48481634Sbrian
48581634Sbrianint
48681634Sbrianncp_LayersOpen(struct ncp *ncp)
48781634Sbrian{
48881634Sbrian  int n;
48981634Sbrian
49081634Sbrian  n = !!(ncp->ipcp.fsm.state == ST_OPENED);
49181634Sbrian#ifndef NOINET6
49281897Sbrian  n += !!(ncp->ipv6cp.fsm.state == ST_OPENED);
49381634Sbrian#endif
49481634Sbrian
49581634Sbrian  return n;
49681634Sbrian}
49781634Sbrian
49881634Sbrianint
49981634Sbrianncp_LayersUnfinished(struct ncp *ncp)
50081634Sbrian{
50181634Sbrian  int n = 0;
50281634Sbrian
50381634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
50481634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
50581634Sbrian    n++;
50681634Sbrian
50781634Sbrian#ifndef NOINET6
50881897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
50981897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
51081897Sbrian    n++;
51181634Sbrian#endif
51281634Sbrian
51381634Sbrian  return n;
51481634Sbrian}
51581634Sbrian
51681634Sbrianvoid
51781634Sbrianncp_Close(struct ncp *ncp)
51881634Sbrian{
51981634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
52081634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
52181634Sbrian    fsm_Close(&ncp->ipcp.fsm);
52281634Sbrian
52381634Sbrian#ifndef NOINET6
52481897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
52581897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
52681897Sbrian    fsm_Close(&ncp->ipv6cp.fsm);
52781634Sbrian#endif
52881634Sbrian}
52981634Sbrian
53081634Sbrianvoid
53181634Sbrianncp2initial(struct ncp *ncp)
53281634Sbrian{
53381634Sbrian  fsm2initial(&ncp->ipcp.fsm);
53481634Sbrian#ifndef NOINET6
53581897Sbrian  fsm2initial(&ncp->ipv6cp.fsm);
53681634Sbrian#endif
53781634Sbrian}
538