kernel - Fix auto port assignment collision in network code
[dragonfly.git] / usr.sbin / ppp / tcp.c
blob84d4abced5e5543c23732f6bf7a0a7c1b2920e94
1 /*-
2 * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
3 * All rights reserved.
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.
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.
26 * $FreeBSD: src/usr.sbin/ppp/tcp.c,v 1.10.2.4 2002/09/01 02:12:32 brian Exp $
27 * $DragonFly: src/usr.sbin/ppp/tcp.c,v 1.2 2003/06/17 04:30:01 dillon Exp $
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netdb.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/stat.h>
41 #include <sys/uio.h>
42 #include <termios.h>
43 #include <unistd.h>
45 #include "layer.h"
46 #include "defs.h"
47 #include "mbuf.h"
48 #include "log.h"
49 #include "timer.h"
50 #include "lqr.h"
51 #include "hdlc.h"
52 #include "throughput.h"
53 #include "fsm.h"
54 #include "lcp.h"
55 #include "ccp.h"
56 #include "link.h"
57 #include "async.h"
58 #include "descriptor.h"
59 #include "physical.h"
60 #include "tcp.h"
62 static int
63 tcp_OpenConnection(const char *name, char *host, char *port)
65 struct sockaddr_in dest;
66 int sock;
67 struct servent *sp;
69 dest.sin_family = AF_INET;
70 dest.sin_addr = GetIpAddr(host);
71 if (dest.sin_addr.s_addr == INADDR_NONE) {
72 log_Printf(LogWARN, "%s: %s: unknown host\n", name, host);
73 return -2;
75 dest.sin_port = htons(atoi(port));
76 if (dest.sin_port == 0) {
77 sp = getservbyname(port, "tcp");
78 if (sp)
79 dest.sin_port = sp->s_port;
80 else {
81 log_Printf(LogWARN, "%s: %s: unknown service\n", name, port);
82 return -2;
85 log_Printf(LogPHASE, "%s: Connecting to %s:%s/tcp\n", name, host, port);
87 sock = socket(PF_INET, SOCK_STREAM, 0);
88 if (sock < 0)
89 return -2;
91 if (connect(sock, (struct sockaddr *)&dest, sizeof dest) < 0) {
92 log_Printf(LogWARN, "%s: connect: %s\n", name, strerror(errno));
93 close(sock);
94 return -2;
97 return sock;
100 static struct device tcpdevice = {
101 TCP_DEVICE,
102 "tcp",
104 { CD_NOTREQUIRED, 0 },
105 NULL,
106 NULL,
107 NULL,
108 NULL,
109 NULL,
110 NULL,
111 NULL,
112 NULL,
113 NULL,
114 NULL,
115 NULL,
116 NULL,
117 NULL,
118 NULL
121 struct device *
122 tcp_iov2device(int type, struct physical *p, struct iovec *iov,
123 int *niov, int maxiov __unused, int *auxfd __unused, int *nauxfd __unused)
125 if (type == TCP_DEVICE) {
126 free(iov[(*niov)++].iov_base);
127 physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC);
128 return &tcpdevice;
131 return NULL;
134 struct device *
135 tcp_Create(struct physical *p)
137 char *cp, *host, *port, *svc;
139 if (p->fd < 0) {
140 if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) {
141 *cp = '\0';
142 host = p->name.full;
143 port = cp + 1;
144 svc = strchr(port, '/');
145 if (svc && strcasecmp(svc, "/tcp")) {
146 *cp = ':';
147 return 0;
149 if (svc) {
150 p->fd--; /* We own the device but maybe can't use it - change fd */
151 *svc = '\0';
153 if (*host && *port) {
154 p->fd = tcp_OpenConnection(p->link.name, host, port);
155 *cp = ':';
156 if (svc)
157 *svc = '/';
158 if (p->fd >= 0)
159 log_Printf(LogDEBUG, "%s: Opened tcp socket %s\n", p->link.name,
160 p->name.full);
161 } else {
162 if (svc)
163 *svc = '/';
164 *cp = ':';
169 if (p->fd >= 0) {
170 /* See if we're a tcp socket */
171 struct stat st;
173 if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) {
174 int type, sz;
176 sz = sizeof type;
177 if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) {
178 log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name);
179 close(p->fd);
180 p->fd = -1;
181 return NULL;
184 if (sz == sizeof type && type == SOCK_STREAM) {
185 struct sockaddr_in sock;
186 struct sockaddr *sockp = (struct sockaddr *)&sock;
188 if (*p->name.full == '\0') {
189 sz = sizeof sock;
190 if (getpeername(p->fd, sockp, &sz) != 0 ||
191 sz != sizeof(struct sockaddr_in) || sock.sin_family != AF_INET) {
192 log_Printf(LogDEBUG, "%s: Link is SOCK_STREAM, but not inet\n",
193 p->link.name);
194 return NULL;
197 log_Printf(LogPHASE, "%s: Link is a tcp socket\n", p->link.name);
199 snprintf(p->name.full, sizeof p->name.full, "%s:%d/tcp",
200 inet_ntoa(sock.sin_addr), ntohs(sock.sin_port));
201 p->name.base = p->name.full;
203 physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC);
204 if (p->cfg.cd.necessity != CD_DEFAULT)
205 log_Printf(LogWARN, "Carrier settings ignored\n");
206 return &tcpdevice;
211 return NULL;