16815097bSBrian Somers /*- 2*1de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*1de7b4b8SPedro F. Giffuni * 46815097bSBrian Somers * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 56815097bSBrian Somers * All rights reserved. 66815097bSBrian Somers * 76815097bSBrian Somers * Redistribution and use in source and binary forms, with or without 86815097bSBrian Somers * modification, are permitted provided that the following conditions 96815097bSBrian Somers * are met: 106815097bSBrian Somers * 1. Redistributions of source code must retain the above copyright 116815097bSBrian Somers * notice, this list of conditions and the following disclaimer. 126815097bSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 136815097bSBrian Somers * notice, this list of conditions and the following disclaimer in the 146815097bSBrian Somers * documentation and/or other materials provided with the distribution. 156815097bSBrian Somers * 166815097bSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176815097bSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186815097bSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196815097bSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 206815097bSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216815097bSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226815097bSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236815097bSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246815097bSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256815097bSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266815097bSBrian Somers * SUCH DAMAGE. 276815097bSBrian Somers * 2897d92980SPeter Wemm * $FreeBSD$ 296815097bSBrian Somers */ 306815097bSBrian Somers 316815097bSBrian Somers #include <sys/types.h> 326815097bSBrian Somers #include <sys/socket.h> 336815097bSBrian Somers #include <netinet/in.h> 346815097bSBrian Somers #include <arpa/inet.h> 356815097bSBrian Somers #include <netdb.h> 366815097bSBrian Somers 376815097bSBrian Somers #include <errno.h> 386815097bSBrian Somers #include <stdio.h> 396815097bSBrian Somers #include <stdlib.h> 406815097bSBrian Somers #include <string.h> 41f5a99677SBrian Somers #include <sysexits.h> 42165fbe26SBrian Somers #include <sys/stat.h> 436815097bSBrian Somers #include <sys/uio.h> 446815097bSBrian Somers #include <termios.h> 456815097bSBrian Somers #include <unistd.h> 466815097bSBrian Somers 476815097bSBrian Somers #include "layer.h" 486815097bSBrian Somers #include "defs.h" 496815097bSBrian Somers #include "mbuf.h" 506815097bSBrian Somers #include "log.h" 516815097bSBrian Somers #include "timer.h" 526815097bSBrian Somers #include "lqr.h" 536815097bSBrian Somers #include "hdlc.h" 546815097bSBrian Somers #include "throughput.h" 556815097bSBrian Somers #include "fsm.h" 566815097bSBrian Somers #include "lcp.h" 576815097bSBrian Somers #include "ccp.h" 586815097bSBrian Somers #include "link.h" 596815097bSBrian Somers #include "async.h" 606815097bSBrian Somers #include "descriptor.h" 616815097bSBrian Somers #include "physical.h" 62f5a99677SBrian Somers #include "main.h" 636815097bSBrian Somers #include "udp.h" 646815097bSBrian Somers 65527a86a3SBrian Somers 66527a86a3SBrian Somers #define UDP_CONNECTED 1 67527a86a3SBrian Somers #define UDP_UNCONNECTED 2 68527a86a3SBrian Somers #define UDP_MAYBEUNCONNECTED 3 69527a86a3SBrian Somers 706815097bSBrian Somers struct udpdevice { 716815097bSBrian Somers struct device dev; /* What struct physical knows about */ 726815097bSBrian Somers struct sockaddr_in sock; /* peer address */ 73527a86a3SBrian Somers unsigned connected : 2; /* Have we connect()d ? */ 746815097bSBrian Somers }; 756815097bSBrian Somers 766815097bSBrian Somers #define device2udp(d) ((d)->type == UDP_DEVICE ? (struct udpdevice *)d : NULL) 776815097bSBrian Somers 78057f1760SBrian Somers unsigned 79f5a99677SBrian Somers udp_DeviceSize(void) 80f5a99677SBrian Somers { 81f5a99677SBrian Somers return sizeof(struct udpdevice); 82f5a99677SBrian Somers } 83f5a99677SBrian Somers 846815097bSBrian Somers static ssize_t 856815097bSBrian Somers udp_Sendto(struct physical *p, const void *v, size_t n) 866815097bSBrian Somers { 876815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 88527a86a3SBrian Somers int ret; 896815097bSBrian Somers 90527a86a3SBrian Somers switch (dev->connected) { 91527a86a3SBrian Somers case UDP_CONNECTED: 92527a86a3SBrian Somers ret = write(p->fd, v, n); 93527a86a3SBrian Somers break; 946815097bSBrian Somers 95527a86a3SBrian Somers case UDP_UNCONNECTED: 96527a86a3SBrian Somers default: 97527a86a3SBrian Somers ret = sendto(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, 986815097bSBrian Somers sizeof dev->sock); 99527a86a3SBrian Somers break; 100527a86a3SBrian Somers } 101527a86a3SBrian Somers if (dev->connected == UDP_MAYBEUNCONNECTED) { 102527a86a3SBrian Somers if (ret == -1 && errno == EISCONN) { 103527a86a3SBrian Somers dev->connected = UDP_CONNECTED; 104527a86a3SBrian Somers ret = write(p->fd, v, n); 105527a86a3SBrian Somers } else 106527a86a3SBrian Somers dev->connected = UDP_UNCONNECTED; 107527a86a3SBrian Somers } 108527a86a3SBrian Somers 109527a86a3SBrian Somers return ret; 1106815097bSBrian Somers } 1116815097bSBrian Somers 1126815097bSBrian Somers static ssize_t 1136815097bSBrian Somers udp_Recvfrom(struct physical *p, void *v, size_t n) 1146815097bSBrian Somers { 1156815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 1166815097bSBrian Somers int sz, ret; 1176815097bSBrian Somers 118527a86a3SBrian Somers if (dev->connected == UDP_CONNECTED) 1196815097bSBrian Somers return read(p->fd, v, n); 1206815097bSBrian Somers 1216815097bSBrian Somers sz = sizeof dev->sock; 1226815097bSBrian Somers ret = recvfrom(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, &sz); 1236815097bSBrian Somers 1246815097bSBrian Somers if (*p->name.full == '\0') { 1256815097bSBrian Somers snprintf(p->name.full, sizeof p->name.full, "%s:%d/udp", 1266815097bSBrian Somers inet_ntoa(dev->sock.sin_addr), ntohs(dev->sock.sin_port)); 1276815097bSBrian Somers p->name.base = p->name.full; 1286815097bSBrian Somers } 1296815097bSBrian Somers 1306815097bSBrian Somers return ret; 1316815097bSBrian Somers } 1326815097bSBrian Somers 1336815097bSBrian Somers static void 1346815097bSBrian Somers udp_Free(struct physical *p) 1356815097bSBrian Somers { 1366815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 1376815097bSBrian Somers 1386815097bSBrian Somers free(dev); 1396815097bSBrian Somers } 1406815097bSBrian Somers 1416815097bSBrian Somers static void 142f5a99677SBrian Somers udp_device2iov(struct device *d, struct iovec *iov, int *niov, 143057f1760SBrian Somers int maxiov __unused, int *auxfd __unused, int *nauxfd __unused) 1446815097bSBrian Somers { 145f5a99677SBrian Somers int sz = physical_MaxDeviceSize(); 146f5a99677SBrian Somers 147f5a99677SBrian Somers iov[*niov].iov_base = realloc(d, sz); 148f5a99677SBrian Somers if (iov[*niov].iov_base == NULL) { 149f5a99677SBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 150f5a99677SBrian Somers AbortProgram(EX_OSERR); 151f5a99677SBrian Somers } 152f5a99677SBrian Somers iov[*niov].iov_len = sz; 1536815097bSBrian Somers (*niov)++; 1546815097bSBrian Somers } 1556815097bSBrian Somers 1566815097bSBrian Somers static const struct device baseudpdevice = { 1576815097bSBrian Somers UDP_DEVICE, 1586815097bSBrian Somers "udp", 159c8b9fb53SBrian Somers 0, 160fdc29d54SBrian Somers { CD_NOTREQUIRED, 0 }, 1616815097bSBrian Somers NULL, 1626815097bSBrian Somers NULL, 1636815097bSBrian Somers NULL, 1646815097bSBrian Somers NULL, 165eb6e5e05SBrian Somers NULL, 16687c3786eSBrian Somers NULL, 167fb11a9c2SBrian Somers NULL, 1686815097bSBrian Somers udp_Free, 1696815097bSBrian Somers udp_Recvfrom, 1706815097bSBrian Somers udp_Sendto, 1716815097bSBrian Somers udp_device2iov, 1726815097bSBrian Somers NULL, 173de59e178SBrian Somers NULL, 1746815097bSBrian Somers NULL 1756815097bSBrian Somers }; 1766815097bSBrian Somers 1776815097bSBrian Somers struct device * 1786815097bSBrian Somers udp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 179057f1760SBrian Somers int maxiov __unused, int *auxfd __unused, int *nauxfd __unused) 1806815097bSBrian Somers { 1816815097bSBrian Somers if (type == UDP_DEVICE) { 182acbd1f00SBrian Somers struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base; 1836815097bSBrian Somers 184f5a99677SBrian Somers dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ 185f5a99677SBrian Somers if (dev == NULL) { 186f5a99677SBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", 187f5a99677SBrian Somers (int)(sizeof *dev)); 188f5a99677SBrian Somers AbortProgram(EX_OSERR); 189f5a99677SBrian Somers } 190f5a99677SBrian Somers 1916815097bSBrian Somers /* Refresh function pointers etc */ 192acbd1f00SBrian Somers memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 1936815097bSBrian Somers 194acbd1f00SBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 195acbd1f00SBrian Somers return &dev->dev; 196acbd1f00SBrian Somers } 1976815097bSBrian Somers 198acbd1f00SBrian Somers return NULL; 1996815097bSBrian Somers } 2006815097bSBrian Somers 2016815097bSBrian Somers static struct udpdevice * 2026815097bSBrian Somers udp_CreateDevice(struct physical *p, char *host, char *port) 2036815097bSBrian Somers { 2046815097bSBrian Somers struct udpdevice *dev; 2056815097bSBrian Somers struct servent *sp; 2066815097bSBrian Somers 2076815097bSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) { 2086815097bSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 2096815097bSBrian Somers p->link.name, strerror(errno)); 2106815097bSBrian Somers return NULL; 2116815097bSBrian Somers } 2126815097bSBrian Somers 2136815097bSBrian Somers dev->sock.sin_family = AF_INET; 2146815097bSBrian Somers dev->sock.sin_addr = GetIpAddr(host); 2156815097bSBrian Somers if (dev->sock.sin_addr.s_addr == INADDR_NONE) { 2166815097bSBrian Somers log_Printf(LogWARN, "%s: %s: unknown host\n", p->link.name, host); 2176815097bSBrian Somers free(dev); 2186815097bSBrian Somers return NULL; 2196815097bSBrian Somers } 2206815097bSBrian Somers dev->sock.sin_port = htons(atoi(port)); 2216815097bSBrian Somers if (dev->sock.sin_port == 0) { 2226815097bSBrian Somers sp = getservbyname(port, "udp"); 2236815097bSBrian Somers if (sp) 2246815097bSBrian Somers dev->sock.sin_port = sp->s_port; 2256815097bSBrian Somers else { 2266815097bSBrian Somers log_Printf(LogWARN, "%s: %s: unknown service\n", p->link.name, port); 2276815097bSBrian Somers free(dev); 2286815097bSBrian Somers return NULL; 2296815097bSBrian Somers } 2306815097bSBrian Somers } 2316815097bSBrian Somers 2326815097bSBrian Somers log_Printf(LogPHASE, "%s: Connecting to %s:%s/udp\n", p->link.name, 2336815097bSBrian Somers host, port); 2346815097bSBrian Somers 23563c6cac9SBrian Somers p->fd = socket(PF_INET, SOCK_DGRAM, 0); 2366815097bSBrian Somers if (p->fd >= 0) { 2376815097bSBrian Somers log_Printf(LogDEBUG, "%s: Opened udp socket %s\n", p->link.name, 2386815097bSBrian Somers p->name.full); 2396815097bSBrian Somers if (connect(p->fd, (struct sockaddr *)&dev->sock, sizeof dev->sock) == 0) { 240527a86a3SBrian Somers dev->connected = UDP_CONNECTED; 2416815097bSBrian Somers return dev; 2426815097bSBrian Somers } else 2436815097bSBrian Somers log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); 2446815097bSBrian Somers } else 2456815097bSBrian Somers log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); 2466815097bSBrian Somers 2476815097bSBrian Somers close(p->fd); 2486815097bSBrian Somers p->fd = -1; 2496815097bSBrian Somers free(dev); 2506815097bSBrian Somers 2516815097bSBrian Somers return NULL; 2526815097bSBrian Somers } 2536815097bSBrian Somers 2546815097bSBrian Somers struct device * 2556815097bSBrian Somers udp_Create(struct physical *p) 2566815097bSBrian Somers { 2576815097bSBrian Somers char *cp, *host, *port, *svc; 2586815097bSBrian Somers struct udpdevice *dev; 2596815097bSBrian Somers 2606815097bSBrian Somers dev = NULL; 2616815097bSBrian Somers if (p->fd < 0) { 26287c3786eSBrian Somers if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) { 2636815097bSBrian Somers *cp = '\0'; 2646815097bSBrian Somers host = p->name.full; 2656815097bSBrian Somers port = cp + 1; 2666815097bSBrian Somers svc = strchr(port, '/'); 2676815097bSBrian Somers if (svc && strcasecmp(svc, "/udp")) { 2686815097bSBrian Somers *cp = ':'; 2696815097bSBrian Somers return NULL; 2706815097bSBrian Somers } 27187c3786eSBrian Somers if (svc) { 27287c3786eSBrian Somers p->fd--; /* We own the device but maybe can't use it - change fd */ 2736815097bSBrian Somers *svc = '\0'; 27487c3786eSBrian Somers } 2756815097bSBrian Somers 2766815097bSBrian Somers if (*host && *port) 2776815097bSBrian Somers dev = udp_CreateDevice(p, host, port); 2786815097bSBrian Somers 2796815097bSBrian Somers *cp = ':'; 2806815097bSBrian Somers if (svc) 2816815097bSBrian Somers *svc = '/'; 2826815097bSBrian Somers } 2836815097bSBrian Somers } else { 2846815097bSBrian Somers /* See if we're a connected udp socket */ 285165fbe26SBrian Somers struct stat st; 286165fbe26SBrian Somers 287165fbe26SBrian Somers if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) { 288165fbe26SBrian Somers int type, sz; 2896815097bSBrian Somers 2906815097bSBrian Somers sz = sizeof type; 291165fbe26SBrian Somers if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) { 292165fbe26SBrian Somers log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name); 293165fbe26SBrian Somers close(p->fd); 294165fbe26SBrian Somers p->fd = -1; 295165fbe26SBrian Somers return NULL; 296165fbe26SBrian Somers } 297165fbe26SBrian Somers 298165fbe26SBrian Somers if (sz == sizeof type && type == SOCK_DGRAM) { 299c3805e01SBrian Somers struct sockaddr_in sock; 300c3805e01SBrian Somers struct sockaddr *sockp = (struct sockaddr *)&sock; 301c3805e01SBrian Somers 3026815097bSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) { 3036815097bSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 3046815097bSBrian Somers p->link.name, strerror(errno)); 3056815097bSBrian Somers return NULL; 3066815097bSBrian Somers } 3076815097bSBrian Somers 308c3805e01SBrian Somers if (getpeername(p->fd, sockp, &sz) == 0) { 309c3805e01SBrian Somers log_Printf(LogPHASE, "%s: Link is a connected udp socket\n", 310c3805e01SBrian Somers p->link.name); 311c3805e01SBrian Somers dev->connected = UDP_CONNECTED; 312c3805e01SBrian Somers } else { 313c3805e01SBrian Somers log_Printf(LogPHASE, "%s: Link is a disconnected udp socket\n", 314c3805e01SBrian Somers p->link.name); 3156815097bSBrian Somers 316c3805e01SBrian Somers dev->connected = UDP_MAYBEUNCONNECTED; 3176815097bSBrian Somers 3186815097bSBrian Somers if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) { 3196815097bSBrian Somers log_Printf(LogPHASE, "%s: Changing openmode to PASSIVE\n", 3206815097bSBrian Somers p->link.name); 3216815097bSBrian Somers p->link.lcp.cfg.openmode = OPEN_PASSIVE; 3226815097bSBrian Somers } 3236815097bSBrian Somers } 3246815097bSBrian Somers } 325165fbe26SBrian Somers } 326c3805e01SBrian Somers } 3276815097bSBrian Somers 3286815097bSBrian Somers if (dev) { 3296815097bSBrian Somers memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 330acbd1f00SBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 331fdc29d54SBrian Somers if (p->cfg.cd.necessity != CD_DEFAULT) 332fdc29d54SBrian Somers log_Printf(LogWARN, "Carrier settings ignored\n"); 3336815097bSBrian Somers return &dev->dev; 3346815097bSBrian Somers } 3356815097bSBrian Somers 3366815097bSBrian Somers return NULL; 3376815097bSBrian Somers } 338