1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <netdb.h> 36 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <sysexits.h> 42 #include <sys/stat.h> 43 #include <sys/uio.h> 44 #include <termios.h> 45 #include <unistd.h> 46 47 #include "layer.h" 48 #include "defs.h" 49 #include "mbuf.h" 50 #include "log.h" 51 #include "timer.h" 52 #include "lqr.h" 53 #include "hdlc.h" 54 #include "throughput.h" 55 #include "fsm.h" 56 #include "lcp.h" 57 #include "ccp.h" 58 #include "link.h" 59 #include "async.h" 60 #include "descriptor.h" 61 #include "physical.h" 62 #include "main.h" 63 #include "udp.h" 64 65 66 #define UDP_CONNECTED 1 67 #define UDP_UNCONNECTED 2 68 #define UDP_MAYBEUNCONNECTED 3 69 70 struct udpdevice { 71 struct device dev; /* What struct physical knows about */ 72 struct sockaddr_in sock; /* peer address */ 73 unsigned connected : 2; /* Have we connect()d ? */ 74 }; 75 76 #define device2udp(d) ((d)->type == UDP_DEVICE ? (struct udpdevice *)d : NULL) 77 78 unsigned 79 udp_DeviceSize(void) 80 { 81 return sizeof(struct udpdevice); 82 } 83 84 static ssize_t 85 udp_Sendto(struct physical *p, const void *v, size_t n) 86 { 87 struct udpdevice *dev = device2udp(p->handler); 88 int ret; 89 90 switch (dev->connected) { 91 case UDP_CONNECTED: 92 ret = write(p->fd, v, n); 93 break; 94 95 case UDP_UNCONNECTED: 96 default: 97 ret = sendto(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, 98 sizeof dev->sock); 99 break; 100 } 101 if (dev->connected == UDP_MAYBEUNCONNECTED) { 102 if (ret == -1 && errno == EISCONN) { 103 dev->connected = UDP_CONNECTED; 104 ret = write(p->fd, v, n); 105 } else 106 dev->connected = UDP_UNCONNECTED; 107 } 108 109 return ret; 110 } 111 112 static ssize_t 113 udp_Recvfrom(struct physical *p, void *v, size_t n) 114 { 115 struct udpdevice *dev = device2udp(p->handler); 116 int sz, ret; 117 118 if (dev->connected == UDP_CONNECTED) 119 return read(p->fd, v, n); 120 121 sz = sizeof dev->sock; 122 ret = recvfrom(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, &sz); 123 124 if (*p->name.full == '\0') { 125 snprintf(p->name.full, sizeof p->name.full, "%s:%d/udp", 126 inet_ntoa(dev->sock.sin_addr), ntohs(dev->sock.sin_port)); 127 p->name.base = p->name.full; 128 } 129 130 return ret; 131 } 132 133 static void 134 udp_Free(struct physical *p) 135 { 136 struct udpdevice *dev = device2udp(p->handler); 137 138 free(dev); 139 } 140 141 static void 142 udp_device2iov(struct device *d, struct iovec *iov, int *niov, 143 int maxiov __unused, int *auxfd __unused, int *nauxfd __unused) 144 { 145 int sz = physical_MaxDeviceSize(); 146 147 iov[*niov].iov_base = realloc(d, sz); 148 if (iov[*niov].iov_base == NULL) { 149 log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 150 AbortProgram(EX_OSERR); 151 } 152 iov[*niov].iov_len = sz; 153 (*niov)++; 154 } 155 156 static const struct device baseudpdevice = { 157 UDP_DEVICE, 158 "udp", 159 0, 160 { CD_NOTREQUIRED, 0 }, 161 NULL, 162 NULL, 163 NULL, 164 NULL, 165 NULL, 166 NULL, 167 NULL, 168 udp_Free, 169 udp_Recvfrom, 170 udp_Sendto, 171 udp_device2iov, 172 NULL, 173 NULL, 174 NULL 175 }; 176 177 struct device * 178 udp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 179 int maxiov __unused, int *auxfd __unused, int *nauxfd __unused) 180 { 181 if (type == UDP_DEVICE) { 182 struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base; 183 184 dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ 185 if (dev == NULL) { 186 log_Printf(LogALERT, "Failed to allocate memory: %d\n", 187 (int)(sizeof *dev)); 188 AbortProgram(EX_OSERR); 189 } 190 191 /* Refresh function pointers etc */ 192 memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 193 194 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 195 return &dev->dev; 196 } 197 198 return NULL; 199 } 200 201 static struct udpdevice * 202 udp_CreateDevice(struct physical *p, char *host, char *port) 203 { 204 struct udpdevice *dev; 205 struct servent *sp; 206 207 if ((dev = malloc(sizeof *dev)) == NULL) { 208 log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 209 p->link.name, strerror(errno)); 210 return NULL; 211 } 212 213 dev->sock.sin_family = AF_INET; 214 dev->sock.sin_addr = GetIpAddr(host); 215 if (dev->sock.sin_addr.s_addr == INADDR_NONE) { 216 log_Printf(LogWARN, "%s: %s: unknown host\n", p->link.name, host); 217 free(dev); 218 return NULL; 219 } 220 dev->sock.sin_port = htons(atoi(port)); 221 if (dev->sock.sin_port == 0) { 222 sp = getservbyname(port, "udp"); 223 if (sp) 224 dev->sock.sin_port = sp->s_port; 225 else { 226 log_Printf(LogWARN, "%s: %s: unknown service\n", p->link.name, port); 227 free(dev); 228 return NULL; 229 } 230 } 231 232 log_Printf(LogPHASE, "%s: Connecting to %s:%s/udp\n", p->link.name, 233 host, port); 234 235 p->fd = socket(PF_INET, SOCK_DGRAM, 0); 236 if (p->fd >= 0) { 237 log_Printf(LogDEBUG, "%s: Opened udp socket %s\n", p->link.name, 238 p->name.full); 239 if (connect(p->fd, (struct sockaddr *)&dev->sock, sizeof dev->sock) == 0) { 240 dev->connected = UDP_CONNECTED; 241 return dev; 242 } else 243 log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); 244 } else 245 log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); 246 247 close(p->fd); 248 p->fd = -1; 249 free(dev); 250 251 return NULL; 252 } 253 254 struct device * 255 udp_Create(struct physical *p) 256 { 257 char *cp, *host, *port, *svc; 258 struct udpdevice *dev; 259 260 dev = NULL; 261 if (p->fd < 0) { 262 if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) { 263 *cp = '\0'; 264 host = p->name.full; 265 port = cp + 1; 266 svc = strchr(port, '/'); 267 if (svc && strcasecmp(svc, "/udp")) { 268 *cp = ':'; 269 return NULL; 270 } 271 if (svc) { 272 p->fd--; /* We own the device but maybe can't use it - change fd */ 273 *svc = '\0'; 274 } 275 276 if (*host && *port) 277 dev = udp_CreateDevice(p, host, port); 278 279 *cp = ':'; 280 if (svc) 281 *svc = '/'; 282 } 283 } else { 284 /* See if we're a connected udp socket */ 285 struct stat st; 286 287 if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) { 288 int type, sz; 289 290 sz = sizeof type; 291 if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) { 292 log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name); 293 close(p->fd); 294 p->fd = -1; 295 return NULL; 296 } 297 298 if (sz == sizeof type && type == SOCK_DGRAM) { 299 struct sockaddr_in sock; 300 struct sockaddr *sockp = (struct sockaddr *)&sock; 301 302 if ((dev = malloc(sizeof *dev)) == NULL) { 303 log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 304 p->link.name, strerror(errno)); 305 return NULL; 306 } 307 308 if (getpeername(p->fd, sockp, &sz) == 0) { 309 log_Printf(LogPHASE, "%s: Link is a connected udp socket\n", 310 p->link.name); 311 dev->connected = UDP_CONNECTED; 312 } else { 313 log_Printf(LogPHASE, "%s: Link is a disconnected udp socket\n", 314 p->link.name); 315 316 dev->connected = UDP_MAYBEUNCONNECTED; 317 318 if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) { 319 log_Printf(LogPHASE, "%s: Changing openmode to PASSIVE\n", 320 p->link.name); 321 p->link.lcp.cfg.openmode = OPEN_PASSIVE; 322 } 323 } 324 } 325 } 326 } 327 328 if (dev) { 329 memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 330 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 331 if (p->cfg.cd.necessity != CD_DEFAULT) 332 log_Printf(LogWARN, "Carrier settings ignored\n"); 333 return &dev->dev; 334 } 335 336 return NULL; 337 } 338