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> 406815097bSBrian Somers #include <sys/uio.h> 416815097bSBrian Somers #include <termios.h> 426815097bSBrian Somers #include <unistd.h> 436815097bSBrian Somers 446815097bSBrian Somers #include "layer.h" 456815097bSBrian Somers #include "defs.h" 466815097bSBrian Somers #include "mbuf.h" 476815097bSBrian Somers #include "log.h" 486815097bSBrian Somers #include "timer.h" 496815097bSBrian Somers #include "lqr.h" 506815097bSBrian Somers #include "hdlc.h" 516815097bSBrian Somers #include "throughput.h" 526815097bSBrian Somers #include "fsm.h" 536815097bSBrian Somers #include "lcp.h" 546815097bSBrian Somers #include "ccp.h" 556815097bSBrian Somers #include "link.h" 566815097bSBrian Somers #include "async.h" 576815097bSBrian Somers #include "descriptor.h" 586815097bSBrian Somers #include "physical.h" 59f5a99677SBrian Somers #include "main.h" 606815097bSBrian Somers #include "udp.h" 616815097bSBrian Somers 626815097bSBrian Somers struct udpdevice { 636815097bSBrian Somers struct device dev; /* What struct physical knows about */ 646815097bSBrian Somers struct sockaddr_in sock; /* peer address */ 656815097bSBrian Somers unsigned connected : 1; /* Have we connect()d ? */ 666815097bSBrian Somers }; 676815097bSBrian Somers 686815097bSBrian Somers #define device2udp(d) ((d)->type == UDP_DEVICE ? (struct udpdevice *)d : NULL) 696815097bSBrian Somers 70f5a99677SBrian Somers int 71f5a99677SBrian Somers udp_DeviceSize(void) 72f5a99677SBrian Somers { 73f5a99677SBrian Somers return sizeof(struct udpdevice); 74f5a99677SBrian Somers } 75f5a99677SBrian Somers 766815097bSBrian Somers static ssize_t 776815097bSBrian Somers udp_Sendto(struct physical *p, const void *v, size_t n) 786815097bSBrian Somers { 796815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 806815097bSBrian Somers 816815097bSBrian Somers if (dev->connected) 826815097bSBrian Somers return write(p->fd, v, n); 836815097bSBrian Somers 846815097bSBrian Somers return sendto(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, 856815097bSBrian Somers sizeof dev->sock); 866815097bSBrian Somers } 876815097bSBrian Somers 886815097bSBrian Somers static ssize_t 896815097bSBrian Somers udp_Recvfrom(struct physical *p, void *v, size_t n) 906815097bSBrian Somers { 916815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 926815097bSBrian Somers int sz, ret; 936815097bSBrian Somers 946815097bSBrian Somers if (dev->connected) 956815097bSBrian Somers return read(p->fd, v, n); 966815097bSBrian Somers 976815097bSBrian Somers sz = sizeof dev->sock; 986815097bSBrian Somers ret = recvfrom(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, &sz); 996815097bSBrian Somers 1006815097bSBrian Somers if (*p->name.full == '\0') { 1016815097bSBrian Somers snprintf(p->name.full, sizeof p->name.full, "%s:%d/udp", 1026815097bSBrian Somers inet_ntoa(dev->sock.sin_addr), ntohs(dev->sock.sin_port)); 1036815097bSBrian Somers p->name.base = p->name.full; 1046815097bSBrian Somers } 1056815097bSBrian Somers 1066815097bSBrian Somers return ret; 1076815097bSBrian Somers } 1086815097bSBrian Somers 1096815097bSBrian Somers static void 1106815097bSBrian Somers udp_Free(struct physical *p) 1116815097bSBrian Somers { 1126815097bSBrian Somers struct udpdevice *dev = device2udp(p->handler); 1136815097bSBrian Somers 1146815097bSBrian Somers free(dev); 1156815097bSBrian Somers } 1166815097bSBrian Somers 1176815097bSBrian Somers static void 118f5a99677SBrian Somers udp_device2iov(struct device *d, struct iovec *iov, int *niov, 1192cb305afSBrian Somers int maxiov, int *auxfd, int *nauxfd) 1206815097bSBrian Somers { 121f5a99677SBrian Somers int sz = physical_MaxDeviceSize(); 122f5a99677SBrian Somers 123f5a99677SBrian Somers iov[*niov].iov_base = realloc(d, sz); 124f5a99677SBrian Somers if (iov[*niov].iov_base == NULL) { 125f5a99677SBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 126f5a99677SBrian Somers AbortProgram(EX_OSERR); 127f5a99677SBrian Somers } 128f5a99677SBrian Somers iov[*niov].iov_len = sz; 1296815097bSBrian Somers (*niov)++; 1306815097bSBrian Somers } 1316815097bSBrian Somers 1326815097bSBrian Somers static const struct device baseudpdevice = { 1336815097bSBrian Somers UDP_DEVICE, 1346815097bSBrian Somers "udp", 135fdc29d54SBrian Somers { CD_NOTREQUIRED, 0 }, 1366815097bSBrian Somers NULL, 1376815097bSBrian Somers NULL, 1386815097bSBrian Somers NULL, 1396815097bSBrian Somers NULL, 140eb6e5e05SBrian Somers NULL, 14187c3786eSBrian Somers NULL, 1426815097bSBrian Somers udp_Free, 1436815097bSBrian Somers udp_Recvfrom, 1446815097bSBrian Somers udp_Sendto, 1456815097bSBrian Somers udp_device2iov, 1466815097bSBrian Somers NULL, 1476815097bSBrian Somers NULL 1486815097bSBrian Somers }; 1496815097bSBrian Somers 1506815097bSBrian Somers struct device * 1516815097bSBrian Somers udp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 15287c3786eSBrian Somers int maxiov, int *auxfd, int *nauxfd) 1536815097bSBrian Somers { 1546815097bSBrian Somers if (type == UDP_DEVICE) { 155acbd1f00SBrian Somers struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base; 1566815097bSBrian Somers 157f5a99677SBrian Somers dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ 158f5a99677SBrian Somers if (dev == NULL) { 159f5a99677SBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", 160f5a99677SBrian Somers (int)(sizeof *dev)); 161f5a99677SBrian Somers AbortProgram(EX_OSERR); 162f5a99677SBrian Somers } 163f5a99677SBrian Somers 1646815097bSBrian Somers /* Refresh function pointers etc */ 165acbd1f00SBrian Somers memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 1666815097bSBrian Somers 167acbd1f00SBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 168acbd1f00SBrian Somers return &dev->dev; 169acbd1f00SBrian Somers } 1706815097bSBrian Somers 171acbd1f00SBrian Somers return NULL; 1726815097bSBrian Somers } 1736815097bSBrian Somers 1746815097bSBrian Somers static struct udpdevice * 1756815097bSBrian Somers udp_CreateDevice(struct physical *p, char *host, char *port) 1766815097bSBrian Somers { 1776815097bSBrian Somers struct udpdevice *dev; 1786815097bSBrian Somers struct servent *sp; 1796815097bSBrian Somers 1806815097bSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) { 1816815097bSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 1826815097bSBrian Somers p->link.name, strerror(errno)); 1836815097bSBrian Somers return NULL; 1846815097bSBrian Somers } 1856815097bSBrian Somers 1866815097bSBrian Somers dev->sock.sin_family = AF_INET; 1876815097bSBrian Somers dev->sock.sin_addr.s_addr = inet_addr(host); 1886815097bSBrian Somers dev->sock.sin_addr = GetIpAddr(host); 1896815097bSBrian Somers if (dev->sock.sin_addr.s_addr == INADDR_NONE) { 1906815097bSBrian Somers log_Printf(LogWARN, "%s: %s: unknown host\n", p->link.name, host); 1916815097bSBrian Somers free(dev); 1926815097bSBrian Somers return NULL; 1936815097bSBrian Somers } 1946815097bSBrian Somers dev->sock.sin_port = htons(atoi(port)); 1956815097bSBrian Somers if (dev->sock.sin_port == 0) { 1966815097bSBrian Somers sp = getservbyname(port, "udp"); 1976815097bSBrian Somers if (sp) 1986815097bSBrian Somers dev->sock.sin_port = sp->s_port; 1996815097bSBrian Somers else { 2006815097bSBrian Somers log_Printf(LogWARN, "%s: %s: unknown service\n", p->link.name, port); 2016815097bSBrian Somers free(dev); 2026815097bSBrian Somers return NULL; 2036815097bSBrian Somers } 2046815097bSBrian Somers } 2056815097bSBrian Somers 2066815097bSBrian Somers log_Printf(LogPHASE, "%s: Connecting to %s:%s/udp\n", p->link.name, 2076815097bSBrian Somers host, port); 2086815097bSBrian Somers 2096815097bSBrian Somers p->fd = socket(PF_INET, SOCK_DGRAM, 0); 2106815097bSBrian Somers if (p->fd >= 0) { 2116815097bSBrian Somers log_Printf(LogDEBUG, "%s: Opened udp socket %s\n", p->link.name, 2126815097bSBrian Somers p->name.full); 2136815097bSBrian Somers if (connect(p->fd, (struct sockaddr *)&dev->sock, sizeof dev->sock) == 0) { 2146815097bSBrian Somers dev->connected = 1; 2156815097bSBrian Somers return dev; 2166815097bSBrian Somers } else 2176815097bSBrian Somers log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); 2186815097bSBrian Somers } else 2196815097bSBrian Somers log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); 2206815097bSBrian Somers 2216815097bSBrian Somers close(p->fd); 2226815097bSBrian Somers p->fd = -1; 2236815097bSBrian Somers free(dev); 2246815097bSBrian Somers 2256815097bSBrian Somers return NULL; 2266815097bSBrian Somers } 2276815097bSBrian Somers 2286815097bSBrian Somers struct device * 2296815097bSBrian Somers udp_Create(struct physical *p) 2306815097bSBrian Somers { 2316815097bSBrian Somers char *cp, *host, *port, *svc; 2326815097bSBrian Somers struct udpdevice *dev; 2336815097bSBrian Somers 2346815097bSBrian Somers dev = NULL; 2356815097bSBrian Somers if (p->fd < 0) { 23687c3786eSBrian Somers if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) { 2376815097bSBrian Somers *cp = '\0'; 2386815097bSBrian Somers host = p->name.full; 2396815097bSBrian Somers port = cp + 1; 2406815097bSBrian Somers svc = strchr(port, '/'); 2416815097bSBrian Somers if (svc && strcasecmp(svc, "/udp")) { 2426815097bSBrian Somers *cp = ':'; 2436815097bSBrian Somers return NULL; 2446815097bSBrian Somers } 24587c3786eSBrian Somers if (svc) { 24687c3786eSBrian Somers p->fd--; /* We own the device but maybe can't use it - change fd */ 2476815097bSBrian Somers *svc = '\0'; 24887c3786eSBrian Somers } 2496815097bSBrian Somers 2506815097bSBrian Somers if (*host && *port) 2516815097bSBrian Somers dev = udp_CreateDevice(p, host, port); 2526815097bSBrian Somers 2536815097bSBrian Somers *cp = ':'; 2546815097bSBrian Somers if (svc) 2556815097bSBrian Somers *svc = '/'; 2566815097bSBrian Somers } 2576815097bSBrian Somers } else { 2586815097bSBrian Somers /* See if we're a connected udp socket */ 2596815097bSBrian Somers int type, sz, err; 2606815097bSBrian Somers 2616815097bSBrian Somers sz = sizeof type; 2626815097bSBrian Somers if ((err = getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz)) == 0 && 2636815097bSBrian Somers sz == sizeof type && type == SOCK_DGRAM) { 2646815097bSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) { 2656815097bSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 2666815097bSBrian Somers p->link.name, strerror(errno)); 2676815097bSBrian Somers return NULL; 2686815097bSBrian Somers } 2696815097bSBrian Somers 2706815097bSBrian Somers /* We can't getpeername().... hence we stay un-connect()ed */ 2716815097bSBrian Somers dev->connected = 0; 2726815097bSBrian Somers 2736815097bSBrian Somers log_Printf(LogPHASE, "%s: Link is a udp socket\n", p->link.name); 2746815097bSBrian Somers 2756815097bSBrian Somers if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) { 2766815097bSBrian Somers log_Printf(LogPHASE, "%s: Changing openmode to PASSIVE\n", 2776815097bSBrian Somers p->link.name); 2786815097bSBrian Somers p->link.lcp.cfg.openmode = OPEN_PASSIVE; 2796815097bSBrian Somers } 2806815097bSBrian Somers } 2816815097bSBrian Somers } 2826815097bSBrian Somers 2836815097bSBrian Somers if (dev) { 2846815097bSBrian Somers memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 285acbd1f00SBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 286fdc29d54SBrian Somers if (p->cfg.cd.necessity != CD_DEFAULT) 287fdc29d54SBrian Somers log_Printf(LogWARN, "Carrier settings ignored\n"); 2886815097bSBrian Somers return &dev->dev; 2896815097bSBrian Somers } 2906815097bSBrian Somers 2916815097bSBrian Somers return NULL; 2926815097bSBrian Somers } 293