165862Sbrian/*-
265862Sbrian * Copyright (c) 2000 Jakob Stoklund Olesen <stoklund@taxidriver.dk>
365862Sbrian * All rights reserved.
465862Sbrian *
565862Sbrian * Redistribution and use in source and binary forms, with or without
665862Sbrian * modification, are permitted provided that the following conditions
765862Sbrian * are met:
865862Sbrian * 1. Redistributions of source code must retain the above copyright
965862Sbrian *    notice, this list of conditions and the following disclaimer.
1065862Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1165862Sbrian *    notice, this list of conditions and the following disclaimer in the
1265862Sbrian *    documentation and/or other materials provided with the distribution.
1365862Sbrian *
1465862Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1565862Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1665862Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1765862Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1865862Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1965862Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2065862Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2165862Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2265862Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2365862Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2465862Sbrian * SUCH DAMAGE.
2565862Sbrian *
2665862Sbrian * $FreeBSD$
2765862Sbrian */
2865862Sbrian
2965862Sbrian#include <sys/types.h>
3065862Sbrian#include <sys/socket.h>
3165862Sbrian#include <net/if.h>
3265862Sbrian#include <netnatm/natm.h>
3365862Sbrian
3465862Sbrian#include <errno.h>
3565862Sbrian#include <stdio.h>
3665862Sbrian#include <stdlib.h>
3765862Sbrian#include <string.h>
3865862Sbrian#include <sysexits.h>
3965862Sbrian#include <sys/uio.h>
4065862Sbrian#include <termios.h>
4165862Sbrian#include <unistd.h>
4265862Sbrian
4365862Sbrian#include "layer.h"
4465862Sbrian#include "defs.h"
4565862Sbrian#include "mbuf.h"
4665862Sbrian#include "log.h"
4765862Sbrian#include "timer.h"
4865862Sbrian#include "lqr.h"
4965862Sbrian#include "hdlc.h"
5065862Sbrian#include "throughput.h"
5165862Sbrian#include "fsm.h"
5265862Sbrian#include "lcp.h"
5365862Sbrian#include "ccp.h"
5465862Sbrian#include "link.h"
5565862Sbrian#include "async.h"
5665862Sbrian#include "descriptor.h"
5765862Sbrian#include "physical.h"
5865862Sbrian#include "main.h"
5965862Sbrian#include "atm.h"
6065862Sbrian
6165862Sbrian/* String identifying PPPoA */
6265863Sbrian#define PPPOA		"PPPoA"
6365863Sbrian#define PPPOA_LEN	(sizeof(PPPOA) - 1)
6465862Sbrian
6565862Sbrianstruct atmdevice {
6665862Sbrian  struct device dev;		/* What struct physical knows about */
6765862Sbrian};
6865862Sbrian
6965862Sbrian#define device2atm(d) ((d)->type == ATM_DEVICE ? (struct atmdevice *)d : NULL)
7065862Sbrian
71134789Sbrianunsigned
7265862Sbrianatm_DeviceSize(void)
7365862Sbrian{
7465862Sbrian  return sizeof(struct atmdevice);
7565862Sbrian}
7665862Sbrian
7765862Sbrianstatic ssize_t
7865862Sbrianatm_Sendto(struct physical *p, const void *v, size_t n)
7965862Sbrian{
8065862Sbrian  ssize_t ret = write(p->fd, v, n);
8165863Sbrian  if (ret < 0) {
8271781Sbrian    log_Printf(LogDEBUG, "atm_Sendto(%ld): %s\n", (long)n, strerror(errno));
8365862Sbrian    return ret;
8465862Sbrian  }
8565862Sbrian  return ret;
8665862Sbrian}
8765862Sbrian
8865862Sbrianstatic ssize_t
8965862Sbrianatm_Recvfrom(struct physical *p, void *v, size_t n)
9065862Sbrian{
9165862Sbrian    ssize_t ret = read(p->fd, (char*)v, n);
9265863Sbrian    if (ret < 0) {
9371781Sbrian      log_Printf(LogDEBUG, "atm_Recvfrom(%ld): %s\n", (long)n, strerror(errno));
9465862Sbrian      return ret;
9565862Sbrian    }
9665862Sbrian    return ret;
9765862Sbrian}
9865862Sbrian
9965862Sbrianstatic void
10065862Sbrianatm_Free(struct physical *p)
10165862Sbrian{
10265862Sbrian  struct atmdevice *dev = device2atm(p->handler);
10365862Sbrian
10465862Sbrian  free(dev);
10565862Sbrian}
10665862Sbrian
10765862Sbrianstatic void
10865862Sbrianatm_device2iov(struct device *d, struct iovec *iov, int *niov,
109134789Sbrian               int maxiov __unused, int *auxfd __unused, int *nauxfd __unused)
11065862Sbrian{
11165862Sbrian  int sz = physical_MaxDeviceSize();
11265862Sbrian
11365862Sbrian  iov[*niov].iov_base = realloc(d, sz);
11465862Sbrian  if (iov[*niov].iov_base == NULL) {
11565862Sbrian    log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
11665862Sbrian    AbortProgram(EX_OSERR);
11765862Sbrian  }
11865862Sbrian  iov[*niov].iov_len = sz;
11965862Sbrian  (*niov)++;
12065862Sbrian}
12165862Sbrian
12265862Sbrianstatic const struct device baseatmdevice = {
12365862Sbrian  ATM_DEVICE,
12465862Sbrian  "atm",
12578410Sbrian  0,
12665862Sbrian  { CD_NOTREQUIRED, 0 },
12765862Sbrian  NULL,
12865862Sbrian  NULL,
12965862Sbrian  NULL,
13065862Sbrian  NULL,
13165862Sbrian  NULL,
13265862Sbrian  NULL,
13393418Sbrian  NULL,
13465862Sbrian  atm_Free,
13565862Sbrian  atm_Recvfrom,
13665862Sbrian  atm_Sendto,
13765862Sbrian  atm_device2iov,
13865862Sbrian  NULL,
13996582Sbrian  NULL,
14065862Sbrian  NULL
14165862Sbrian};
14265862Sbrian
14365862Sbrianstruct device *
14465862Sbrianatm_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
145134789Sbrian               int maxiov __unused, int *auxfd __unused, int *nauxfd __unused)
14665862Sbrian{
14765862Sbrian  if (type == ATM_DEVICE) {
14865862Sbrian    struct atmdevice *dev = (struct atmdevice *)iov[(*niov)++].iov_base;
14965862Sbrian
15065862Sbrian    dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
15165862Sbrian    if (dev == NULL) {
15265862Sbrian      log_Printf(LogALERT, "Failed to allocate memory: %d\n",
15365862Sbrian                 (int)(sizeof *dev));
15465862Sbrian      AbortProgram(EX_OSERR);
15565862Sbrian    }
15665862Sbrian
15765862Sbrian    /* Refresh function pointers etc */
15865862Sbrian    memcpy(&dev->dev, &baseatmdevice, sizeof dev->dev);
15965862Sbrian
16065862Sbrian    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF);
16165862Sbrian    return &dev->dev;
16265862Sbrian  }
16365862Sbrian
16465862Sbrian  return NULL;
16565862Sbrian}
16665862Sbrian
16765862Sbrianstatic struct atmdevice *
16865863Sbrianatm_CreateDevice(struct physical *p, const char *iface, unsigned vpi,
16965863Sbrian                 unsigned vci)
17065862Sbrian{
17165862Sbrian  struct atmdevice *dev;
17265862Sbrian  struct sockaddr_natm sock;
17398243Sbrian
17465863Sbrian  if ((dev = calloc(1, sizeof *dev)) == NULL) {
17565862Sbrian    log_Printf(LogWARN, "%s: Cannot allocate an atm device: %s\n",
17665862Sbrian               p->link.name, strerror(errno));
17765862Sbrian    return NULL;
17865862Sbrian  }
17965862Sbrian
18065862Sbrian  sock.snatm_len = sizeof sock;
18165862Sbrian  sock.snatm_family = AF_NATM;
18265863Sbrian  strncpy(sock.snatm_if, iface, IFNAMSIZ);
18365862Sbrian  sock.snatm_vpi = vpi;
18465862Sbrian  sock.snatm_vci = vci;
18565862Sbrian
18665862Sbrian  log_Printf(LogPHASE, "%s: Connecting to %s:%u.%u\n", p->link.name,
18765862Sbrian             iface, vpi, vci);
18865862Sbrian
18989422Sbrian  p->fd = socket(PF_NATM, SOCK_DGRAM, PROTO_NATMAAL5);
19065862Sbrian  if (p->fd >= 0) {
19165862Sbrian    log_Printf(LogDEBUG, "%s: Opened atm socket %s\n", p->link.name,
19265862Sbrian               p->name.full);
19365862Sbrian    if (connect(p->fd, (struct sockaddr *)&sock, sizeof sock) == 0)
19465862Sbrian      return dev;
19565862Sbrian    else
19665862Sbrian      log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno));
19765862Sbrian  } else
19865862Sbrian    log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno));
19965862Sbrian
20065862Sbrian  close(p->fd);
20165862Sbrian  p->fd = -1;
20265862Sbrian  free(dev);
20365862Sbrian
20465862Sbrian  return NULL;
20565862Sbrian}
20665862Sbrian
20765862Sbrianstruct device *
20865862Sbrianatm_Create(struct physical *p)
20965862Sbrian{
21065862Sbrian  struct atmdevice *dev;
21165862Sbrian
21265862Sbrian  dev = NULL;
21365863Sbrian  if (p->fd < 0 && !strncasecmp(p->name.full, PPPOA, PPPOA_LEN)
21465862Sbrian      && p->name.full[PPPOA_LEN] == ':') {
21565862Sbrian    char iface[25];
21665862Sbrian    unsigned vci, vpi;
21798243Sbrian
21865863Sbrian    if (sscanf(p->name.full + PPPOA_LEN + 1, "%25[A-Za-z0-9]:%u.%u", iface,
21965863Sbrian               &vpi, &vci) != 3) {
22065863Sbrian      log_Printf(LogWARN, "Malformed ATM device name \'%s\', "
22165863Sbrian                 "PPPoA:if:vpi.vci expected\n", p->name.full);
22265862Sbrian      return NULL;
22365862Sbrian    }
22498243Sbrian
22565862Sbrian    dev = atm_CreateDevice(p, iface, vpi, vci);
22665862Sbrian  }
22765862Sbrian
22865862Sbrian  if (dev) {
22965862Sbrian    memcpy(&dev->dev, &baseatmdevice, sizeof dev->dev);
23065862Sbrian    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF);
23165862Sbrian    if (p->cfg.cd.necessity != CD_DEFAULT)
23265862Sbrian      log_Printf(LogWARN, "Carrier settings ignored\n");
23365862Sbrian    return &dev->dev;
23465862Sbrian  }
23565862Sbrian
23665862Sbrian  return NULL;
23765862Sbrian}
238