xref: /freebsd/usr.sbin/ppp/udp.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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