16815097bSBrian Somers /*- 26815097bSBrian Somers * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 36815097bSBrian Somers * All rights reserved. 46815097bSBrian Somers * 56815097bSBrian Somers * Redistribution and use in source and binary forms, with or without 66815097bSBrian Somers * modification, are permitted provided that the following conditions 76815097bSBrian Somers * are met: 86815097bSBrian Somers * 1. Redistributions of source code must retain the above copyright 96815097bSBrian Somers * notice, this list of conditions and the following disclaimer. 106815097bSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 116815097bSBrian Somers * notice, this list of conditions and the following disclaimer in the 126815097bSBrian Somers * documentation and/or other materials provided with the distribution. 136815097bSBrian Somers * 146815097bSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156815097bSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166815097bSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176815097bSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186815097bSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196815097bSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206815097bSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216815097bSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226815097bSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236815097bSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246815097bSBrian Somers * SUCH DAMAGE. 256815097bSBrian Somers * 2697d92980SPeter Wemm * $FreeBSD$ 276815097bSBrian Somers */ 286815097bSBrian Somers 296815097bSBrian Somers #include <sys/types.h> 306815097bSBrian Somers #include <sys/socket.h> 316815097bSBrian Somers #include <netinet/in.h> 326815097bSBrian Somers #include <arpa/inet.h> 336815097bSBrian Somers #include <netdb.h> 346815097bSBrian Somers 356815097bSBrian Somers #include <errno.h> 366815097bSBrian Somers #include <stdio.h> 376815097bSBrian Somers #include <stdlib.h> 386815097bSBrian Somers #include <string.h> 39f5a99677SBrian Somers #include <sysexits.h> 40165fbe26SBrian Somers #include <sys/stat.h> 416815097bSBrian Somers #include <sys/uio.h> 426815097bSBrian Somers #include <termios.h> 436815097bSBrian Somers #include <unistd.h> 446815097bSBrian Somers 456815097bSBrian Somers #include "layer.h" 466815097bSBrian Somers #include "defs.h" 476815097bSBrian Somers #include "mbuf.h" 486815097bSBrian Somers #include "log.h" 496815097bSBrian Somers #include "timer.h" 506815097bSBrian Somers #include "lqr.h" 516815097bSBrian Somers #include "hdlc.h" 526815097bSBrian Somers #include "throughput.h" 536815097bSBrian Somers #include "fsm.h" 546815097bSBrian Somers #include "lcp.h" 556815097bSBrian Somers #include "ccp.h" 566815097bSBrian Somers #include "link.h" 576815097bSBrian Somers #include "async.h" 586815097bSBrian Somers #include "descriptor.h" 596815097bSBrian Somers #include "physical.h" 60f5a99677SBrian Somers #include "main.h" 616815097bSBrian Somers #include "udp.h" 626815097bSBrian Somers 63527a86a3SBrian Somers 64527a86a3SBrian Somers #define UDP_CONNECTED 1 65527a86a3SBrian Somers #define UDP_UNCONNECTED 2 66527a86a3SBrian Somers #define UDP_MAYBEUNCONNECTED 3 67527a86a3SBrian Somers 686815097bSBrian Somers struct udpdevice { 696815097bSBrian Somers struct device dev; /* What struct physical knows about */ 706815097bSBrian Somers struct sockaddr_in sock; /* peer address */ 71527a86a3SBrian Somers unsigned connected : 2; /* Have we connect()d ? */ 726815097bSBrian Somers }; 736815097bSBrian Somers 746815097bSBrian Somers #define device2udp(d) ((d)->type == UDP_DEVICE ? (struct udpdevice *)d : NULL) 756815097bSBrian Somers 76f5a99677SBrian Somers int 77f5a99677SBrian Somers udp_DeviceSize(void) 78f5a99677SBrian Somers { 79f5a99677SBrian Somers return sizeof(struct udpdevice); 80f5a99677SBrian Somers } 81f5a99677SBrian Somers 826815097bSBrian Somers static ssize_t 836815097bSBrian Somers udp_Sendto(struct physical *p, const void *v, size_t n) 846815097bSBrian Somers { 856815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 86527a86a3SBrian Somers int ret; 876815097bSBrian Somers 88527a86a3SBrian Somers switch (dev->connected) { 89527a86a3SBrian Somers case UDP_CONNECTED: 90527a86a3SBrian Somers ret = write(p->fd, v, n); 91527a86a3SBrian Somers break; 926815097bSBrian Somers 93527a86a3SBrian Somers case UDP_UNCONNECTED: 94527a86a3SBrian Somers default: 95527a86a3SBrian Somers ret = sendto(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, 966815097bSBrian Somers sizeof dev->sock); 97527a86a3SBrian Somers break; 98527a86a3SBrian Somers } 99527a86a3SBrian Somers if (dev->connected == UDP_MAYBEUNCONNECTED) { 100527a86a3SBrian Somers if (ret == -1 && errno == EISCONN) { 101527a86a3SBrian Somers dev->connected = UDP_CONNECTED; 102527a86a3SBrian Somers ret = write(p->fd, v, n); 103527a86a3SBrian Somers } else 104527a86a3SBrian Somers dev->connected = UDP_UNCONNECTED; 105527a86a3SBrian Somers } 106527a86a3SBrian Somers 107527a86a3SBrian Somers return ret; 1086815097bSBrian Somers } 1096815097bSBrian Somers 1106815097bSBrian Somers static ssize_t 1116815097bSBrian Somers udp_Recvfrom(struct physical *p, void *v, size_t n) 1126815097bSBrian Somers { 1136815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 1146815097bSBrian Somers int sz, ret; 1156815097bSBrian Somers 116527a86a3SBrian Somers if (dev->connected == UDP_CONNECTED) 1176815097bSBrian Somers return read(p->fd, v, n); 1186815097bSBrian Somers 1196815097bSBrian Somers sz = sizeof dev->sock; 1206815097bSBrian Somers ret = recvfrom(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, &sz); 1216815097bSBrian Somers 1226815097bSBrian Somers if (*p->name.full == '\0') { 1236815097bSBrian Somers snprintf(p->name.full, sizeof p->name.full, "%s:%d/udp", 1246815097bSBrian Somers inet_ntoa(dev->sock.sin_addr), ntohs(dev->sock.sin_port)); 1256815097bSBrian Somers p->name.base = p->name.full; 1266815097bSBrian Somers } 1276815097bSBrian Somers 1286815097bSBrian Somers return ret; 1296815097bSBrian Somers } 1306815097bSBrian Somers 1316815097bSBrian Somers static void 1326815097bSBrian Somers udp_Free(struct physical *p) 1336815097bSBrian Somers { 1346815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 1356815097bSBrian Somers 1366815097bSBrian Somers free(dev); 1376815097bSBrian Somers } 1386815097bSBrian Somers 1396815097bSBrian Somers static void 140f5a99677SBrian Somers udp_device2iov(struct device *d, struct iovec *iov, int *niov, 1412cb305afSBrian Somers int maxiov, int *auxfd, int *nauxfd) 1426815097bSBrian Somers { 143f5a99677SBrian Somers int sz = physical_MaxDeviceSize(); 144f5a99677SBrian Somers 145f5a99677SBrian Somers iov[*niov].iov_base = realloc(d, sz); 146f5a99677SBrian Somers if (iov[*niov].iov_base == NULL) { 147f5a99677SBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 148f5a99677SBrian Somers AbortProgram(EX_OSERR); 149f5a99677SBrian Somers } 150f5a99677SBrian Somers iov[*niov].iov_len = sz; 1516815097bSBrian Somers (*niov)++; 1526815097bSBrian Somers } 1536815097bSBrian Somers 1546815097bSBrian Somers static const struct device baseudpdevice = { 1556815097bSBrian Somers UDP_DEVICE, 1566815097bSBrian Somers "udp", 157fdc29d54SBrian Somers { CD_NOTREQUIRED, 0 }, 1586815097bSBrian Somers NULL, 1596815097bSBrian Somers NULL, 1606815097bSBrian Somers NULL, 1616815097bSBrian Somers NULL, 162eb6e5e05SBrian Somers NULL, 16387c3786eSBrian Somers NULL, 1646815097bSBrian Somers udp_Free, 1656815097bSBrian Somers udp_Recvfrom, 1666815097bSBrian Somers udp_Sendto, 1676815097bSBrian Somers udp_device2iov, 1686815097bSBrian Somers NULL, 1696815097bSBrian Somers NULL 1706815097bSBrian Somers }; 1716815097bSBrian Somers 1726815097bSBrian Somers struct device * 1736815097bSBrian Somers udp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 17487c3786eSBrian Somers int maxiov, int *auxfd, int *nauxfd) 1756815097bSBrian Somers { 1766815097bSBrian Somers if (type == UDP_DEVICE) { 177acbd1f00SBrian Somers struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base; 1786815097bSBrian Somers 179f5a99677SBrian Somers dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ 180f5a99677SBrian Somers if (dev == NULL) { 181f5a99677SBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", 182f5a99677SBrian Somers (int)(sizeof *dev)); 183f5a99677SBrian Somers AbortProgram(EX_OSERR); 184f5a99677SBrian Somers } 185f5a99677SBrian Somers 1866815097bSBrian Somers /* Refresh function pointers etc */ 187acbd1f00SBrian Somers memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 1886815097bSBrian Somers 189acbd1f00SBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 190acbd1f00SBrian Somers return &dev->dev; 191acbd1f00SBrian Somers } 1926815097bSBrian Somers 193acbd1f00SBrian Somers return NULL; 1946815097bSBrian Somers } 1956815097bSBrian Somers 1966815097bSBrian Somers static struct udpdevice * 1976815097bSBrian Somers udp_CreateDevice(struct physical *p, char *host, char *port) 1986815097bSBrian Somers { 1996815097bSBrian Somers struct udpdevice *dev; 2006815097bSBrian Somers struct servent *sp; 2016815097bSBrian Somers 2026815097bSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) { 2036815097bSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 2046815097bSBrian Somers p->link.name, strerror(errno)); 2056815097bSBrian Somers return NULL; 2066815097bSBrian Somers } 2076815097bSBrian Somers 2086815097bSBrian Somers dev->sock.sin_family = AF_INET; 2096815097bSBrian Somers dev->sock.sin_addr.s_addr = inet_addr(host); 2106815097bSBrian Somers dev->sock.sin_addr = GetIpAddr(host); 2116815097bSBrian Somers if (dev->sock.sin_addr.s_addr == INADDR_NONE) { 2126815097bSBrian Somers log_Printf(LogWARN, "%s: %s: unknown host\n", p->link.name, host); 2136815097bSBrian Somers free(dev); 2146815097bSBrian Somers return NULL; 2156815097bSBrian Somers } 2166815097bSBrian Somers dev->sock.sin_port = htons(atoi(port)); 2176815097bSBrian Somers if (dev->sock.sin_port == 0) { 2186815097bSBrian Somers sp = getservbyname(port, "udp"); 2196815097bSBrian Somers if (sp) 2206815097bSBrian Somers dev->sock.sin_port = sp->s_port; 2216815097bSBrian Somers else { 2226815097bSBrian Somers log_Printf(LogWARN, "%s: %s: unknown service\n", p->link.name, port); 2236815097bSBrian Somers free(dev); 2246815097bSBrian Somers return NULL; 2256815097bSBrian Somers } 2266815097bSBrian Somers } 2276815097bSBrian Somers 2286815097bSBrian Somers log_Printf(LogPHASE, "%s: Connecting to %s:%s/udp\n", p->link.name, 2296815097bSBrian Somers host, port); 2306815097bSBrian Somers 2316815097bSBrian Somers p->fd = socket(PF_INET, SOCK_DGRAM, 0); 2326815097bSBrian Somers if (p->fd >= 0) { 2336815097bSBrian Somers log_Printf(LogDEBUG, "%s: Opened udp socket %s\n", p->link.name, 2346815097bSBrian Somers p->name.full); 2356815097bSBrian Somers if (connect(p->fd, (struct sockaddr *)&dev->sock, sizeof dev->sock) == 0) { 236527a86a3SBrian Somers dev->connected = UDP_CONNECTED; 2376815097bSBrian Somers return dev; 2386815097bSBrian Somers } else 2396815097bSBrian Somers log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); 2406815097bSBrian Somers } else 2416815097bSBrian Somers log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); 2426815097bSBrian Somers 2436815097bSBrian Somers close(p->fd); 2446815097bSBrian Somers p->fd = -1; 2456815097bSBrian Somers free(dev); 2466815097bSBrian Somers 2476815097bSBrian Somers return NULL; 2486815097bSBrian Somers } 2496815097bSBrian Somers 2506815097bSBrian Somers struct device * 2516815097bSBrian Somers udp_Create(struct physical *p) 2526815097bSBrian Somers { 2536815097bSBrian Somers char *cp, *host, *port, *svc; 2546815097bSBrian Somers struct udpdevice *dev; 2556815097bSBrian Somers 2566815097bSBrian Somers dev = NULL; 2576815097bSBrian Somers if (p->fd < 0) { 25887c3786eSBrian Somers if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) { 2596815097bSBrian Somers *cp = '\0'; 2606815097bSBrian Somers host = p->name.full; 2616815097bSBrian Somers port = cp + 1; 2626815097bSBrian Somers svc = strchr(port, '/'); 2636815097bSBrian Somers if (svc && strcasecmp(svc, "/udp")) { 2646815097bSBrian Somers *cp = ':'; 2656815097bSBrian Somers return NULL; 2666815097bSBrian Somers } 26787c3786eSBrian Somers if (svc) { 26887c3786eSBrian Somers p->fd--; /* We own the device but maybe can't use it - change fd */ 2696815097bSBrian Somers *svc = '\0'; 27087c3786eSBrian Somers } 2716815097bSBrian Somers 2726815097bSBrian Somers if (*host && *port) 2736815097bSBrian Somers dev = udp_CreateDevice(p, host, port); 2746815097bSBrian Somers 2756815097bSBrian Somers *cp = ':'; 2766815097bSBrian Somers if (svc) 2776815097bSBrian Somers *svc = '/'; 2786815097bSBrian Somers } 2796815097bSBrian Somers } else { 2806815097bSBrian Somers /* See if we're a connected udp socket */ 281165fbe26SBrian Somers struct stat st; 282165fbe26SBrian Somers 283165fbe26SBrian Somers if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) { 284165fbe26SBrian Somers int type, sz; 2856815097bSBrian Somers 2866815097bSBrian Somers sz = sizeof type; 287165fbe26SBrian Somers if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) { 288165fbe26SBrian Somers log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name); 289165fbe26SBrian Somers close(p->fd); 290165fbe26SBrian Somers p->fd = -1; 291165fbe26SBrian Somers return NULL; 292165fbe26SBrian Somers } 293165fbe26SBrian Somers 294165fbe26SBrian Somers if (sz == sizeof type && type == SOCK_DGRAM) { 2956815097bSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) { 2966815097bSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 2976815097bSBrian Somers p->link.name, strerror(errno)); 2986815097bSBrian Somers return NULL; 2996815097bSBrian Somers } 3006815097bSBrian Somers 301527a86a3SBrian Somers /* We can't getpeername().... */ 302527a86a3SBrian Somers dev->connected = UDP_MAYBEUNCONNECTED; 3036815097bSBrian Somers 3046815097bSBrian Somers log_Printf(LogPHASE, "%s: Link is a udp socket\n", p->link.name); 3056815097bSBrian Somers 3066815097bSBrian Somers if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) { 3076815097bSBrian Somers log_Printf(LogPHASE, "%s: Changing openmode to PASSIVE\n", 3086815097bSBrian Somers p->link.name); 3096815097bSBrian Somers p->link.lcp.cfg.openmode = OPEN_PASSIVE; 3106815097bSBrian Somers } 3116815097bSBrian Somers } 3126815097bSBrian Somers } 313165fbe26SBrian Somers } 3146815097bSBrian Somers 3156815097bSBrian Somers if (dev) { 3166815097bSBrian Somers memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 317acbd1f00SBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 318fdc29d54SBrian Somers if (p->cfg.cd.necessity != CD_DEFAULT) 319fdc29d54SBrian Somers log_Printf(LogWARN, "Carrier settings ignored\n"); 3206815097bSBrian Somers return &dev->dev; 3216815097bSBrian Somers } 3226815097bSBrian Somers 3236815097bSBrian Somers return NULL; 3246815097bSBrian Somers } 325