ncp.c revision 81897
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 81897 2001-08-18 19:07:13Z 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 <arpa/inet.h>
3481634Sbrian#include <sys/socket.h>
3581634Sbrian#include <net/if.h>
3681634Sbrian#include <net/route.h>
3781634Sbrian#include <netdb.h>
3881634Sbrian#include <sys/un.h>
3981634Sbrian
4081634Sbrian#include <errno.h>
4181634Sbrian#include <fcntl.h>
4281634Sbrian#include <resolv.h>
4381634Sbrian#include <stdlib.h>
4481634Sbrian#include <string.h>
4581634Sbrian#include <sys/stat.h>
4681634Sbrian#include <termios.h>
4781634Sbrian#include <unistd.h>
4881634Sbrian
4981634Sbrian#include "layer.h"
5081634Sbrian#include "ua.h"
5181634Sbrian#include "defs.h"
5281634Sbrian#include "command.h"
5381634Sbrian#include "mbuf.h"
5481634Sbrian#include "log.h"
5581634Sbrian#include "timer.h"
5681634Sbrian#include "fsm.h"
5781634Sbrian#include "proto.h"
5881634Sbrian#include "iplist.h"
5981634Sbrian#include "throughput.h"
6081634Sbrian#include "slcompress.h"
6181634Sbrian#include "lqr.h"
6281634Sbrian#include "hdlc.h"
6381634Sbrian#include "lcp.h"
6481634Sbrian#include "ncpaddr.h"
6581634Sbrian#include "ip.h"
6681634Sbrian#include "ipcp.h"
6781634Sbrian#include "filter.h"
6881634Sbrian#include "descriptor.h"
6981634Sbrian#include "vjcomp.h"
7081634Sbrian#include "async.h"
7181634Sbrian#include "ccp.h"
7281634Sbrian#include "link.h"
7381634Sbrian#include "physical.h"
7481634Sbrian#include "mp.h"
7581634Sbrian#ifndef NORADIUS
7681634Sbrian#include "radius.h"
7781634Sbrian#endif
7881634Sbrian#include "ipv6cp.h"
7981634Sbrian#include "ncp.h"
8081634Sbrian#include "bundle.h"
8181634Sbrian#include "id.h"
8281634Sbrian#include "arp.h"
8381634Sbrian#include "systems.h"
8481634Sbrian#include "prompt.h"
8581634Sbrian#include "route.h"
8681634Sbrian#include "iface.h"
8781634Sbrian#include "chat.h"
8881634Sbrian#include "auth.h"
8981634Sbrian#include "chap.h"
9081634Sbrian#include "pap.h"
9181634Sbrian#include "cbcp.h"
9281634Sbrian#include "datalink.h"
9381634Sbrian
9481634Sbrian
9581634Sbrianstatic u_short default_urgent_tcp_ports[] = {
9681634Sbrian  21,	/* ftp */
9781634Sbrian  22,	/* ssh */
9881634Sbrian  23,	/* telnet */
9981634Sbrian  513,	/* login */
10081634Sbrian  514,	/* shell */
10181634Sbrian  543,	/* klogin */
10281634Sbrian  544	/* kshell */
10381634Sbrian};
10481634Sbrian
10581634Sbrianstatic u_short default_urgent_udp_ports[] = { };
10681634Sbrian
10781634Sbrian#define NDEFTCPPORTS \
10881634Sbrian  (sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
10981634Sbrian#define NDEFUDPPORTS \
11081634Sbrian  (sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0])
11181634Sbrian
11281634Sbrianvoid
11381634Sbrianncp_Init(struct ncp *ncp, struct bundle *bundle)
11481634Sbrian{
11581634Sbrian  ncp->afq = AF_INET;
11681634Sbrian  ncp->route = NULL;
11781634Sbrian
11881634Sbrian  ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
11981634Sbrian  ncp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
12081634Sbrian  memcpy(ncp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
12181634Sbrian         NDEFTCPPORTS * sizeof(u_short));
12281634Sbrian  ncp->cfg.urgent.tos = 1;
12381634Sbrian
12481634Sbrian  ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = NDEFUDPPORTS;
12581634Sbrian  ncp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short));
12681634Sbrian  memcpy(ncp->cfg.urgent.udp.port, default_urgent_udp_ports,
12781634Sbrian         NDEFUDPPORTS * sizeof(u_short));
12881634Sbrian
12981634Sbrian
13081634Sbrian  mp_Init(&ncp->mp, bundle);
13181634Sbrian
13281634Sbrian  /* Send over the first physical link by default */
13381634Sbrian  ipcp_Init(&ncp->ipcp, bundle, &bundle->links->physical->link,
13481634Sbrian            &bundle->fsm);
13581634Sbrian#ifndef NOINET6
13681897Sbrian  ipv6cp_Init(&ncp->ipv6cp, bundle, &bundle->links->physical->link,
13781897Sbrian              &bundle->fsm);
13881634Sbrian#endif
13981634Sbrian}
14081634Sbrian
14181634Sbrianvoid
14281634Sbrianncp_Destroy(struct ncp *ncp)
14381634Sbrian{
14481634Sbrian  ipcp_Destroy(&ncp->ipcp);
14581634Sbrian#ifndef NOINET6
14681897Sbrian  ipv6cp_Destroy(&ncp->ipv6cp);
14781634Sbrian#endif
14881634Sbrian
14981634Sbrian  if (ncp->cfg.urgent.tcp.maxports) {
15081634Sbrian    ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = 0;
15181634Sbrian    free(ncp->cfg.urgent.tcp.port);
15281634Sbrian    ncp->cfg.urgent.tcp.port = NULL;
15381634Sbrian  }
15481634Sbrian  if (ncp->cfg.urgent.udp.maxports) {
15581634Sbrian    ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
15681634Sbrian    free(ncp->cfg.urgent.udp.port);
15781634Sbrian    ncp->cfg.urgent.udp.port = NULL;
15881634Sbrian  }
15981634Sbrian}
16081634Sbrian
16181634Sbrianint
16281634Sbrianncp_fsmStart(struct ncp *ncp, struct bundle *bundle)
16381634Sbrian{
16481634Sbrian  int res = 0;
16581634Sbrian
16681634Sbrian#ifndef NOINET6
16781634Sbrian  if (Enabled(bundle, OPT_IPCP)) {
16881634Sbrian#endif
16981634Sbrian    fsm_Up(&ncp->ipcp.fsm);
17081634Sbrian    fsm_Open(&ncp->ipcp.fsm);
17181634Sbrian    res++;
17281634Sbrian#ifndef NOINET6
17381634Sbrian  }
17481634Sbrian
17581897Sbrian  if (Enabled(bundle, OPT_IPV6CP)) {
17681634Sbrian    fsm_Up(&ncp->ipv6cp.fsm);
17781634Sbrian    fsm_Open(&ncp->ipv6cp.fsm);
17881634Sbrian    res++;
17981634Sbrian  }
18081634Sbrian#endif
18181634Sbrian
18281634Sbrian  return res;
18381634Sbrian}
18481634Sbrian
18581634Sbrianvoid
18681634Sbrianncp_IfaceAddrAdded(struct ncp *ncp, const struct iface_addr *addr)
18781634Sbrian{
18881634Sbrian  switch (ncprange_family(&addr->ifa)) {
18981634Sbrian  case AF_INET:
19081634Sbrian    ipcp_IfaceAddrAdded(&ncp->ipcp, addr);
19181634Sbrian    break;
19281634Sbrian#ifndef NOINET6
19381634Sbrian  case AF_INET6:
19481634Sbrian    ipv6cp_IfaceAddrAdded(&ncp->ipv6cp, addr);
19581634Sbrian    break;
19681634Sbrian#endif
19781634Sbrian  }
19881634Sbrian}
19981634Sbrian
20081634Sbrianvoid
20181634Sbrianncp_IfaceAddrDeleted(struct ncp *ncp, const struct iface_addr *addr)
20281634Sbrian{
20381634Sbrian  if (ncprange_family(&addr->ifa) == AF_INET)
20481634Sbrian    ipcp_IfaceAddrDeleted(&ncp->ipcp, addr);
20581634Sbrian}
20681634Sbrian
20781634Sbrianvoid
20881634Sbrianncp_SetLink(struct ncp *ncp, struct link *l)
20981634Sbrian{
21081634Sbrian  ipcp_SetLink(&ncp->ipcp, l);
21181634Sbrian#ifndef NOINET6
21281897Sbrian  ipv6cp_SetLink(&ncp->ipv6cp, l);
21381634Sbrian#endif
21481634Sbrian}
21581634Sbrian
21681634Sbrian/*
21781634Sbrian * Enqueue a packet of the given address family.  Nothing will make it
21881634Sbrian * down to the physical link level 'till ncp_FillPhysicalQueues() is used.
21981634Sbrian */
22081634Sbrianvoid
22181634Sbrianncp_Enqueue(struct ncp *ncp, int af, int pri, char *ptr, int count)
22281634Sbrian{
22381634Sbrian#ifndef NOINET6
22481634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
22581634Sbrian#endif
22681634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
22781634Sbrian  struct mbuf *bp;
22881634Sbrian
22981634Sbrian  /*
23081634Sbrian   * We allocate an extra 6 bytes, four at the front and two at the end.
23181634Sbrian   * This is an optimisation so that we need to do less work in
23281634Sbrian   * m_prepend() in acf_LayerPush() and proto_LayerPush() and
23381634Sbrian   * appending in hdlc_LayerPush().
23481634Sbrian   */
23581634Sbrian
23681634Sbrian  switch (af) {
23781634Sbrian  case AF_INET:
23881634Sbrian    if (pri < 0 || pri >= IPCP_QUEUES(ipcp)) {
23981634Sbrian      log_Printf(LogERROR, "Can't store in ip queue %d\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(ipcp->Queue + pri, bp);
24881634Sbrian    break;
24981634Sbrian
25081634Sbrian#ifndef NOINET6
25181634Sbrian  case AF_INET6:
25281634Sbrian    if (pri < 0 || pri >= IPV6CP_QUEUES(ipcp)) {
25381634Sbrian      log_Printf(LogERROR, "Can't store in ipv6 queue %d\n", pri);
25481634Sbrian      break;
25581634Sbrian    }
25681634Sbrian
25781634Sbrian    bp = m_get(count + 6, MB_IPOUT);
25881634Sbrian    bp->m_offset += 4;
25981634Sbrian    bp->m_len -= 6;
26081634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
26181634Sbrian    m_enqueue(ipv6cp->Queue + pri, bp);
26281634Sbrian    break;
26381634Sbrian#endif
26481634Sbrian
26581634Sbrian  default:
26681634Sbrian      log_Printf(LogERROR, "Can't enqueue protocol family %d\n", af);
26781634Sbrian  }
26881634Sbrian}
26981634Sbrian
27081634Sbrian/*
27181634Sbrian * How many packets are queued to go out ?
27281634Sbrian */
27381634Sbriansize_t
27481634Sbrianncp_QueueLen(struct ncp *ncp)
27581634Sbrian{
27681634Sbrian  size_t result;
27781634Sbrian
27881634Sbrian  result = ipcp_QueueLen(&ncp->ipcp);
27981634Sbrian#ifndef NOINET6
28081897Sbrian  result += ipv6cp_QueueLen(&ncp->ipv6cp);
28181634Sbrian#endif
28281634Sbrian  result += mp_QueueLen(&ncp->mp);	/* Usually empty */
28381634Sbrian
28481634Sbrian  return result;
28581634Sbrian}
28681634Sbrian
28781634Sbrian/*
28881634Sbrian * Ditch all queued packets.  This is usually done after our choked timer
28981634Sbrian * has fired - which happens because we couldn't send any traffic over
29081634Sbrian * any links for some time.
29181634Sbrian */
29281634Sbrianvoid
29381634Sbrianncp_DeleteQueues(struct ncp *ncp)
29481634Sbrian{
29581634Sbrian#ifndef NOINET6
29681634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
29781634Sbrian#endif
29881634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
29981634Sbrian  struct mp *mp = &ncp->mp;
30081634Sbrian  struct mqueue *q;
30181634Sbrian
30281634Sbrian  for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
30381634Sbrian    while (q->top)
30481634Sbrian      m_freem(m_dequeue(q));
30581634Sbrian
30681634Sbrian#ifndef NOINET6
30781897Sbrian  for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
30881897Sbrian    while (q->top)
30981897Sbrian      m_freem(m_dequeue(q));
31081634Sbrian#endif
31181634Sbrian
31281634Sbrian  link_DeleteQueue(&mp->link);	/* Usually empty anyway */
31381634Sbrian}
31481634Sbrian
31581634Sbrian/*
31681634Sbrian * Arrange that each of our links has at least one packet.  We keep the
31781634Sbrian * number of packets queued at the link level to a minimum so that the
31881634Sbrian * loss of a link in multi-link mode results in the minimum number of
31981634Sbrian * dropped packets.
32081634Sbrian */
32181634Sbriansize_t
32281634Sbrianncp_FillPhysicalQueues(struct ncp *ncp, struct bundle *bundle)
32381634Sbrian{
32481634Sbrian  size_t total;
32581634Sbrian
32681634Sbrian  if (bundle->ncp.mp.active)
32781634Sbrian    total = mp_FillPhysicalQueues(bundle);
32881634Sbrian  else {
32981634Sbrian    struct datalink *dl;
33081634Sbrian    size_t add;
33181634Sbrian
33281634Sbrian    for (total = 0, dl = bundle->links; dl; dl = dl->next)
33381634Sbrian      if (dl->state == DATALINK_OPEN) {
33481634Sbrian        add = link_QueueLen(&dl->physical->link);
33581634Sbrian        if (add == 0 && dl->physical->out == NULL)
33681634Sbrian          add = ncp_PushPacket(ncp, &ncp->afq, &dl->physical->link);
33781634Sbrian        total += add;
33881634Sbrian      }
33981634Sbrian  }
34081634Sbrian
34181634Sbrian  return total + ncp_QueueLen(&bundle->ncp);
34281634Sbrian}
34381634Sbrian
34481634Sbrian/*
34581634Sbrian * Push a packet into the given link.  ``af'' is used as a persistent record
34681634Sbrian * of what is to be pushed next, coming either from mp->out or ncp->afq.
34781634Sbrian */
34881634Sbrianint
34981634Sbrianncp_PushPacket(struct ncp *ncp, int *af, struct link *l)
35081634Sbrian{
35181634Sbrian  struct bundle *bundle = l->lcp.fsm.bundle;
35281634Sbrian  int res;
35381634Sbrian
35481634Sbrian#ifndef NOINET6
35581897Sbrian  if (*af == AF_INET) {
35681634Sbrian    if ((res = ipcp_PushPacket(&bundle->ncp.ipcp, l)))
35781634Sbrian      *af = AF_INET6;
35881634Sbrian    else
35981634Sbrian      res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l);
36081634Sbrian  } else {
36181634Sbrian    if ((res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l)))
36281634Sbrian      *af = AF_INET;
36381634Sbrian    else
36481634Sbrian      res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
36581634Sbrian  }
36681634Sbrian#else
36781634Sbrian  res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
36881634Sbrian#endif
36981634Sbrian
37081634Sbrian  return res;
37181634Sbrian}
37281634Sbrian
37381634Sbrianint
37481634Sbrianncp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
37581634Sbrian{
37681634Sbrian  int f;
37781634Sbrian
37881634Sbrian  for (f = 0; f < range->nports; f++)
37981634Sbrian    if (range->port[f] == src || range->port[f] == dst)
38081634Sbrian      return 1;
38181634Sbrian
38281634Sbrian  return 0;
38381634Sbrian}
38481634Sbrian
38581634Sbrianvoid
38681634Sbrianncp_AddUrgentPort(struct port_range *range, u_short port)
38781634Sbrian{
38881634Sbrian  u_short *newport;
38981634Sbrian  int p;
39081634Sbrian
39181634Sbrian  if (range->nports == range->maxports) {
39281634Sbrian    range->maxports += 10;
39381634Sbrian    newport = (u_short *)realloc(range->port,
39481634Sbrian                                 range->maxports * sizeof(u_short));
39581634Sbrian    if (newport == NULL) {
39681634Sbrian      log_Printf(LogERROR, "ncp_AddUrgentPort: realloc: %s\n",
39781634Sbrian                 strerror(errno));
39881634Sbrian      range->maxports -= 10;
39981634Sbrian      return;
40081634Sbrian    }
40181634Sbrian    range->port = newport;
40281634Sbrian  }
40381634Sbrian
40481634Sbrian  for (p = 0; p < range->nports; p++)
40581634Sbrian    if (range->port[p] == port) {
40681634Sbrian      log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
40781634Sbrian      break;
40881634Sbrian    } else if (range->port[p] > port) {
40981634Sbrian      memmove(range->port + p + 1, range->port + p,
41081634Sbrian              (range->nports - p) * sizeof(u_short));
41181634Sbrian      range->port[p] = port;
41281634Sbrian      range->nports++;
41381634Sbrian      break;
41481634Sbrian    }
41581634Sbrian
41681634Sbrian  if (p == range->nports)
41781634Sbrian    range->port[range->nports++] = port;
41881634Sbrian}
41981634Sbrian
42081634Sbrianvoid
42181634Sbrianncp_RemoveUrgentPort(struct port_range *range, u_short port)
42281634Sbrian{
42381634Sbrian  int p;
42481634Sbrian
42581634Sbrian  for (p = 0; p < range->nports; p++)
42681634Sbrian    if (range->port[p] == port) {
42781634Sbrian      if (p != range->nports - 1)
42881634Sbrian        memmove(range->port + p, range->port + p + 1,
42981634Sbrian                (range->nports - p - 1) * sizeof(u_short));
43081634Sbrian      range->nports--;
43181634Sbrian      return;
43281634Sbrian    }
43381634Sbrian
43481634Sbrian  if (p == range->nports)
43581634Sbrian    log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
43681634Sbrian}
43781634Sbrian
43881634Sbrianvoid
43981634Sbrianncp_ClearUrgentPorts(struct port_range *range)
44081634Sbrian{
44181634Sbrian  range->nports = 0;
44281634Sbrian}
44381634Sbrian
44481634Sbrianint
44581634Sbrianncp_Show(struct cmdargs const *arg)
44681634Sbrian{
44781634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
44881634Sbrian  int p;
44981634Sbrian
45081634Sbrian#ifndef NOINET6
45181897Sbrian  prompt_Printf(arg->prompt, "Next queued AF: %s\n",
45281897Sbrian                ncp->afq == AF_INET6 ? "inet6" : "inet");
45381634Sbrian#endif
45481634Sbrian
45581634Sbrian  if (ncp->route) {
45681634Sbrian    prompt_Printf(arg->prompt, "\n");
45781634Sbrian    route_ShowSticky(arg->prompt, ncp->route, "Sticky routes", 1);
45881634Sbrian  }
45981634Sbrian
46081634Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
46181634Sbrian  prompt_Printf(arg->prompt, "  sendpipe:      ");
46281634Sbrian  if (ncp->cfg.sendpipe > 0)
46381634Sbrian    prompt_Printf(arg->prompt, "%-20ld\n", ncp->cfg.sendpipe);
46481634Sbrian  else
46581634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
46681634Sbrian  prompt_Printf(arg->prompt, "  recvpipe:      ");
46781634Sbrian  if (ncp->cfg.recvpipe > 0)
46881634Sbrian    prompt_Printf(arg->prompt, "%ld\n", ncp->cfg.recvpipe);
46981634Sbrian  else
47081634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
47181634Sbrian
47281634Sbrian  prompt_Printf(arg->prompt, "\n  Urgent ports\n");
47381634Sbrian  prompt_Printf(arg->prompt, "         TCP:    ");
47481634Sbrian  if (ncp->cfg.urgent.tcp.nports == 0)
47581634Sbrian    prompt_Printf(arg->prompt, "none");
47681634Sbrian  else
47781634Sbrian    for (p = 0; p < ncp->cfg.urgent.tcp.nports; p++) {
47881634Sbrian      if (p)
47981634Sbrian        prompt_Printf(arg->prompt, ", ");
48081634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.tcp.port[p]);
48181634Sbrian    }
48281634Sbrian
48381634Sbrian  prompt_Printf(arg->prompt, "\n         UDP:    ");
48481634Sbrian  if (ncp->cfg.urgent.udp.nports == 0)
48581634Sbrian    prompt_Printf(arg->prompt, "none");
48681634Sbrian  else
48781634Sbrian    for (p = 0; p < ncp->cfg.urgent.udp.nports; p++) {
48881634Sbrian      if (p)
48981634Sbrian        prompt_Printf(arg->prompt, ", ");
49081634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.udp.port[p]);
49181634Sbrian    }
49281634Sbrian  prompt_Printf(arg->prompt, "\n         TOS:    %s\n\n",
49381634Sbrian                ncp->cfg.urgent.tos ? "yes" : "no");
49481634Sbrian
49581634Sbrian  return 0;
49681634Sbrian}
49781634Sbrian
49881634Sbrianint
49981634Sbrianncp_LayersOpen(struct ncp *ncp)
50081634Sbrian{
50181634Sbrian  int n;
50281634Sbrian
50381634Sbrian  n = !!(ncp->ipcp.fsm.state == ST_OPENED);
50481634Sbrian#ifndef NOINET6
50581897Sbrian  n += !!(ncp->ipv6cp.fsm.state == ST_OPENED);
50681634Sbrian#endif
50781634Sbrian
50881634Sbrian  return n;
50981634Sbrian}
51081634Sbrian
51181634Sbrianint
51281634Sbrianncp_LayersUnfinished(struct ncp *ncp)
51381634Sbrian{
51481634Sbrian  int n = 0;
51581634Sbrian
51681634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
51781634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
51881634Sbrian    n++;
51981634Sbrian
52081634Sbrian#ifndef NOINET6
52181897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
52281897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
52381897Sbrian    n++;
52481634Sbrian#endif
52581634Sbrian
52681634Sbrian  return n;
52781634Sbrian}
52881634Sbrian
52981634Sbrianvoid
53081634Sbrianncp_Close(struct ncp *ncp)
53181634Sbrian{
53281634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
53381634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
53481634Sbrian    fsm_Close(&ncp->ipcp.fsm);
53581634Sbrian
53681634Sbrian#ifndef NOINET6
53781897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
53881897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
53981897Sbrian    fsm_Close(&ncp->ipv6cp.fsm);
54081634Sbrian#endif
54181634Sbrian}
54281634Sbrian
54381634Sbrianvoid
54481634Sbrianncp2initial(struct ncp *ncp)
54581634Sbrian{
54681634Sbrian  fsm2initial(&ncp->ipcp.fsm);
54781634Sbrian#ifndef NOINET6
54881897Sbrian  fsm2initial(&ncp->ipv6cp.fsm);
54981634Sbrian#endif
55081634Sbrian}
551