ncp.c revision 134875
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 134875 2004-09-06 23:54:54Z 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
9281634Sbrian#define NDEFTCPPORTS \
9381634Sbrian  (sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
9481634Sbrian
9581634Sbrianvoid
9681634Sbrianncp_Init(struct ncp *ncp, struct bundle *bundle)
9781634Sbrian{
9881634Sbrian  ncp->afq = AF_INET;
9981634Sbrian  ncp->route = NULL;
10081634Sbrian
10181634Sbrian  ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
10281634Sbrian  ncp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
10381634Sbrian  memcpy(ncp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
10481634Sbrian         NDEFTCPPORTS * sizeof(u_short));
10581634Sbrian  ncp->cfg.urgent.tos = 1;
10681634Sbrian
107134789Sbrian  ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
108134789Sbrian  ncp->cfg.urgent.udp.port = NULL;
10981634Sbrian
11081634Sbrian  mp_Init(&ncp->mp, bundle);
11181634Sbrian
11281634Sbrian  /* Send over the first physical link by default */
11381634Sbrian  ipcp_Init(&ncp->ipcp, bundle, &bundle->links->physical->link,
11481634Sbrian            &bundle->fsm);
11581634Sbrian#ifndef NOINET6
11681897Sbrian  ipv6cp_Init(&ncp->ipv6cp, bundle, &bundle->links->physical->link,
11781897Sbrian              &bundle->fsm);
11881634Sbrian#endif
11981634Sbrian}
12081634Sbrian
12181634Sbrianvoid
12281634Sbrianncp_Destroy(struct ncp *ncp)
12381634Sbrian{
12481634Sbrian  ipcp_Destroy(&ncp->ipcp);
12581634Sbrian#ifndef NOINET6
12681897Sbrian  ipv6cp_Destroy(&ncp->ipv6cp);
12781634Sbrian#endif
12881634Sbrian
12981634Sbrian  if (ncp->cfg.urgent.tcp.maxports) {
13081634Sbrian    ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = 0;
13181634Sbrian    free(ncp->cfg.urgent.tcp.port);
13281634Sbrian    ncp->cfg.urgent.tcp.port = NULL;
13381634Sbrian  }
13481634Sbrian  if (ncp->cfg.urgent.udp.maxports) {
13581634Sbrian    ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
13681634Sbrian    free(ncp->cfg.urgent.udp.port);
13781634Sbrian    ncp->cfg.urgent.udp.port = NULL;
13881634Sbrian  }
13981634Sbrian}
14081634Sbrian
14181634Sbrianint
142134875Sbrianncp_fsmStart(struct ncp *ncp,
143134875Sbrian#ifdef NOINET6
144134875Sbrian	     struct bundle *bundle __unused
145134875Sbrian#else
146134875Sbrian	     struct bundle *bundle
147134875Sbrian#endif
148134875Sbrian	     )
14981634Sbrian{
15081634Sbrian  int res = 0;
15181634Sbrian
15281634Sbrian#ifndef NOINET6
15381634Sbrian  if (Enabled(bundle, OPT_IPCP)) {
15481634Sbrian#endif
15581634Sbrian    fsm_Up(&ncp->ipcp.fsm);
15681634Sbrian    fsm_Open(&ncp->ipcp.fsm);
15781634Sbrian    res++;
15881634Sbrian#ifndef NOINET6
15981634Sbrian  }
16081634Sbrian
16181897Sbrian  if (Enabled(bundle, OPT_IPV6CP)) {
16281634Sbrian    fsm_Up(&ncp->ipv6cp.fsm);
16381634Sbrian    fsm_Open(&ncp->ipv6cp.fsm);
16481634Sbrian    res++;
16581634Sbrian  }
16681634Sbrian#endif
16781634Sbrian
16881634Sbrian  return res;
16981634Sbrian}
17081634Sbrian
17181634Sbrianvoid
17281634Sbrianncp_IfaceAddrAdded(struct ncp *ncp, const struct iface_addr *addr)
17381634Sbrian{
17481634Sbrian  switch (ncprange_family(&addr->ifa)) {
17581634Sbrian  case AF_INET:
17681634Sbrian    ipcp_IfaceAddrAdded(&ncp->ipcp, addr);
17781634Sbrian    break;
17881634Sbrian#ifndef NOINET6
17981634Sbrian  case AF_INET6:
18081634Sbrian    ipv6cp_IfaceAddrAdded(&ncp->ipv6cp, addr);
18181634Sbrian    break;
18281634Sbrian#endif
18381634Sbrian  }
18481634Sbrian}
18581634Sbrian
18681634Sbrianvoid
18781634Sbrianncp_IfaceAddrDeleted(struct ncp *ncp, const struct iface_addr *addr)
18881634Sbrian{
18981634Sbrian  if (ncprange_family(&addr->ifa) == AF_INET)
19081634Sbrian    ipcp_IfaceAddrDeleted(&ncp->ipcp, addr);
19181634Sbrian}
19281634Sbrian
19381634Sbrianvoid
19481634Sbrianncp_SetLink(struct ncp *ncp, struct link *l)
19581634Sbrian{
19681634Sbrian  ipcp_SetLink(&ncp->ipcp, l);
19781634Sbrian#ifndef NOINET6
19881897Sbrian  ipv6cp_SetLink(&ncp->ipv6cp, l);
19981634Sbrian#endif
20081634Sbrian}
20181634Sbrian
20281634Sbrian/*
20381634Sbrian * Enqueue a packet of the given address family.  Nothing will make it
20481634Sbrian * down to the physical link level 'till ncp_FillPhysicalQueues() is used.
20581634Sbrian */
20681634Sbrianvoid
207134789Sbrianncp_Enqueue(struct ncp *ncp, int af, unsigned pri, char *ptr, int count)
20881634Sbrian{
20981634Sbrian#ifndef NOINET6
21081634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
21181634Sbrian#endif
21281634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
21381634Sbrian  struct mbuf *bp;
21481634Sbrian
21581634Sbrian  /*
21681634Sbrian   * We allocate an extra 6 bytes, four at the front and two at the end.
21781634Sbrian   * This is an optimisation so that we need to do less work in
21881634Sbrian   * m_prepend() in acf_LayerPush() and proto_LayerPush() and
21981634Sbrian   * appending in hdlc_LayerPush().
22081634Sbrian   */
22181634Sbrian
22281634Sbrian  switch (af) {
22381634Sbrian  case AF_INET:
224134789Sbrian    if (pri >= IPCP_QUEUES(ipcp)) {
225134789Sbrian      log_Printf(LogERROR, "Can't store in ip queue %u\n", pri);
22681634Sbrian      break;
22781634Sbrian    }
22881634Sbrian
22981634Sbrian    bp = m_get(count + 6, MB_IPOUT);
23081634Sbrian    bp->m_offset += 4;
23181634Sbrian    bp->m_len -= 6;
23281634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
23381634Sbrian    m_enqueue(ipcp->Queue + pri, bp);
23481634Sbrian    break;
23581634Sbrian
23681634Sbrian#ifndef NOINET6
23781634Sbrian  case AF_INET6:
238134789Sbrian    if (pri >= IPV6CP_QUEUES(ipcp)) {
239134789Sbrian      log_Printf(LogERROR, "Can't store in ipv6 queue %u\n", pri);
24081634Sbrian      break;
24181634Sbrian    }
24281634Sbrian
24381634Sbrian    bp = m_get(count + 6, MB_IPOUT);
24481634Sbrian    bp->m_offset += 4;
24581634Sbrian    bp->m_len -= 6;
24681634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
24781634Sbrian    m_enqueue(ipv6cp->Queue + pri, bp);
24881634Sbrian    break;
24981634Sbrian#endif
25081634Sbrian
25181634Sbrian  default:
25281634Sbrian      log_Printf(LogERROR, "Can't enqueue protocol family %d\n", af);
25381634Sbrian  }
25481634Sbrian}
25581634Sbrian
25681634Sbrian/*
25781634Sbrian * How many packets are queued to go out ?
25881634Sbrian */
25981634Sbriansize_t
26081634Sbrianncp_QueueLen(struct ncp *ncp)
26181634Sbrian{
26281634Sbrian  size_t result;
26381634Sbrian
26481634Sbrian  result = ipcp_QueueLen(&ncp->ipcp);
26581634Sbrian#ifndef NOINET6
26681897Sbrian  result += ipv6cp_QueueLen(&ncp->ipv6cp);
26781634Sbrian#endif
26881634Sbrian  result += mp_QueueLen(&ncp->mp);	/* Usually empty */
26981634Sbrian
27081634Sbrian  return result;
27181634Sbrian}
27281634Sbrian
27381634Sbrian/*
27481634Sbrian * Ditch all queued packets.  This is usually done after our choked timer
27581634Sbrian * has fired - which happens because we couldn't send any traffic over
27681634Sbrian * any links for some time.
27781634Sbrian */
27881634Sbrianvoid
27981634Sbrianncp_DeleteQueues(struct ncp *ncp)
28081634Sbrian{
28181634Sbrian#ifndef NOINET6
28281634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
28381634Sbrian#endif
28481634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
28581634Sbrian  struct mp *mp = &ncp->mp;
28681634Sbrian  struct mqueue *q;
28781634Sbrian
28881634Sbrian  for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
28981634Sbrian    while (q->top)
29081634Sbrian      m_freem(m_dequeue(q));
29181634Sbrian
29281634Sbrian#ifndef NOINET6
29381897Sbrian  for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
29481897Sbrian    while (q->top)
29581897Sbrian      m_freem(m_dequeue(q));
29681634Sbrian#endif
29781634Sbrian
29881634Sbrian  link_DeleteQueue(&mp->link);	/* Usually empty anyway */
29981634Sbrian}
30081634Sbrian
30181634Sbrian/*
30281634Sbrian * Arrange that each of our links has at least one packet.  We keep the
30381634Sbrian * number of packets queued at the link level to a minimum so that the
30481634Sbrian * loss of a link in multi-link mode results in the minimum number of
30581634Sbrian * dropped packets.
30681634Sbrian */
30781634Sbriansize_t
30881634Sbrianncp_FillPhysicalQueues(struct ncp *ncp, struct bundle *bundle)
30981634Sbrian{
31081634Sbrian  size_t total;
31181634Sbrian
31281634Sbrian  if (bundle->ncp.mp.active)
31381634Sbrian    total = mp_FillPhysicalQueues(bundle);
31481634Sbrian  else {
31581634Sbrian    struct datalink *dl;
31681634Sbrian    size_t add;
31781634Sbrian
31881634Sbrian    for (total = 0, dl = bundle->links; dl; dl = dl->next)
31981634Sbrian      if (dl->state == DATALINK_OPEN) {
32081634Sbrian        add = link_QueueLen(&dl->physical->link);
32181634Sbrian        if (add == 0 && dl->physical->out == NULL)
32281634Sbrian          add = ncp_PushPacket(ncp, &ncp->afq, &dl->physical->link);
32381634Sbrian        total += add;
32481634Sbrian      }
32581634Sbrian  }
32681634Sbrian
32781634Sbrian  return total + ncp_QueueLen(&bundle->ncp);
32881634Sbrian}
32981634Sbrian
33081634Sbrian/*
33181634Sbrian * Push a packet into the given link.  ``af'' is used as a persistent record
33281634Sbrian * of what is to be pushed next, coming either from mp->out or ncp->afq.
33381634Sbrian */
33481634Sbrianint
335134875Sbrianncp_PushPacket(struct ncp *ncp __unused,
336134875Sbrian#ifdef NOINET6
337134875Sbrian	       int *af __unused,
338134875Sbrian#else
339134875Sbrian	       int *af,
340134875Sbrian#endif
341134875Sbrian	       struct link *l)
34281634Sbrian{
34381634Sbrian  struct bundle *bundle = l->lcp.fsm.bundle;
34481634Sbrian  int res;
34581634Sbrian
34681634Sbrian#ifndef NOINET6
34781897Sbrian  if (*af == AF_INET) {
34881634Sbrian    if ((res = ipcp_PushPacket(&bundle->ncp.ipcp, l)))
34981634Sbrian      *af = AF_INET6;
35081634Sbrian    else
35181634Sbrian      res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l);
35281634Sbrian  } else {
35381634Sbrian    if ((res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l)))
35481634Sbrian      *af = AF_INET;
35581634Sbrian    else
35681634Sbrian      res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
35781634Sbrian  }
35881634Sbrian#else
35981634Sbrian  res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
36081634Sbrian#endif
36181634Sbrian
36281634Sbrian  return res;
36381634Sbrian}
36481634Sbrian
36581634Sbrianint
36681634Sbrianncp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
36781634Sbrian{
368134789Sbrian  unsigned f;
36981634Sbrian
37081634Sbrian  for (f = 0; f < range->nports; f++)
37181634Sbrian    if (range->port[f] == src || range->port[f] == dst)
37281634Sbrian      return 1;
37381634Sbrian
37481634Sbrian  return 0;
37581634Sbrian}
37681634Sbrian
37781634Sbrianvoid
37881634Sbrianncp_AddUrgentPort(struct port_range *range, u_short port)
37981634Sbrian{
38081634Sbrian  u_short *newport;
381134789Sbrian  unsigned p;
38281634Sbrian
38381634Sbrian  if (range->nports == range->maxports) {
38481634Sbrian    range->maxports += 10;
38581634Sbrian    newport = (u_short *)realloc(range->port,
38681634Sbrian                                 range->maxports * sizeof(u_short));
38781634Sbrian    if (newport == NULL) {
38881634Sbrian      log_Printf(LogERROR, "ncp_AddUrgentPort: realloc: %s\n",
38981634Sbrian                 strerror(errno));
39081634Sbrian      range->maxports -= 10;
39181634Sbrian      return;
39281634Sbrian    }
39381634Sbrian    range->port = newport;
39481634Sbrian  }
39581634Sbrian
39681634Sbrian  for (p = 0; p < range->nports; p++)
39781634Sbrian    if (range->port[p] == port) {
39881634Sbrian      log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
39981634Sbrian      break;
40081634Sbrian    } else if (range->port[p] > port) {
40181634Sbrian      memmove(range->port + p + 1, range->port + p,
40281634Sbrian              (range->nports - p) * sizeof(u_short));
40381634Sbrian      range->port[p] = port;
40481634Sbrian      range->nports++;
40581634Sbrian      break;
40681634Sbrian    }
40781634Sbrian
40881634Sbrian  if (p == range->nports)
40981634Sbrian    range->port[range->nports++] = port;
41081634Sbrian}
41181634Sbrian
41281634Sbrianvoid
41381634Sbrianncp_RemoveUrgentPort(struct port_range *range, u_short port)
41481634Sbrian{
415134789Sbrian  unsigned p;
41681634Sbrian
41781634Sbrian  for (p = 0; p < range->nports; p++)
41881634Sbrian    if (range->port[p] == port) {
419134789Sbrian      if (p + 1 != range->nports)
42081634Sbrian        memmove(range->port + p, range->port + p + 1,
42181634Sbrian                (range->nports - p - 1) * sizeof(u_short));
42281634Sbrian      range->nports--;
42381634Sbrian      return;
42481634Sbrian    }
42581634Sbrian
42681634Sbrian  if (p == range->nports)
42781634Sbrian    log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
42881634Sbrian}
42981634Sbrian
43081634Sbrianvoid
43181634Sbrianncp_ClearUrgentPorts(struct port_range *range)
43281634Sbrian{
43381634Sbrian  range->nports = 0;
43481634Sbrian}
43581634Sbrian
43681634Sbrianint
43781634Sbrianncp_Show(struct cmdargs const *arg)
43881634Sbrian{
43981634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
440134789Sbrian  unsigned p;
44181634Sbrian
44281634Sbrian#ifndef NOINET6
44381897Sbrian  prompt_Printf(arg->prompt, "Next queued AF: %s\n",
44481897Sbrian                ncp->afq == AF_INET6 ? "inet6" : "inet");
44581634Sbrian#endif
44681634Sbrian
44781634Sbrian  if (ncp->route) {
44881634Sbrian    prompt_Printf(arg->prompt, "\n");
44981634Sbrian    route_ShowSticky(arg->prompt, ncp->route, "Sticky routes", 1);
45081634Sbrian  }
45181634Sbrian
45281634Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
45381634Sbrian  prompt_Printf(arg->prompt, "  sendpipe:      ");
45481634Sbrian  if (ncp->cfg.sendpipe > 0)
45581634Sbrian    prompt_Printf(arg->prompt, "%-20ld\n", ncp->cfg.sendpipe);
45681634Sbrian  else
45781634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
45881634Sbrian  prompt_Printf(arg->prompt, "  recvpipe:      ");
45981634Sbrian  if (ncp->cfg.recvpipe > 0)
46081634Sbrian    prompt_Printf(arg->prompt, "%ld\n", ncp->cfg.recvpipe);
46181634Sbrian  else
46281634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
46381634Sbrian
46481634Sbrian  prompt_Printf(arg->prompt, "\n  Urgent ports\n");
46581634Sbrian  prompt_Printf(arg->prompt, "         TCP:    ");
46681634Sbrian  if (ncp->cfg.urgent.tcp.nports == 0)
46781634Sbrian    prompt_Printf(arg->prompt, "none");
46881634Sbrian  else
46981634Sbrian    for (p = 0; p < ncp->cfg.urgent.tcp.nports; p++) {
47081634Sbrian      if (p)
47181634Sbrian        prompt_Printf(arg->prompt, ", ");
47281634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.tcp.port[p]);
47381634Sbrian    }
47481634Sbrian
47581634Sbrian  prompt_Printf(arg->prompt, "\n         UDP:    ");
47681634Sbrian  if (ncp->cfg.urgent.udp.nports == 0)
47781634Sbrian    prompt_Printf(arg->prompt, "none");
47881634Sbrian  else
47981634Sbrian    for (p = 0; p < ncp->cfg.urgent.udp.nports; p++) {
48081634Sbrian      if (p)
48181634Sbrian        prompt_Printf(arg->prompt, ", ");
48281634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.udp.port[p]);
48381634Sbrian    }
48481634Sbrian  prompt_Printf(arg->prompt, "\n         TOS:    %s\n\n",
48581634Sbrian                ncp->cfg.urgent.tos ? "yes" : "no");
48681634Sbrian
48781634Sbrian  return 0;
48881634Sbrian}
48981634Sbrian
49081634Sbrianint
49181634Sbrianncp_LayersOpen(struct ncp *ncp)
49281634Sbrian{
49381634Sbrian  int n;
49481634Sbrian
49581634Sbrian  n = !!(ncp->ipcp.fsm.state == ST_OPENED);
49681634Sbrian#ifndef NOINET6
49781897Sbrian  n += !!(ncp->ipv6cp.fsm.state == ST_OPENED);
49881634Sbrian#endif
49981634Sbrian
50081634Sbrian  return n;
50181634Sbrian}
50281634Sbrian
50381634Sbrianint
50481634Sbrianncp_LayersUnfinished(struct ncp *ncp)
50581634Sbrian{
50681634Sbrian  int n = 0;
50781634Sbrian
50881634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
50981634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
51081634Sbrian    n++;
51181634Sbrian
51281634Sbrian#ifndef NOINET6
51381897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
51481897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
51581897Sbrian    n++;
51681634Sbrian#endif
51781634Sbrian
51881634Sbrian  return n;
51981634Sbrian}
52081634Sbrian
52181634Sbrianvoid
52281634Sbrianncp_Close(struct ncp *ncp)
52381634Sbrian{
52481634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
52581634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
52681634Sbrian    fsm_Close(&ncp->ipcp.fsm);
52781634Sbrian
52881634Sbrian#ifndef NOINET6
52981897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
53081897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
53181897Sbrian    fsm_Close(&ncp->ipv6cp.fsm);
53281634Sbrian#endif
53381634Sbrian}
53481634Sbrian
53581634Sbrianvoid
53681634Sbrianncp2initial(struct ncp *ncp)
53781634Sbrian{
53881634Sbrian  fsm2initial(&ncp->ipcp.fsm);
53981634Sbrian#ifndef NOINET6
54081897Sbrian  fsm2initial(&ncp->ipv6cp.fsm);
54181634Sbrian#endif
54281634Sbrian}
543