15d9e6103SBrian Somers /*- 25d9e6103SBrian Somers * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 35d9e6103SBrian Somers * All rights reserved. 45d9e6103SBrian Somers * 55d9e6103SBrian Somers * Redistribution and use in source and binary forms, with or without 65d9e6103SBrian Somers * modification, are permitted provided that the following conditions 75d9e6103SBrian Somers * are met: 85d9e6103SBrian Somers * 1. Redistributions of source code must retain the above copyright 95d9e6103SBrian Somers * notice, this list of conditions and the following disclaimer. 105d9e6103SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 115d9e6103SBrian Somers * notice, this list of conditions and the following disclaimer in the 125d9e6103SBrian Somers * documentation and/or other materials provided with the distribution. 135d9e6103SBrian Somers * 145d9e6103SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 155d9e6103SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 165d9e6103SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 175d9e6103SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 185d9e6103SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 195d9e6103SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 205d9e6103SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 215d9e6103SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 225d9e6103SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 235d9e6103SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 245d9e6103SBrian Somers * SUCH DAMAGE. 255d9e6103SBrian Somers * 2697d92980SPeter Wemm * $FreeBSD$ 275d9e6103SBrian Somers */ 285d9e6103SBrian Somers 295d9e6103SBrian Somers #include <sys/types.h> 305d9e6103SBrian Somers #include <sys/socket.h> 315d9e6103SBrian Somers #include <netinet/in.h> 325d9e6103SBrian Somers #include <arpa/inet.h> 335d9e6103SBrian Somers #include <netdb.h> 345d9e6103SBrian Somers 355d9e6103SBrian Somers #include <errno.h> 365d9e6103SBrian Somers #include <stdio.h> 375d9e6103SBrian Somers #include <stdlib.h> 385d9e6103SBrian Somers #include <string.h> 39165fbe26SBrian Somers #include <sys/stat.h> 40f5a99677SBrian Somers #include <sys/uio.h> 415d9e6103SBrian Somers #include <termios.h> 425d9e6103SBrian Somers #include <unistd.h> 435d9e6103SBrian Somers 445d9e6103SBrian Somers #include "layer.h" 455d9e6103SBrian Somers #include "defs.h" 465d9e6103SBrian Somers #include "mbuf.h" 475d9e6103SBrian Somers #include "log.h" 485d9e6103SBrian Somers #include "timer.h" 495d9e6103SBrian Somers #include "lqr.h" 505d9e6103SBrian Somers #include "hdlc.h" 515d9e6103SBrian Somers #include "throughput.h" 525d9e6103SBrian Somers #include "fsm.h" 535d9e6103SBrian Somers #include "lcp.h" 545d9e6103SBrian Somers #include "ccp.h" 555d9e6103SBrian Somers #include "link.h" 565d9e6103SBrian Somers #include "async.h" 575d9e6103SBrian Somers #include "descriptor.h" 585d9e6103SBrian Somers #include "physical.h" 595d9e6103SBrian Somers #include "tcp.h" 605d9e6103SBrian Somers 615d9e6103SBrian Somers static int 626815097bSBrian Somers tcp_OpenConnection(const char *name, char *host, char *port) 635d9e6103SBrian Somers { 645d9e6103SBrian Somers struct sockaddr_in dest; 655d9e6103SBrian Somers int sock; 665d9e6103SBrian Somers struct servent *sp; 675d9e6103SBrian Somers 685d9e6103SBrian Somers dest.sin_family = AF_INET; 695d9e6103SBrian Somers dest.sin_addr.s_addr = inet_addr(host); 705d9e6103SBrian Somers dest.sin_addr = GetIpAddr(host); 715d9e6103SBrian Somers if (dest.sin_addr.s_addr == INADDR_NONE) { 725d9e6103SBrian Somers log_Printf(LogWARN, "%s: %s: unknown host\n", name, host); 73bcff3386SBrian Somers return -2; 745d9e6103SBrian Somers } 755d9e6103SBrian Somers dest.sin_port = htons(atoi(port)); 765d9e6103SBrian Somers if (dest.sin_port == 0) { 775d9e6103SBrian Somers sp = getservbyname(port, "tcp"); 786815097bSBrian Somers if (sp) 795d9e6103SBrian Somers dest.sin_port = sp->s_port; 806815097bSBrian Somers else { 815d9e6103SBrian Somers log_Printf(LogWARN, "%s: %s: unknown service\n", name, port); 82bcff3386SBrian Somers return -2; 835d9e6103SBrian Somers } 845d9e6103SBrian Somers } 856815097bSBrian Somers log_Printf(LogPHASE, "%s: Connecting to %s:%s/tcp\n", name, host, port); 865d9e6103SBrian Somers 8763c6cac9SBrian Somers sock = socket(PF_INET, SOCK_STREAM, 0); 886815097bSBrian Somers if (sock < 0) 89bcff3386SBrian Somers return -2; 906815097bSBrian Somers 915d9e6103SBrian Somers if (connect(sock, (struct sockaddr *)&dest, sizeof dest) < 0) { 925d9e6103SBrian Somers log_Printf(LogWARN, "%s: connect: %s\n", name, strerror(errno)); 935d9e6103SBrian Somers close(sock); 94bcff3386SBrian Somers return -2; 955d9e6103SBrian Somers } 965d9e6103SBrian Somers 976815097bSBrian Somers return sock; 985d9e6103SBrian Somers } 995d9e6103SBrian Somers 1006815097bSBrian Somers static struct device tcpdevice = { 1016815097bSBrian Somers TCP_DEVICE, 1025d9e6103SBrian Somers "tcp", 103c8b9fb53SBrian Somers 0, 104fdc29d54SBrian Somers { CD_NOTREQUIRED, 0 }, 1056815097bSBrian Somers NULL, 1066815097bSBrian Somers NULL, 1076815097bSBrian Somers NULL, 1085d9e6103SBrian Somers NULL, 1095d9e6103SBrian Somers NULL, 1105d9e6103SBrian Somers NULL, 1115d9e6103SBrian Somers NULL, 1125d9e6103SBrian Somers NULL, 1135d9e6103SBrian Somers NULL, 114eb6e5e05SBrian Somers NULL, 11587c3786eSBrian Somers NULL, 116fb11a9c2SBrian Somers NULL, 1175d9e6103SBrian Somers NULL 1185d9e6103SBrian Somers }; 1196815097bSBrian Somers 1206815097bSBrian Somers struct device * 1216815097bSBrian Somers tcp_iov2device(int type, struct physical *p, struct iovec *iov, 12287c3786eSBrian Somers int *niov, int maxiov, int *auxfd, int *nauxfd) 1236815097bSBrian Somers { 124acbd1f00SBrian Somers if (type == TCP_DEVICE) { 125f5a99677SBrian Somers free(iov[(*niov)++].iov_base); 126acbd1f00SBrian Somers physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC); 1276815097bSBrian Somers return &tcpdevice; 128acbd1f00SBrian Somers } 1296815097bSBrian Somers 1306815097bSBrian Somers return NULL; 1316815097bSBrian Somers } 1326815097bSBrian Somers 1336815097bSBrian Somers struct device * 1346815097bSBrian Somers tcp_Create(struct physical *p) 1356815097bSBrian Somers { 1366815097bSBrian Somers char *cp, *host, *port, *svc; 1376815097bSBrian Somers 1386815097bSBrian Somers if (p->fd < 0) { 13987c3786eSBrian Somers if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) { 1406815097bSBrian Somers *cp = '\0'; 1416815097bSBrian Somers host = p->name.full; 1426815097bSBrian Somers port = cp + 1; 1436815097bSBrian Somers svc = strchr(port, '/'); 1446815097bSBrian Somers if (svc && strcasecmp(svc, "/tcp")) { 1456815097bSBrian Somers *cp = ':'; 1466815097bSBrian Somers return 0; 1476815097bSBrian Somers } 14887c3786eSBrian Somers if (svc) { 14987c3786eSBrian Somers p->fd--; /* We own the device but maybe can't use it - change fd */ 1506815097bSBrian Somers *svc = '\0'; 15187c3786eSBrian Somers } 1526815097bSBrian Somers if (*host && *port) { 1536815097bSBrian Somers p->fd = tcp_OpenConnection(p->link.name, host, port); 1546815097bSBrian Somers *cp = ':'; 1556815097bSBrian Somers if (svc) 1566815097bSBrian Somers *svc = '/'; 1576815097bSBrian Somers if (p->fd >= 0) 1586815097bSBrian Somers log_Printf(LogDEBUG, "%s: Opened tcp socket %s\n", p->link.name, 1596815097bSBrian Somers p->name.full); 1606815097bSBrian Somers } else { 1616815097bSBrian Somers if (svc) 1626815097bSBrian Somers *svc = '/'; 1636815097bSBrian Somers *cp = ':'; 1646815097bSBrian Somers } 1656815097bSBrian Somers } 1666815097bSBrian Somers } 1676815097bSBrian Somers 1686815097bSBrian Somers if (p->fd >= 0) { 1696815097bSBrian Somers /* See if we're a tcp socket */ 170165fbe26SBrian Somers struct stat st; 171165fbe26SBrian Somers 172165fbe26SBrian Somers if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) { 173165fbe26SBrian Somers int type, sz; 1746815097bSBrian Somers 1756815097bSBrian Somers sz = sizeof type; 176165fbe26SBrian Somers if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) { 177165fbe26SBrian Somers log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name); 178165fbe26SBrian Somers close(p->fd); 179165fbe26SBrian Somers p->fd = -1; 180165fbe26SBrian Somers return NULL; 181165fbe26SBrian Somers } 182165fbe26SBrian Somers 183165fbe26SBrian Somers if (sz == sizeof type && type == SOCK_STREAM) { 1846815097bSBrian Somers struct sockaddr_in sock; 1856815097bSBrian Somers struct sockaddr *sockp = (struct sockaddr *)&sock; 1866815097bSBrian Somers 1876815097bSBrian Somers if (*p->name.full == '\0') { 1886815097bSBrian Somers sz = sizeof sock; 1896815097bSBrian Somers if (getpeername(p->fd, sockp, &sz) != 0 || 1906815097bSBrian Somers sz != sizeof(struct sockaddr_in) || sock.sin_family != AF_INET) { 1916815097bSBrian Somers log_Printf(LogDEBUG, "%s: Link is SOCK_STREAM, but not inet\n", 1926815097bSBrian Somers p->link.name); 1936815097bSBrian Somers return NULL; 1946815097bSBrian Somers } 1956815097bSBrian Somers 1966815097bSBrian Somers log_Printf(LogPHASE, "%s: Link is a tcp socket\n", p->link.name); 1976815097bSBrian Somers 1986815097bSBrian Somers snprintf(p->name.full, sizeof p->name.full, "%s:%d/tcp", 1996815097bSBrian Somers inet_ntoa(sock.sin_addr), ntohs(sock.sin_port)); 2006815097bSBrian Somers p->name.base = p->name.full; 2016815097bSBrian Somers } 202acbd1f00SBrian Somers physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC); 203fdc29d54SBrian Somers if (p->cfg.cd.necessity != CD_DEFAULT) 204fdc29d54SBrian Somers log_Printf(LogWARN, "Carrier settings ignored\n"); 2056815097bSBrian Somers return &tcpdevice; 2066815097bSBrian Somers } 2076815097bSBrian Somers } 208165fbe26SBrian Somers } 2096815097bSBrian Somers 2106815097bSBrian Somers return NULL; 2116815097bSBrian Somers } 212