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$
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.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
102136377Sbrian  if (ncp->cfg.urgent.tcp.port == NULL) {
103136377Sbrian    log_Printf(LogERROR, "ncp_Init: Out of memory allocating urgent ports\n");
104136377Sbrian    ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = 0;
105136377Sbrian  } else {
106136377Sbrian    ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
107136377Sbrian    memcpy(ncp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
108136377Sbrian	   NDEFTCPPORTS * sizeof(u_short));
109136377Sbrian  }
11081634Sbrian  ncp->cfg.urgent.tos = 1;
11181634Sbrian
112134789Sbrian  ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
113134789Sbrian  ncp->cfg.urgent.udp.port = NULL;
11481634Sbrian
11581634Sbrian  mp_Init(&ncp->mp, bundle);
11681634Sbrian
11781634Sbrian  /* Send over the first physical link by default */
11881634Sbrian  ipcp_Init(&ncp->ipcp, bundle, &bundle->links->physical->link,
11981634Sbrian            &bundle->fsm);
12081634Sbrian#ifndef NOINET6
12181897Sbrian  ipv6cp_Init(&ncp->ipv6cp, bundle, &bundle->links->physical->link,
12281897Sbrian              &bundle->fsm);
12381634Sbrian#endif
12481634Sbrian}
12581634Sbrian
12681634Sbrianvoid
12781634Sbrianncp_Destroy(struct ncp *ncp)
12881634Sbrian{
12981634Sbrian  ipcp_Destroy(&ncp->ipcp);
13081634Sbrian#ifndef NOINET6
13181897Sbrian  ipv6cp_Destroy(&ncp->ipv6cp);
13281634Sbrian#endif
13381634Sbrian
13481634Sbrian  if (ncp->cfg.urgent.tcp.maxports) {
13581634Sbrian    ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = 0;
13681634Sbrian    free(ncp->cfg.urgent.tcp.port);
13781634Sbrian    ncp->cfg.urgent.tcp.port = NULL;
13881634Sbrian  }
13981634Sbrian  if (ncp->cfg.urgent.udp.maxports) {
14081634Sbrian    ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
14181634Sbrian    free(ncp->cfg.urgent.udp.port);
14281634Sbrian    ncp->cfg.urgent.udp.port = NULL;
14381634Sbrian  }
14481634Sbrian}
14581634Sbrian
14681634Sbrianint
147134875Sbrianncp_fsmStart(struct ncp *ncp,
148134875Sbrian#ifdef NOINET6
149134875Sbrian	     struct bundle *bundle __unused
150134875Sbrian#else
151134875Sbrian	     struct bundle *bundle
152134875Sbrian#endif
153134875Sbrian	     )
15481634Sbrian{
15581634Sbrian  int res = 0;
15681634Sbrian
15781634Sbrian#ifndef NOINET6
15881634Sbrian  if (Enabled(bundle, OPT_IPCP)) {
15981634Sbrian#endif
16081634Sbrian    fsm_Up(&ncp->ipcp.fsm);
16181634Sbrian    fsm_Open(&ncp->ipcp.fsm);
16281634Sbrian    res++;
16381634Sbrian#ifndef NOINET6
16481634Sbrian  }
16581634Sbrian
16681897Sbrian  if (Enabled(bundle, OPT_IPV6CP)) {
16781634Sbrian    fsm_Up(&ncp->ipv6cp.fsm);
16881634Sbrian    fsm_Open(&ncp->ipv6cp.fsm);
16981634Sbrian    res++;
17081634Sbrian  }
17181634Sbrian#endif
17281634Sbrian
17381634Sbrian  return res;
17481634Sbrian}
17581634Sbrian
17681634Sbrianvoid
17781634Sbrianncp_IfaceAddrAdded(struct ncp *ncp, const struct iface_addr *addr)
17881634Sbrian{
17981634Sbrian  switch (ncprange_family(&addr->ifa)) {
18081634Sbrian  case AF_INET:
18181634Sbrian    ipcp_IfaceAddrAdded(&ncp->ipcp, addr);
18281634Sbrian    break;
18381634Sbrian#ifndef NOINET6
18481634Sbrian  case AF_INET6:
18581634Sbrian    ipv6cp_IfaceAddrAdded(&ncp->ipv6cp, addr);
18681634Sbrian    break;
18781634Sbrian#endif
18881634Sbrian  }
18981634Sbrian}
19081634Sbrian
19181634Sbrianvoid
19281634Sbrianncp_IfaceAddrDeleted(struct ncp *ncp, const struct iface_addr *addr)
19381634Sbrian{
19481634Sbrian  if (ncprange_family(&addr->ifa) == AF_INET)
19581634Sbrian    ipcp_IfaceAddrDeleted(&ncp->ipcp, addr);
19681634Sbrian}
19781634Sbrian
19881634Sbrianvoid
19981634Sbrianncp_SetLink(struct ncp *ncp, struct link *l)
20081634Sbrian{
20181634Sbrian  ipcp_SetLink(&ncp->ipcp, l);
20281634Sbrian#ifndef NOINET6
20381897Sbrian  ipv6cp_SetLink(&ncp->ipv6cp, l);
20481634Sbrian#endif
20581634Sbrian}
20681634Sbrian
20781634Sbrian/*
20881634Sbrian * Enqueue a packet of the given address family.  Nothing will make it
20981634Sbrian * down to the physical link level 'till ncp_FillPhysicalQueues() is used.
21081634Sbrian */
21181634Sbrianvoid
212134789Sbrianncp_Enqueue(struct ncp *ncp, int af, unsigned pri, char *ptr, int count)
21381634Sbrian{
21481634Sbrian#ifndef NOINET6
21581634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
21681634Sbrian#endif
21781634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
21881634Sbrian  struct mbuf *bp;
21981634Sbrian
22081634Sbrian  /*
22181634Sbrian   * We allocate an extra 6 bytes, four at the front and two at the end.
22281634Sbrian   * This is an optimisation so that we need to do less work in
22381634Sbrian   * m_prepend() in acf_LayerPush() and proto_LayerPush() and
22481634Sbrian   * appending in hdlc_LayerPush().
22581634Sbrian   */
22681634Sbrian
22781634Sbrian  switch (af) {
22881634Sbrian  case AF_INET:
229134789Sbrian    if (pri >= IPCP_QUEUES(ipcp)) {
230134789Sbrian      log_Printf(LogERROR, "Can't store in ip queue %u\n", pri);
23181634Sbrian      break;
23281634Sbrian    }
23381634Sbrian
23481634Sbrian    bp = m_get(count + 6, MB_IPOUT);
23581634Sbrian    bp->m_offset += 4;
23681634Sbrian    bp->m_len -= 6;
23781634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
23881634Sbrian    m_enqueue(ipcp->Queue + pri, bp);
23981634Sbrian    break;
24081634Sbrian
24181634Sbrian#ifndef NOINET6
24281634Sbrian  case AF_INET6:
243134789Sbrian    if (pri >= IPV6CP_QUEUES(ipcp)) {
244134789Sbrian      log_Printf(LogERROR, "Can't store in ipv6 queue %u\n", pri);
24581634Sbrian      break;
24681634Sbrian    }
24781634Sbrian
24881634Sbrian    bp = m_get(count + 6, MB_IPOUT);
24981634Sbrian    bp->m_offset += 4;
25081634Sbrian    bp->m_len -= 6;
25181634Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
25281634Sbrian    m_enqueue(ipv6cp->Queue + pri, bp);
25381634Sbrian    break;
25481634Sbrian#endif
25581634Sbrian
25681634Sbrian  default:
25781634Sbrian      log_Printf(LogERROR, "Can't enqueue protocol family %d\n", af);
25881634Sbrian  }
25981634Sbrian}
26081634Sbrian
26181634Sbrian/*
26281634Sbrian * How many packets are queued to go out ?
26381634Sbrian */
26481634Sbriansize_t
26581634Sbrianncp_QueueLen(struct ncp *ncp)
26681634Sbrian{
26781634Sbrian  size_t result;
26881634Sbrian
26981634Sbrian  result = ipcp_QueueLen(&ncp->ipcp);
27081634Sbrian#ifndef NOINET6
27181897Sbrian  result += ipv6cp_QueueLen(&ncp->ipv6cp);
27281634Sbrian#endif
27381634Sbrian  result += mp_QueueLen(&ncp->mp);	/* Usually empty */
27481634Sbrian
27581634Sbrian  return result;
27681634Sbrian}
27781634Sbrian
27881634Sbrian/*
27981634Sbrian * Ditch all queued packets.  This is usually done after our choked timer
28081634Sbrian * has fired - which happens because we couldn't send any traffic over
28181634Sbrian * any links for some time.
28281634Sbrian */
28381634Sbrianvoid
28481634Sbrianncp_DeleteQueues(struct ncp *ncp)
28581634Sbrian{
28681634Sbrian#ifndef NOINET6
28781634Sbrian  struct ipv6cp *ipv6cp = &ncp->ipv6cp;
28881634Sbrian#endif
28981634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
29081634Sbrian  struct mp *mp = &ncp->mp;
29181634Sbrian  struct mqueue *q;
29281634Sbrian
29381634Sbrian  for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
29481634Sbrian    while (q->top)
29581634Sbrian      m_freem(m_dequeue(q));
29681634Sbrian
29781634Sbrian#ifndef NOINET6
29881897Sbrian  for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
29981897Sbrian    while (q->top)
30081897Sbrian      m_freem(m_dequeue(q));
30181634Sbrian#endif
30281634Sbrian
30381634Sbrian  link_DeleteQueue(&mp->link);	/* Usually empty anyway */
30481634Sbrian}
30581634Sbrian
30681634Sbrian/*
30781634Sbrian * Arrange that each of our links has at least one packet.  We keep the
30881634Sbrian * number of packets queued at the link level to a minimum so that the
30981634Sbrian * loss of a link in multi-link mode results in the minimum number of
31081634Sbrian * dropped packets.
31181634Sbrian */
31281634Sbriansize_t
31381634Sbrianncp_FillPhysicalQueues(struct ncp *ncp, struct bundle *bundle)
31481634Sbrian{
31581634Sbrian  size_t total;
31681634Sbrian
31781634Sbrian  if (bundle->ncp.mp.active)
31881634Sbrian    total = mp_FillPhysicalQueues(bundle);
31981634Sbrian  else {
32081634Sbrian    struct datalink *dl;
32181634Sbrian    size_t add;
32281634Sbrian
32381634Sbrian    for (total = 0, dl = bundle->links; dl; dl = dl->next)
32481634Sbrian      if (dl->state == DATALINK_OPEN) {
32581634Sbrian        add = link_QueueLen(&dl->physical->link);
32681634Sbrian        if (add == 0 && dl->physical->out == NULL)
32781634Sbrian          add = ncp_PushPacket(ncp, &ncp->afq, &dl->physical->link);
32881634Sbrian        total += add;
32981634Sbrian      }
33081634Sbrian  }
33181634Sbrian
33281634Sbrian  return total + ncp_QueueLen(&bundle->ncp);
33381634Sbrian}
33481634Sbrian
33581634Sbrian/*
33681634Sbrian * Push a packet into the given link.  ``af'' is used as a persistent record
33781634Sbrian * of what is to be pushed next, coming either from mp->out or ncp->afq.
33881634Sbrian */
33981634Sbrianint
340134875Sbrianncp_PushPacket(struct ncp *ncp __unused,
341134875Sbrian#ifdef NOINET6
342134875Sbrian	       int *af __unused,
343134875Sbrian#else
344134875Sbrian	       int *af,
345134875Sbrian#endif
346134875Sbrian	       struct link *l)
34781634Sbrian{
34881634Sbrian  struct bundle *bundle = l->lcp.fsm.bundle;
34981634Sbrian  int res;
35081634Sbrian
35181634Sbrian#ifndef NOINET6
35281897Sbrian  if (*af == AF_INET) {
35381634Sbrian    if ((res = ipcp_PushPacket(&bundle->ncp.ipcp, l)))
35481634Sbrian      *af = AF_INET6;
35581634Sbrian    else
35681634Sbrian      res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l);
35781634Sbrian  } else {
35881634Sbrian    if ((res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l)))
35981634Sbrian      *af = AF_INET;
36081634Sbrian    else
36181634Sbrian      res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
36281634Sbrian  }
36381634Sbrian#else
36481634Sbrian  res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
36581634Sbrian#endif
36681634Sbrian
36781634Sbrian  return res;
36881634Sbrian}
36981634Sbrian
37081634Sbrianint
37181634Sbrianncp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
37281634Sbrian{
373134789Sbrian  unsigned f;
37481634Sbrian
37581634Sbrian  for (f = 0; f < range->nports; f++)
37681634Sbrian    if (range->port[f] == src || range->port[f] == dst)
37781634Sbrian      return 1;
37881634Sbrian
37981634Sbrian  return 0;
38081634Sbrian}
38181634Sbrian
38281634Sbrianvoid
38381634Sbrianncp_AddUrgentPort(struct port_range *range, u_short port)
38481634Sbrian{
38581634Sbrian  u_short *newport;
386134789Sbrian  unsigned p;
38781634Sbrian
38881634Sbrian  if (range->nports == range->maxports) {
38981634Sbrian    range->maxports += 10;
39081634Sbrian    newport = (u_short *)realloc(range->port,
39181634Sbrian                                 range->maxports * sizeof(u_short));
39281634Sbrian    if (newport == NULL) {
39381634Sbrian      log_Printf(LogERROR, "ncp_AddUrgentPort: realloc: %s\n",
39481634Sbrian                 strerror(errno));
39581634Sbrian      range->maxports -= 10;
39681634Sbrian      return;
39781634Sbrian    }
39881634Sbrian    range->port = newport;
39981634Sbrian  }
40081634Sbrian
40181634Sbrian  for (p = 0; p < range->nports; p++)
40281634Sbrian    if (range->port[p] == port) {
40381634Sbrian      log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
40481634Sbrian      break;
40581634Sbrian    } else if (range->port[p] > port) {
40681634Sbrian      memmove(range->port + p + 1, range->port + p,
40781634Sbrian              (range->nports - p) * sizeof(u_short));
40881634Sbrian      range->port[p] = port;
40981634Sbrian      range->nports++;
41081634Sbrian      break;
41181634Sbrian    }
41281634Sbrian
41381634Sbrian  if (p == range->nports)
41481634Sbrian    range->port[range->nports++] = port;
41581634Sbrian}
41681634Sbrian
41781634Sbrianvoid
41881634Sbrianncp_RemoveUrgentPort(struct port_range *range, u_short port)
41981634Sbrian{
420134789Sbrian  unsigned p;
42181634Sbrian
42281634Sbrian  for (p = 0; p < range->nports; p++)
42381634Sbrian    if (range->port[p] == port) {
424134789Sbrian      if (p + 1 != range->nports)
42581634Sbrian        memmove(range->port + p, range->port + p + 1,
42681634Sbrian                (range->nports - p - 1) * sizeof(u_short));
42781634Sbrian      range->nports--;
42881634Sbrian      return;
42981634Sbrian    }
43081634Sbrian
43181634Sbrian  if (p == range->nports)
43281634Sbrian    log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
43381634Sbrian}
43481634Sbrian
43581634Sbrianvoid
43681634Sbrianncp_ClearUrgentPorts(struct port_range *range)
43781634Sbrian{
43881634Sbrian  range->nports = 0;
43981634Sbrian}
44081634Sbrian
44181634Sbrianint
44281634Sbrianncp_Show(struct cmdargs const *arg)
44381634Sbrian{
44481634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
445134789Sbrian  unsigned p;
44681634Sbrian
44781634Sbrian#ifndef NOINET6
44881897Sbrian  prompt_Printf(arg->prompt, "Next queued AF: %s\n",
44981897Sbrian                ncp->afq == AF_INET6 ? "inet6" : "inet");
45081634Sbrian#endif
45181634Sbrian
45281634Sbrian  if (ncp->route) {
45381634Sbrian    prompt_Printf(arg->prompt, "\n");
45481634Sbrian    route_ShowSticky(arg->prompt, ncp->route, "Sticky routes", 1);
45581634Sbrian  }
45681634Sbrian
45781634Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
45881634Sbrian  prompt_Printf(arg->prompt, "  sendpipe:      ");
45981634Sbrian  if (ncp->cfg.sendpipe > 0)
46081634Sbrian    prompt_Printf(arg->prompt, "%-20ld\n", ncp->cfg.sendpipe);
46181634Sbrian  else
46281634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
46381634Sbrian  prompt_Printf(arg->prompt, "  recvpipe:      ");
46481634Sbrian  if (ncp->cfg.recvpipe > 0)
46581634Sbrian    prompt_Printf(arg->prompt, "%ld\n", ncp->cfg.recvpipe);
46681634Sbrian  else
46781634Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
46881634Sbrian
46981634Sbrian  prompt_Printf(arg->prompt, "\n  Urgent ports\n");
47081634Sbrian  prompt_Printf(arg->prompt, "         TCP:    ");
47181634Sbrian  if (ncp->cfg.urgent.tcp.nports == 0)
47281634Sbrian    prompt_Printf(arg->prompt, "none");
47381634Sbrian  else
47481634Sbrian    for (p = 0; p < ncp->cfg.urgent.tcp.nports; p++) {
47581634Sbrian      if (p)
47681634Sbrian        prompt_Printf(arg->prompt, ", ");
47781634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.tcp.port[p]);
47881634Sbrian    }
47981634Sbrian
48081634Sbrian  prompt_Printf(arg->prompt, "\n         UDP:    ");
48181634Sbrian  if (ncp->cfg.urgent.udp.nports == 0)
48281634Sbrian    prompt_Printf(arg->prompt, "none");
48381634Sbrian  else
48481634Sbrian    for (p = 0; p < ncp->cfg.urgent.udp.nports; p++) {
48581634Sbrian      if (p)
48681634Sbrian        prompt_Printf(arg->prompt, ", ");
48781634Sbrian      prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.udp.port[p]);
48881634Sbrian    }
48981634Sbrian  prompt_Printf(arg->prompt, "\n         TOS:    %s\n\n",
49081634Sbrian                ncp->cfg.urgent.tos ? "yes" : "no");
49181634Sbrian
49281634Sbrian  return 0;
49381634Sbrian}
49481634Sbrian
49581634Sbrianint
49681634Sbrianncp_LayersOpen(struct ncp *ncp)
49781634Sbrian{
49881634Sbrian  int n;
49981634Sbrian
50081634Sbrian  n = !!(ncp->ipcp.fsm.state == ST_OPENED);
50181634Sbrian#ifndef NOINET6
50281897Sbrian  n += !!(ncp->ipv6cp.fsm.state == ST_OPENED);
50381634Sbrian#endif
50481634Sbrian
50581634Sbrian  return n;
50681634Sbrian}
50781634Sbrian
50881634Sbrianint
50981634Sbrianncp_LayersUnfinished(struct ncp *ncp)
51081634Sbrian{
51181634Sbrian  int n = 0;
51281634Sbrian
51381634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
51481634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
51581634Sbrian    n++;
51681634Sbrian
51781634Sbrian#ifndef NOINET6
51881897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
51981897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
52081897Sbrian    n++;
52181634Sbrian#endif
52281634Sbrian
52381634Sbrian  return n;
52481634Sbrian}
52581634Sbrian
52681634Sbrianvoid
52781634Sbrianncp_Close(struct ncp *ncp)
52881634Sbrian{
52981634Sbrian  if (ncp->ipcp.fsm.state > ST_CLOSED ||
53081634Sbrian      ncp->ipcp.fsm.state == ST_STARTING)
53181634Sbrian    fsm_Close(&ncp->ipcp.fsm);
53281634Sbrian
53381634Sbrian#ifndef NOINET6
53481897Sbrian  if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
53581897Sbrian      ncp->ipv6cp.fsm.state == ST_STARTING)
53681897Sbrian    fsm_Close(&ncp->ipv6cp.fsm);
53781634Sbrian#endif
53881634Sbrian}
53981634Sbrian
54081634Sbrianvoid
54181634Sbrianncp2initial(struct ncp *ncp)
54281634Sbrian{
54381634Sbrian  fsm2initial(&ncp->ipcp.fsm);
54481634Sbrian#ifndef NOINET6
54581897Sbrian  fsm2initial(&ncp->ipv6cp.fsm);
54681634Sbrian#endif
54781634Sbrian}
548