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