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