NET_LIB_PATH = lib
NET_LIB_NAME = net-tools
-PROGS = ifconfig hostname arp netstat route rarp
+PROGS = ifconfig hostname arp netstat route rarp slattach plipconfig iptunnel ipmaddr
# Compiler and Linker Options
# You may need to uncomment and edit these if you are using libc5 and IPv6.
subdirs:
@for i in $(SUBDIRS); do $(MAKE) -C $$i $(MDEFINES) ; done
-ifconfig: $(NET-LIB) ifconfig.o interface.o sockets.o
- $(CC) $(LDFLAGS) -o ifconfig ifconfig.o interface.o sockets.o $(NLIB) $(RESLIB)
+ifconfig: $(NET-LIB) ifconfig.o
+ $(CC) $(LDFLAGS) -o ifconfig ifconfig.o $(NLIB) $(RESLIB)
hostname: hostname.o
$(CC) $(LDFLAGS) -o hostname hostname.o
rarp: $(NET-LIB) rarp.o
$(CC) $(LDFLAGS) -o rarp rarp.o $(NLIB)
-netstat: $(NET-LIB) netstat.o statistics.o interface.o sockets.o
- $(CC) $(LDFLAGS) -o netstat netstat.o statistics.o interface.o sockets.o $(NLIB) $(RESLIB)
+slattach: $(NET-LIB) slattach.o
+ $(CC) $(LDFLAGS) -o slattach slattach.o $(NLIB)
+
+plipconfig: $(NET-LIB) plipconfig.o
+ $(CC) $(LDFLAGS) -o plipconfig plipconfig.o $(NLIB)
+
+netstat: $(NET-LIB) netstat.o statistics.o
+ $(CC) $(LDFLAGS) -o netstat netstat.o statistics.o $(NLIB) $(RESLIB)
+
+iptunnel: $(NET-LIB) iptunnel.o
+ $(CC) $(LDFLAGS) -o iptunnel iptunnel.o $(NLIB) $(RESLIB)
+
+ipmaddr: $(NET-LIB) ipmaddr.o
+ $(CC) $(LDFLAGS) -o ipmaddr ipmaddr.o $(NLIB) $(RESLIB)
installbin:
install -m 0755 -d ${BASEDIR}/sbin
sockets.
- netstat -s is improved.
- route/netstat -r display the routing cache correctly.
+ - plipconfig and slattach are included in the distribution.
Notable changes since 1.48 include:
Phil Blundell
philb@gnu.org
-11th December 1998
Bernd Eckenfels
net-tools@lina.inka.de
-1999-01-02
--- /dev/null
+struct user_net_device_stats {
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes; /* total bytes received */
+ unsigned long tx_bytes; /* total bytes transmitted */
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long rx_multicast; /* multicast packets received */
+ unsigned long rx_compressed;
+ unsigned long tx_compressed;
+ unsigned long collisions;
+
+ /* detailed rx_errors: */
+ unsigned long rx_length_errors;
+ unsigned long rx_over_errors; /* receiver ring buff overflow */
+ unsigned long rx_crc_errors; /* recved pkt with crc error */
+ unsigned long rx_frame_errors; /* recv'd frame alignment error */
+ unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+ unsigned long rx_missed_errors; /* receiver missed packet */
+ /* detailed tx_errors */
+ unsigned long tx_aborted_errors;
+ unsigned long tx_carrier_errors;
+ unsigned long tx_fifo_errors;
+ unsigned long tx_heartbeat_errors;
+ unsigned long tx_window_errors;
+};
+
+struct interface {
+ struct interface *next;
+
+ char name[IFNAMSIZ]; /* interface name */
+ short type; /* if type */
+ short flags; /* various flags */
+ int metric; /* routing metric */
+ int mtu; /* MTU value */
+ int tx_queue_len; /* transmit queue length */
+ struct ifmap map; /* hardware setup */
+ struct sockaddr addr; /* IP address */
+ struct sockaddr dstaddr; /* P-P IP address */
+ struct sockaddr broadaddr; /* IP broadcast address */
+ struct sockaddr netmask; /* IP network mask */
+ struct sockaddr ipxaddr_bb; /* IPX network address */
+ struct sockaddr ipxaddr_sn; /* IPX network address */
+ struct sockaddr ipxaddr_e3; /* IPX network address */
+ struct sockaddr ipxaddr_e2; /* IPX network address */
+ struct sockaddr ddpaddr; /* Appletalk DDP address */
+ struct sockaddr ecaddr; /* Econet address */
+ int has_ip;
+ int has_ipx_bb;
+ int has_ipx_sn;
+ int has_ipx_e3;
+ int has_ipx_e2;
+ int has_ax25;
+ int has_ddp;
+ int has_econet;
+ char hwaddr[32]; /* HW address */
+ int statistics_valid;
+ struct user_net_device_stats stats; /* statistics */
+ int keepalive; /* keepalive value for SLIP */
+ int outfill; /* outfill value for SLIP */
+};
+
+extern int if_fetch(struct interface *ife);
+
+extern int for_all_interfaces(int (*)(struct interface *, void *), void *);
+extern struct interface *lookup_interface(char *name);
+extern int if_readlist(void);
+
+extern int do_if_fetch(struct interface *ife);
+extern int do_if_print(struct interface *ife, void *cookie);
+
+extern void ife_print(struct interface *ptr);
+
+/* Defines for poor glibc2.0 users, the feature check is done at runtime */
+#if !defined(SIOCSIFTXQLEN)
+#define SIOCSIFTXQLEN 0x8943
+#define SIOCGIFTXQLEN 0x8942
+#endif
+
+#if !defined(ifr_qlen)
+/* Actually it is ifru_ivalue, but that is not present in 2.0 kernel headers */
+#define ifr_qlen ifr_ifru.ifru_mtu
+#endif
+
+#define HAVE_TXQUEUELEN
+
+#define HAVE_DYNAMIC
+#ifndef IFF_DYNAMIC
+#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
+#endif
--- /dev/null
+extern int skfd, ipx_sock, ax25_sock, rose_sock, inet_sock, inet6_sock,
+ ddp_sock, ec_sock;
+
+extern int sockets_open(int family);
--- /dev/null
+#ifndef __UTILS_H__
+#define __UTILS_H__ 1
+
+#if 0
+#include <asm/types.h>
+#include <asm/bitops.h>
+#include <linux/inetdevice.h>
+#include <resolv.h>
+#endif
+
+extern int preferred_family;
+extern int show_stats;
+extern int show_details;
+extern int show_raw;
+extern int resolve_hosts;
+
+#ifndef IPPROTO_ESP
+#define IPPROTO_ESP 50
+#endif
+#ifndef IPPROTO_AH
+#define IPPROTO_AH 51
+#endif
+
+#define SPRINT_BSIZE 64
+#define SPRINT_BUF(x) char x[SPRINT_BSIZE]
+
+
+#define NEXT_ARG() \
+argv++; \
+if (--argc <= 0) \
+ usage();
+
+typedef struct
+{
+ __u8 family;
+ __u8 bytelen;
+ __s16 bitlen;
+ __u32 data[4];
+} inet_prefix;
+
+extern __u32 get_addr32(char *name);
+extern int get_addr_1(inet_prefix *dst, char *arg, int family);
+extern int get_prefix_1(inet_prefix *dst, char *arg, int family);
+extern int get_addr(inet_prefix *dst, char *arg, int family);
+extern int get_prefix(inet_prefix *dst, char *arg, int family);
+
+extern int scan_number(char *arg, unsigned *val);
+
+extern int get_integer(int *val, char *arg, int base);
+extern int get_unsigned(unsigned *val, char *arg, int base);
+#define get_byte get_u8
+#define get_ushort get_u16
+#define get_short get_s16
+extern int get_u32(__u32 *val, char *arg, int base);
+extern int get_u16(__u16 *val, char *arg, int base);
+extern int get_s16(__s16 *val, char *arg, int base);
+extern int get_u8(__u8 *val, char *arg, int base);
+extern int get_s8(__s8 *val, char *arg, int base);
+
+extern int get_tc_classid(__u32 *h, char *str);
+extern int print_tc_classid(char *buf, int len, __u32 h);
+extern char * sprint_tc_classid(__u32 h, char *buf);
+
+/* static void usage(void) __attribute__((noreturn)); */
+void invarg(char *) __attribute__((noreturn));
+int matches(char *arg, char *pattern);
+extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits);
+
+extern int ipaddr_list(int argc, char **argv);
+extern int iproute_monitor(int argc, char **argv);
+extern int do_ipaddr(int argc, char **argv);
+extern int do_iproute(int argc, char **argv);
+extern int do_iprule(int argc, char **argv);
+extern int do_ipneigh(int argc, char **argv);
+extern int do_iptunnel(int argc, char **argv);
+extern int do_iplink(int argc, char **argv);
+extern int do_ipmonitor(int argc, char **argv);
+extern int do_multiaddr(int argc, char **argv);
+extern int do_qdisc(int argc, char **argv);
+extern int do_class(int argc, char **argv);
+extern int do_filter(int argc, char **argv);
+
+extern const char *format_host(int af, void *addr, __u8 *abuf, int alen);
+
+#endif /* __UTILS_H__ */
--- /dev/null
+/*
+ * ipmaddr.c "ip maddress".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/sockios.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+
+char filter_dev[16];
+int filter_family;
+
+/* These have nothing to do with rtnetlink. :-) */
+#define NEWADDR 1
+#define DELADDR 2
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ipmaddr [ add | del ] MULTIADDR dev STRING\n");
+ fprintf(stderr, " ipmaddr show [ dev STRING ] [ ipv4 | ipv6 | link | all ]\n");
+ exit(-1);
+}
+
+static void print_lla(FILE *fp, int len, unsigned char *addr)
+{
+ int i;
+ for (i=0; i<len; i++) {
+ if (i==0)
+ fprintf(fp, "%02x", addr[i]);
+ else
+ fprintf(fp, ":%02x", addr[i]);
+ }
+}
+
+static int parse_lla(char *str, unsigned char *addr)
+{
+ int len=0;
+
+ while (*str) {
+ int tmp;
+ if (str[0] == ':' || str[0] == '.') {
+ str++;
+ continue;
+ }
+ if (str[1] == 0)
+ return -1;
+ if (sscanf(str, "%02x", &tmp) != 1)
+ return -1;
+ addr[len] = tmp;
+ len++;
+ str += 2;
+ }
+ return len;
+}
+
+static int parse_hex(char *str, unsigned char *addr)
+{
+ int len=0;
+
+ while (*str) {
+ int tmp;
+ if (str[1] == 0)
+ return -1;
+ if (sscanf(str, "%02x", &tmp) != 1)
+ return -1;
+ addr[len] = tmp;
+ len++;
+ str += 2;
+ }
+ return len;
+}
+
+struct ma_info
+{
+ struct ma_info *next;
+ int index;
+ int users;
+ char *features;
+ char name[IFNAMSIZ];
+ inet_prefix addr;
+};
+
+void maddr_ins(struct ma_info **lst, struct ma_info *m)
+{
+ struct ma_info *mp;
+
+ for (; (mp=*lst) != NULL; lst = &mp->next) {
+ if (mp->index > m->index)
+ break;
+ }
+ m->next = *lst;
+ *lst = m;
+}
+
+void read_dev_mcast(struct ma_info **result_p)
+{
+ char buf[256];
+ FILE *fp = fopen("/proc/net/dev_mcast", "r");
+
+ if (!fp)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char hexa[256];
+ struct ma_info m;
+ int len;
+ int st;
+
+ memset(&m, 0, sizeof(m));
+ sscanf(buf, "%d%s%d%d%s", &m.index, m.name, &m.users, &st,
+ hexa);
+ if (filter_dev[0] && strcmp(filter_dev, m.name))
+ continue;
+
+ m.addr.family = AF_PACKET;
+
+ len = parse_hex(hexa, (unsigned char*)&m.addr.data);
+ if (len >= 0) {
+ struct ma_info *ma = malloc(sizeof(m));
+
+ memcpy(ma, &m, sizeof(m));
+ ma->addr.bytelen = len;
+ ma->addr.bitlen = len<<3;
+ if (st)
+ ma->features = "static";
+ maddr_ins(result_p, ma);
+ }
+ }
+ fclose(fp);
+}
+
+void read_igmp(struct ma_info **result_p)
+{
+ struct ma_info m;
+ char buf[256];
+ FILE *fp = fopen("/proc/net/igmp", "r");
+
+ if (!fp)
+ return;
+ memset(&m, 0, sizeof(m));
+ fgets(buf, sizeof(buf), fp);
+
+ m.addr.family = AF_INET;
+ m.addr.bitlen = 32;
+ m.addr.bytelen = 4;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ struct ma_info *ma = malloc(sizeof(m));
+
+ if (buf[0] != '\t') {
+ sscanf(buf, "%d%s", &m.index, m.name);
+ continue;
+ }
+
+ if (filter_dev[0] && strcmp(filter_dev, m.name))
+ continue;
+
+ sscanf(buf, "%08x%d", (__u32*)&m.addr.data, &m.users);
+
+ ma = malloc(sizeof(m));
+ memcpy(ma, &m, sizeof(m));
+ maddr_ins(result_p, ma);
+ }
+ fclose(fp);
+}
+
+
+void read_igmp6(struct ma_info **result_p)
+{
+ char buf[256];
+ FILE *fp = fopen("/proc/net/igmp6", "r");
+
+ if (!fp)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char hexa[256];
+ struct ma_info m;
+ int len;
+
+ memset(&m, 0, sizeof(m));
+ sscanf(buf, "%d%s%s%d", &m.index, m.name, hexa, &m.users);
+
+ if (filter_dev[0] && strcmp(filter_dev, m.name))
+ continue;
+
+ m.addr.family = AF_INET6;
+
+ len = parse_hex(hexa, (unsigned char*)&m.addr.data);
+ if (len >= 0) {
+ struct ma_info *ma = malloc(sizeof(m));
+
+ memcpy(ma, &m, sizeof(m));
+
+ ma->addr.bytelen = len;
+ ma->addr.bitlen = len<<3;
+ maddr_ins(result_p, ma);
+ }
+ }
+ fclose(fp);
+}
+
+static void print_maddr(FILE *fp, struct ma_info *list)
+{
+ fprintf(fp, "\t");
+
+ if (list->addr.family == AF_PACKET) {
+ fprintf(fp, "link ");
+ print_lla(fp, list->addr.bytelen, (unsigned char*)list->addr.data);
+ } else {
+ char abuf[256];
+ switch(list->addr.family) {
+ case AF_INET:
+ fprintf(fp, "inet ");
+ break;
+ case AF_INET6:
+ fprintf(fp, "inet6 ");
+ break;
+ default:
+ fprintf(fp, "family %d ", list->addr.family);
+ break;
+ }
+ if (format_host(list->addr.family, list->addr.data, abuf, sizeof(abuf)))
+ fprintf(fp, "%s", abuf);
+ else
+ fprintf(fp, "?");
+ }
+ if (list->users != 1)
+ fprintf(fp, " users %d", list->users);
+ if (list->features)
+ fprintf(fp, " %s", list->features);
+ fprintf(fp, "\n");
+}
+
+static void print_mlist(FILE *fp, struct ma_info *list)
+{
+ int cur_index = 0;
+
+ for (; list; list = list->next) {
+ if (cur_index != list->index) {
+ cur_index = list->index;
+ fprintf(fp, "%d:\t%s\n", cur_index, list->name);
+ }
+ print_maddr(fp, list);
+ }
+}
+
+static int multiaddr_list(int argc, char **argv)
+{
+ struct ma_info *list = NULL;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (filter_dev[0])
+ usage();
+ strcpy(filter_dev, *argv);
+ } else if (strcmp(*argv, "all") == 0) {
+ filter_family = AF_UNSPEC;
+ } else if (strcmp(*argv, "ipv4") == 0) {
+ filter_family = AF_INET;
+ } else if (strcmp(*argv, "ipv6") == 0) {
+ filter_family = AF_INET6;
+ } else if (strcmp(*argv, "link") == 0) {
+ filter_family = AF_PACKET;
+ } else {
+ if (filter_dev[0])
+ usage();
+ strcpy(filter_dev, *argv);
+ }
+ argv++; argc--;
+ }
+
+ if (!filter_family || filter_family == AF_PACKET)
+ read_dev_mcast(&list);
+ if (!filter_family || filter_family == AF_INET)
+ read_igmp(&list);
+ if (!filter_family || filter_family == AF_INET6)
+ read_igmp6(&list);
+ print_mlist(stdout, list);
+ return 0;
+}
+
+int multiaddr_modify(int cmd, int argc, char **argv)
+{
+ struct ifreq ifr;
+ int fd;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (cmd == NEWADDR)
+ cmd = SIOCADDMULTI;
+ else
+ cmd = SIOCDELMULTI;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (ifr.ifr_name[0])
+ usage();
+ strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
+ } else {
+ if (ifr.ifr_hwaddr.sa_data[0])
+ usage();
+ if (parse_lla(*argv, ifr.ifr_hwaddr.sa_data) < 0)
+ usage();
+ }
+ argc--; argv++;
+ }
+ if (ifr.ifr_name[0] == 0)
+ usage();
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("Cannot create socket");
+ exit(1);
+ }
+ if (ioctl(fd, cmd, (char*)&ifr) != 0) {
+ perror("ioctl");
+ exit(1);
+ }
+ close(fd);
+
+ exit(0);
+}
+
+
+int do_multiaddr(int argc, char **argv)
+{
+ if (argc < 1)
+ return multiaddr_list(0, NULL);
+ if (matches(*argv, "add") == 0)
+ return multiaddr_modify(NEWADDR, argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return multiaddr_modify(DELADDR, argc-1, argv+1);
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return multiaddr_list(argc-1, argv+1);
+ usage();
+}
+
+int preferred_family = AF_UNSPEC;
+int show_stats = 0;
+int resolve_hosts = 0;
+
+int main(int argc, char **argv)
+{
+ char *basename;
+
+ basename = strrchr(argv[0], '/');
+ if (basename == NULL)
+ basename = argv[0];
+ else
+ basename++;
+
+ while (argc > 1) {
+ if (argv[1][0] != '-')
+ break;
+ if (matches(argv[1], "-family") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ if (strcmp(argv[1], "inet") == 0)
+ preferred_family = AF_INET;
+ else if (strcmp(argv[1], "inet6") == 0)
+ preferred_family = AF_INET6;
+ else
+ usage();
+ } else if (matches(argv[1], "-stats") == 0 ||
+ matches(argv[1], "-statistics") == 0) {
+ ++show_stats;
+ } else if (matches(argv[1], "-resolve") == 0) {
+ ++resolve_hosts;
+ } else
+ usage();
+ argc--; argv++;
+ }
+
+ return do_multiaddr(argc-1, argv+1);
+}
--- /dev/null
+/*
+ * iptunnel.c "ip tunnel"
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ *
+ * Changes:
+ *
+ * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
+ * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <linux/if_tunnel.h>
+
+#undef GRE_CSUM
+#define GRE_CSUM htons(0x8000)
+#undef GRE_ROUTING
+#define GRE_ROUTING htons(0x4000)
+#undef GRE_KEY
+#define GRE_KEY htons(0x2000)
+#undef GRE_SEQ
+#define GRE_SEQ htons(0x1000)
+#undef GRE_STRICT
+#define GRE_STRICT htons(0x0800)
+#undef GRE_REC
+#define GRE_REC htons(0x0700)
+#undef GRE_FLAGS
+#define GRE_FLAGS htons(0x00F8)
+#undef GRE_VERSION
+#define GRE_VERSION htons(0x0007)
+
+#include "utils.h"
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: iptunnel { add | change | del | show } [ NAME ]\n");
+ fprintf(stderr, " [ mode { ipip | gre | sit } ] [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ nopmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(stderr, " TOS := { NUMBER | inherit }\n");
+ fprintf(stderr, " TTL := { 1..255 | inherit }\n");
+ fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ exit(-1);
+}
+
+static int do_ioctl_get_ifindex(char *dev)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strcpy(ifr.ifr_name, dev);
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err) {
+ perror("ioctl");
+ return 0;
+ }
+ close(fd);
+ return ifr.ifr_ifindex;
+}
+
+static int do_ioctl_get_iftype(char *dev)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strcpy(ifr.ifr_name, dev);
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGIFHWADDR, &ifr);
+ if (err) {
+ perror("ioctl");
+ return -1;
+ }
+ close(fd);
+ return ifr.ifr_addr.sa_family;
+}
+
+
+static char * do_ioctl_get_ifname(int idx)
+{
+ static struct ifreq ifr;
+ int fd;
+ int err;
+
+ ifr.ifr_ifindex = idx;
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGIFNAME, &ifr);
+ if (err) {
+ perror("ioctl");
+ return NULL;
+ }
+ close(fd);
+ return ifr.ifr_name;
+}
+
+
+
+static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strcpy(ifr.ifr_name, basedev);
+ ifr.ifr_ifru.ifru_data = (void*)p;
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGETTUNNEL, &ifr);
+ if (err)
+ perror("ioctl");
+ close(fd);
+ return err;
+}
+
+static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strcpy(ifr.ifr_name, basedev);
+ ifr.ifr_ifru.ifru_data = (void*)p;
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ err = ioctl(fd, cmd, &ifr);
+ if (err)
+ perror("ioctl");
+ close(fd);
+ return err;
+}
+
+static int do_del_ioctl(char *basedev, struct ip_tunnel_parm *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strcpy(ifr.ifr_name, basedev);
+ ifr.ifr_ifru.ifru_data = (void*)p;
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCDELTUNNEL, &ifr);
+ if (err)
+ perror("ioctl");
+ close(fd);
+ return err;
+}
+
+static int parse_args(int argc, char **argv, struct ip_tunnel_parm *p)
+{
+ char medium[IFNAMSIZ];
+
+ memset(p, 0, sizeof(*p));
+ memset(&medium, 0, sizeof(medium));
+
+ p->iph.version = 4;
+ p->iph.ihl = 5;
+#ifndef IP_DF
+#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
+#endif
+ p->iph.frag_off = htons(IP_DF);
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "ipip") == 0) {
+ if (p->iph.protocol)
+ usage();
+ p->iph.protocol = IPPROTO_IPIP;
+ } else if (strcmp(*argv, "gre") == 0) {
+ if (p->iph.protocol)
+ usage();
+ p->iph.protocol = IPPROTO_GRE;
+ } else if (strcmp(*argv, "sit") == 0) {
+ if (p->iph.protocol)
+ usage();
+ p->iph.protocol = IPPROTO_IPV6;
+ } else
+ usage();
+ } else if (strcmp(*argv, "key") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = p->o_key = get_addr32(*argv);
+ else {
+ if (scan_number(*argv, &uval)<0)
+ usage();
+ p->i_key = p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "ikey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->o_key = get_addr32(*argv);
+ else {
+ if (scan_number(*argv, &uval)<0)
+ usage();
+ p->i_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "okey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->o_key = get_addr32(*argv);
+ else {
+ if (scan_number(*argv, &uval)<0)
+ usage();
+ p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "seq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "iseq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "oseq") == 0) {
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "csum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ p->o_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "icsum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "ocsum") == 0) {
+ p->o_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "nopmtudisc") == 0) {
+ p->iph.frag_off = 0;
+ } else if (strcmp(*argv, "remote") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ p->iph.daddr = get_addr32(*argv);
+ } else if (strcmp(*argv, "local") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ p->iph.saddr = get_addr32(*argv);
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(medium, *argv, IFNAMSIZ-1);
+ } else if (strcmp(*argv, "ttl") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (scan_number(*argv, &uval)<0)
+ usage();
+ if (uval > 255)
+ usage();
+ p->iph.ttl = uval;
+ }
+ } else if (strcmp(*argv, "tos") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (scan_number(*argv, &uval)<0)
+ usage();
+ if (uval > 255)
+ usage();
+ p->iph.tos = uval;
+ } else
+ p->iph.tos = 1;
+ } else {
+ if (p->name[0])
+ usage();
+ strncpy(p->name, *argv, IFNAMSIZ);
+ }
+ argc--; argv++;
+ }
+
+ if (p->iph.protocol == 0) {
+ if (memcmp(p->name, "gre", 3) == 0)
+ p->iph.protocol = IPPROTO_GRE;
+ else if (memcmp(p->name, "ipip", 4) == 0)
+ p->iph.protocol = IPPROTO_IPIP;
+ else if (memcmp(p->name, "sit", 3) == 0)
+ p->iph.protocol = IPPROTO_IPV6;
+ }
+
+ if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
+ if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
+ fprintf(stderr, "Keys are not allowed with ipip and sit.\n");
+ return -1;
+ }
+ }
+
+ if (medium[0]) {
+ p->link = do_ioctl_get_ifindex(medium);
+ if (p->link == 0)
+ return -1;
+ }
+
+ if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
+ p->i_key = p->iph.daddr;
+ p->i_flags |= GRE_KEY;
+ }
+ if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
+ p->o_key = p->iph.daddr;
+ p->o_flags |= GRE_KEY;
+ }
+ if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
+ fprintf(stderr, "Broadcast tunnel requires a source address.\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int do_add(int cmd, int argc, char **argv)
+{
+ struct ip_tunnel_parm p;
+
+ if (parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ if (p.iph.ttl && p.iph.frag_off == 0) {
+ fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
+ return -1;
+ }
+
+ switch (p.iph.protocol) {
+ case IPPROTO_IPIP:
+ return do_add_ioctl(cmd, "tunl0", &p);
+ case IPPROTO_GRE:
+ return do_add_ioctl(cmd, "gre0", &p);
+ case IPPROTO_IPV6:
+ return do_add_ioctl(cmd, "sit0", &p);
+ default:
+ fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n");
+ return -1;
+ }
+ return -1;
+}
+
+int do_del(int argc, char **argv)
+{
+ struct ip_tunnel_parm p;
+
+ if (parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ switch (p.iph.protocol) {
+ case IPPROTO_IPIP:
+ return do_del_ioctl(p.name[0] ? p.name : "tunl0", &p);
+ case IPPROTO_GRE:
+ return do_del_ioctl(p.name[0] ? p.name : "gre0", &p);
+ case IPPROTO_IPV6:
+ return do_del_ioctl(p.name[0] ? p.name : "sit0", &p);
+ default:
+ return do_del_ioctl(p.name, &p);
+ }
+ return -1;
+}
+
+void print_tunnel(struct ip_tunnel_parm *p)
+{
+ char s1[256];
+ char s2[256];
+ char s3[64];
+ char s4[64];
+
+ format_host(AF_INET, &p->iph.daddr, s1, sizeof(s1));
+ format_host(AF_INET, &p->iph.saddr, s2, sizeof(s2));
+ inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3));
+ inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4));
+
+ printf("%s: %s/ip remote %s local %s ",
+ p->name,
+ p->iph.protocol == IPPROTO_IPIP ? "ip" :
+ (p->iph.protocol == IPPROTO_GRE ? "gre" :
+ (p->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")),
+ p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any");
+ if (p->link) {
+ char *n = do_ioctl_get_ifname(p->link);
+ if (n)
+ printf(" dev %s ", n);
+ }
+ if (p->iph.ttl)
+ printf(" ttl %d ", p->iph.ttl);
+ else
+ printf(" ttl inherit ");
+ if (p->iph.tos) {
+ printf(" tos");
+ if (p->iph.tos&1)
+ printf(" inherit");
+ if (p->iph.tos&~1)
+ printf("%c%02x ", p->iph.tos&1 ? '/' : ' ', p->iph.tos&~1);
+ }
+ if (!(p->iph.frag_off&htons(IP_DF)))
+ printf(" nopmtudisc");
+
+ if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
+ printf(" key %s", s3);
+ else if ((p->i_flags|p->o_flags)&GRE_KEY) {
+ if (p->i_flags&GRE_KEY)
+ printf(" ikey %s ", s3);
+ if (p->o_flags&GRE_KEY)
+ printf(" okey %s ", s4);
+ }
+ printf("\n");
+
+ if (p->i_flags&GRE_SEQ)
+ printf(" Drop packets out of sequence.\n");
+ if (p->i_flags&GRE_CSUM)
+ printf(" Checksum in received packet is required.\n");
+ if (p->o_flags&GRE_SEQ)
+ printf(" Sequence packets on output.\n");
+ if (p->o_flags&GRE_CSUM)
+ printf(" Checksum output packets.\n");
+}
+
+static int do_tunnels_list(struct ip_tunnel_parm *p)
+{
+ char name[IFNAMSIZ];
+ unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
+ rx_fifo, rx_frame,
+ tx_bytes, tx_packets, tx_errs, tx_drops,
+ tx_fifo, tx_colls, tx_carrier, rx_multi;
+ int type;
+ struct ip_tunnel_parm p1;
+
+ char buf[512];
+ FILE *fp = fopen("/proc/net/dev", "r");
+ if (fp == NULL) {
+ perror("fopen");
+ return -1;
+ }
+
+ fgets(buf, sizeof(buf), fp);
+ fgets(buf, sizeof(buf), fp);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ char *ptr;
+ buf[sizeof(buf) - 1] = 0;
+ if ((ptr = strchr(buf, ':')) == NULL ||
+ (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
+ fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
+ return -1;
+ }
+ if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
+ &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
+ &rx_fifo, &rx_frame, &rx_multi,
+ &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
+ &tx_fifo, &tx_colls, &tx_carrier) != 14)
+ continue;
+ if (p->name[0] && strcmp(p->name, name))
+ continue;
+ type = do_ioctl_get_iftype(name);
+ if (type == -1) {
+ fprintf(stderr, "Failed to get type of [%s]\n", name);
+ continue;
+ }
+ if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
+ continue;
+ memset(&p1, 0, sizeof(p1));
+ if (do_get_ioctl(name, &p1))
+ continue;
+ if ((p->link && p1.link != p->link) ||
+ (p->name[0] && strcmp(p1.name, p->name)) ||
+ (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
+ (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
+ (p->i_key && p1.i_key != p->i_key))
+ continue;
+ print_tunnel(&p1);
+ if (show_stats) {
+ printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts\n");
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld\n",
+ rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi);
+ printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs\n");
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld\n\n",
+ tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+ }
+ }
+ return 0;
+}
+
+static int do_show(int argc, char **argv)
+{
+ int err;
+ struct ip_tunnel_parm p;
+
+ if (parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ switch (p.iph.protocol) {
+ case IPPROTO_IPIP:
+ err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
+ break;
+ case IPPROTO_GRE:
+ err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p);
+ break;
+ case IPPROTO_IPV6:
+ err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p);
+ break;
+ default:
+ do_tunnels_list(&p);
+ return 0;
+ }
+ if (err)
+ return -1;
+
+ print_tunnel(&p);
+ return 0;
+}
+
+int do_iptunnel(int argc, char **argv)
+{
+ if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return do_add(SIOCADDTUNNEL, argc-1, argv+1);
+ if (matches(*argv, "change") == 0)
+ return do_add(SIOCCHGTUNNEL, argc-1, argv+1);
+ if (matches(*argv, "del") == 0)
+ return do_del(argc-1, argv+1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show(argc-1, argv+1);
+ } else
+ return do_show(0, NULL);
+
+ usage();
+}
+
+
+int preferred_family = AF_UNSPEC;
+int show_stats = 0;
+int resolve_hosts = 0;
+
+int main(int argc, char **argv)
+{
+ char *basename;
+
+ basename = strrchr(argv[0], '/');
+ if (basename == NULL)
+ basename = argv[0];
+ else
+ basename++;
+
+ while (argc > 1) {
+ if (argv[1][0] != '-')
+ break;
+ if (matches(argv[1], "-family") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ if (strcmp(argv[1], "inet") == 0)
+ preferred_family = AF_INET;
+ else if (strcmp(argv[1], "inet6") == 0)
+ preferred_family = AF_INET6;
+ else
+ usage();
+ } else if (matches(argv[1], "-stats") == 0 ||
+ matches(argv[1], "-statistics") == 0) {
+ ++show_stats;
+ } else if (matches(argv[1], "-resolve") == 0) {
+ ++resolve_hosts;
+ } else
+ usage();
+ argc--; argv++;
+ }
+
+ return do_iptunnel(argc-1, argv+1);
+}
AFGROBJS = inet_gr.o inet6_gr.o ipx_gr.o ddp_gr.o netrom_gr.o ax25_gr.o rose_gr.o getroute.o
AFSROBJS = inet_sr.o inet6_sr.o netrom_sr.o ipx_sr.o setroute.o
ACTOBJS = slip_ac.o ppp_ac.o activate.o
-VARIA = getargs.o masq_info.o proc.o util.o nstrcmp.o
+VARIA = getargs.o masq_info.o proc.o util.o nstrcmp.o interface.o sockets.o utils.o
OBJS = $(sort $(VARIA) $(AFOBJS) $(HWOBJS) \
$(AFGROBJS) $(AFSROBJS) $(ACTOBJS))
10/1998 partly rewriten by Andi Kleen to support an interface list.
I don't claim that the list operations are efficient @).
- $Id: interface.c,v 1.15 1998/12/01 09:30:06 philip Exp $
+ $Id: interface.c,v 1.1 1999/01/09 14:36:36 philip Exp $
*/
#include "config.h"
--- /dev/null
+/*
+ * utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ *
+ * Changes:
+ *
+ * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <linux/pkt_sched.h>
+
+#include "utils.h"
+
+int scan_number(char *arg, unsigned *val)
+{
+ unsigned long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtoul(arg, &ptr, 0);
+ if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_integer(int *val, char *arg, int base)
+{
+ long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtol(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_unsigned(unsigned *val, char *arg, int base)
+{
+ unsigned long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtoul(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_u32(__u32 *val, char *arg, int base)
+{
+ unsigned long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtoul(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_u16(__u16 *val, char *arg, int base)
+{
+ unsigned long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtoul(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_u8(__u8 *val, char *arg, int base)
+{
+ unsigned long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtoul(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > 0xFF)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_s16(__s16 *val, char *arg, int base)
+{
+ long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtol(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_s8(__s8 *val, char *arg, int base)
+{
+ long res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtol(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+int get_tc_classid(__u32 *h, char *str)
+{
+ __u32 maj, min;
+ char *p;
+
+ maj = TC_H_ROOT;
+ if (strcmp(str, "root") == 0)
+ goto ok;
+ maj = TC_H_UNSPEC;
+ if (strcmp(str, "none") == 0)
+ goto ok;
+ maj = strtoul(str, &p, 16);
+ if (p == str) {
+ maj = 0;
+ if (*p != ':')
+ return -1;
+ }
+ if (*p == ':') {
+ maj <<= 16;
+ str = p+1;
+ min = strtoul(str, &p, 16);
+ if (*p != 0)
+ return -1;
+ maj |= min;
+ } else if (*p != 0)
+ return -1;
+
+ok:
+ *h = maj;
+ return 0;
+}
+
+int print_tc_classid(char *buf, int len, __u32 h)
+{
+ if (h == TC_H_ROOT)
+ sprintf(buf, "root");
+ else if (h == TC_H_UNSPEC)
+ snprintf(buf, len, "none");
+ else if (TC_H_MAJ(h) == 0)
+ snprintf(buf, len, ":%x", TC_H_MIN(h));
+ else if (TC_H_MIN(h) == 0)
+ snprintf(buf, len, "%x:", TC_H_MAJ(h)>>16);
+ else
+ snprintf(buf, len, "%x:%x", TC_H_MAJ(h)>>16, TC_H_MIN(h));
+ return 0;
+}
+
+char * sprint_tc_classid(__u32 h, char *buf)
+{
+ if (print_tc_classid(buf, SPRINT_BSIZE-1, h))
+ strcpy(buf, "???");
+ return buf;
+}
+
+
+int get_addr_1(inet_prefix *addr, char *name, int family)
+{
+ char *cp;
+ unsigned char *ap = (unsigned char*)addr->data;
+ int i;
+
+ memset(addr, 0, sizeof(*addr));
+
+ if (strcmp(name, "default") == 0 || strcmp(name, "any") == 0) {
+ addr->family = family;
+ addr->bytelen = (family == AF_INET6 ? 16 : 4);
+ addr->bitlen = -1;
+ return 0;
+ }
+
+ if (strchr(name, ':')) {
+ addr->family = AF_INET6;
+ if (family != AF_UNSPEC && family != AF_INET6)
+ return -1;
+ if (inet_pton(AF_INET6, name, addr->data) <= 0)
+ return -1;
+ addr->bytelen = 16;
+ addr->bitlen = -1;
+ return 0;
+ }
+
+ addr->family = AF_INET;
+ if (family != AF_UNSPEC && family != AF_INET)
+ return -1;
+ addr->bytelen = 4;
+ addr->bitlen = -1;
+ for (cp=name, i=0; *cp; cp++) {
+ if (*cp <= '9' && *cp >= '0') {
+ ap[i] = 10*ap[i] + (*cp-'0');
+ continue;
+ }
+ if (*cp == '.' && ++i <= 3)
+ continue;
+ return -1;
+ }
+ return 0;
+}
+
+int get_prefix_1(inet_prefix *dst, char *arg, int family)
+{
+ int err;
+ unsigned plen;
+ char *slash;
+
+ memset(dst, 0, sizeof(*dst));
+
+ if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) {
+ dst->family = family;
+ dst->bytelen = 0;
+ dst->bitlen = 0;
+ return 0;
+ }
+
+ slash = strchr(arg, '/');
+ if (slash)
+ *slash = 0;
+ err = get_addr_1(dst, arg, family);
+ if (err == 0) {
+ dst->bitlen = (dst->family == AF_INET6 ? 128 : 32);
+ if (slash) {
+ if (scan_number(slash+1, &plen) || plen > dst->bitlen) {
+ err = -1;
+ goto done;
+ }
+ dst->bitlen = plen;
+ }
+ }
+done:
+ if (slash)
+ *slash = '/';
+ return err;
+}
+
+int get_addr(inet_prefix *dst, char *arg, int family)
+{
+ if (get_addr_1(dst, arg, family)) {
+ fprintf(stderr, "ip: %s is invalid inet address\n", arg);
+ exit(1);
+ }
+ return 0;
+}
+
+int get_prefix(inet_prefix *dst, char *arg, int family)
+{
+ if (get_prefix_1(dst, arg, family)) {
+ fprintf(stderr, "ip: %s is invalid inet prefix\n", arg);
+ exit(1);
+ }
+ return 0;
+}
+
+__u32 get_addr32(char *name)
+{
+ inet_prefix addr;
+ if (get_addr_1(&addr, name, AF_INET)) {
+ fprintf(stderr, "ip: %s is invalid IPv4 address\n", name);
+ exit(1);
+ }
+ return addr.data[0];
+}
+
+void invarg(char *msg)
+{
+ fprintf(stderr, "ip: argument is wrong: %s\n", msg);
+ exit(1);
+}
+
+int matches(char *cmd, char *pattern)
+{
+ int len = strlen(cmd);
+ if (len > strlen(pattern))
+ return -1;
+ return memcmp(pattern, cmd, len);
+}
+
+int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits)
+{
+ __u32 *a1 = a->data;
+ __u32 *a2 = b->data;
+ int words = bits >> 0x05;
+
+ bits &= 0x1f;
+
+ if (words)
+ if (memcmp(a1, a2, words << 2))
+ return -1;
+
+ if (bits) {
+ __u32 w1, w2;
+ __u32 mask;
+
+ w1 = a1[words];
+ w2 = a2[words];
+
+ mask = htonl((0xffffffff) << (0x20 - bits));
+
+ if ((w1 ^ w2) & mask)
+ return 1;
+ }
+
+ return 0;
+}
+
+const char *format_host(int af, void *addr, __u8 *abuf, int alen)
+{
+#ifdef RESOLVE_HOSTNAMES
+ if (resolve_hosts) {
+ int addrlen = 0;
+ struct hostent *h_ent;
+ switch (af) {
+ case AF_INET:
+ addrlen = 4;
+ break;
+ case AF_INET6:
+ addrlen = 16;
+ break;
+ }
+ if (addrlen &&
+ (h_ent = gethostbyaddr(addr, addrlen, af)) != NULL) {
+ snprintf(abuf, alen-1, "%s", h_ent->h_name);
+ return abuf;
+ }
+ }
+#endif
+ return inet_ntop(af, addr, abuf, alen);
+}
--- /dev/null
+.TH PLIPCONFIG 8 "17 February 1995" "" ""
+.SH NAME
+plipconfig \- fine tune PLIP device parameters
+.SH SYNOPSIS
+.B "plipconfig interface"
+.br
+.B "plipconfig interface [nibble NN] [trigger NN] [unit NN]"
+.SH DESCRIPTION
+.B Plipconfig
+is used to (hopefully) improve PLIP performance by changing the default
+timing parameters used by the PLIP protocol. Results are dependent on
+the parallel port hardware, cable, and the CPU speed of each machine
+on each end of the PLIP link.
+.LP
+If the single
+.B interface
+argument is given,
+.B plipconfig
+displays the status of the given interface
+only. Otherwise, it will try to set the options.
+.SH OPTIONS
+.TP
+.B "nibble NN"
+Sets the nibble wait value in microseconds. Default is 3000.
+.TP
+.B "trigger NN"
+Sets the trigger wait value in microseconds. Default is 500.
+.LP
+PLIP speed can in some cases be improved by lowering the default values.
+Values which are too low may cause excess use of CPU, poor interrupt
+response time resulting in serial ports dropping characters, or in dropping
+of PLIP packets. Changing the plip MTU can also affect PLIP speed.
+.SH NOTE
+If you get no response it is far more likely the irq is wrong and needs
+setting with ifconfig. The few cases where the default parameters will
+be too fast are those using very long cables. Something you should
+never do as the parallel port is not specified or designed for driving
+long cable runs.
+.SH SEE ALSO
+.I ifconfig(8)
+.SH BUGS
+Non.
+.SH AUTHOR
+John Paul Morrison, <jmorriso@bogomips.ee.ubc.ca>, <ve7jpm@ve7jpm.ampr.org>
+
--- /dev/null
+.TH SLATTACH 8 "12 Feb 1994" "" ""
+.SH NAME
+slattach \- attach a network interface to a serial line
+.SH SYNOPSIS
+.B "slattach [-dehlLmnqv] [-c command] [-p proto] [-s speed] [tty]"
+.br
+.SH DESCRIPTION
+.B Slattach
+is a tiny little program that can be used to put a normal terminal
+("serial") line into one of several "network" modes, thus allowing
+you to use it for point-to-point links to other computers.
+.SH OPTIONS
+.TP
+.B "[-c command]"
+Execute
+.B command
+when the line is hung up. This can be used to run scripts or re-establish
+connections when a link goes down.
+.TP
+.B "[-d]"
+Enable debugging output. Useful when determining why a given
+setup doesn't work.
+.TP
+.B "[-h]"
+Exit when the carrier is lost. This works on both /dev/tty and /dev/cua
+devices by directly monitoring the carrier status every 15 seconds.
+.B "[-v]"
+Enable verbose output. Useful in shell scripts.
+.TP
+.B "[-q]"
+Operate in quiet mode - no messages at all.
+.TP
+.B "[-l]"
+Create an UUCP-style lockfile for the device in /var/lock.
+.TP
+.B "[-n]"
+Equivalent to the "mesg n" command.
+.TP
+.B "[-m]"
+Do \fBnot\fP initialize the line into 8 bits raw mode.
+.TP
+.B "[-e]"
+Exit right after initializing device, instead of waiting for the
+line to hangup.
+.TP
+.B "[-L]"
+Enable 3 wire operation. The terminal is moved into CLOCAL mode,
+carrier watching is disabled.
+.TP
+.B "[-p proto]"
+Set a specific kind of protocol to use on the line. The default
+is set to
+.B "cslip"
+, i.e. compressed SLIP. Other possible values are
+.B "slip"
+(normal SLIP),
+.B "adaptive"
+(adaptive CSLIP/SLIP),
+.B "ppp"
+(Point-to-Point Protocol)
+and
+.B "kiss"
+(a protocol used for communicating with AX.25 packet radio terminal node controllers).
+The special argument
+.B "tty"
+can be used to put the device back into normal serial operation.
+Using 'ppp' mode is not normally useful as ppp requires an additional ppp daemon
+.B pppd
+to be active on the line. For kiss connections the
+.B axattach
+program should be used.
+.TP
+.B "[-s speed]"
+Set a specific line speed, other than the default.
+.PP
+If no arguments are given, the current terminal line (usually: the
+login device) is used. Otherwise, an attempt is made to claim the
+indicated terminal port, lock it, and open it.
+.SH FILES
+.I /dev/cua* /var/lock/LCK.*
+.SH BUGS
+None known.
+.SH SEE ALSO
+axattach(8), dip(8) pppd(8), sliplogin(8).
+.SH AUTHORS
+Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+.br
+Alan Cox, <Alan.Cox@linux.org>
+.br
+Miquel van Smoorenburg, <miquels@drinkel.ow.org>
+.br
+George Shearer, <gshearer@one.net>
+.br
+Yossi Gottlieb, <yogo@math.tau.ac.il>
+.br
--- /dev/null
+.TH PLIPCONFIG 8 "17 February 1995" "" ""
+.SH NOM
+plipconfig \- réglage fin des paramètres du périphérique PLIP
+.SH SYNOPSIS
+.B "plipconfig interface"
+.br
+.B "plipconfig interface [nibble NN] [trigger NN] [unité NN]"
+.SH DESCRIPTION
+.B Plipconfig
+est utilisé pour améliorer (espérons-le) les performances PLIP
+en changeant les parmètres par défaut liés au temps et utilisés
+par le protocole PLIP. Les résultat dépendent du port parallèle
+utilisé, du cable, et de la vitesse CPU de chaque machine
+Ã chaque bout du lien PLIP.
+.LP
+Si le seul argument est l'
+.B interface,
+.B plipconfig
+affiche seulement l'état de cette interface. Autrement, il essaiera de
+positionner les options données.
+.SH OPTIONS
+.TP
+.B "nibble NN"
+Définit la valeur d'attente des digits en microsecondes. Par défault : 3000.
+.TP
+.B "trigger NN"
+Définit le temps avant déclenchement en microsecondes. Par défault : 500.
+.LP
+La vitesse de PLIP peut, dans certains cas, être améliorée en
+diminuant les valeurs par défaut.
+Les valeurs trop petites peuvent engendrer une utilisation excessive de CPU,
+et un temps de réponse aux interruptions mauvais, dont le résultat est
+la perte de caractères lus sur le port, ou de paquets PLIP.
+La modification du MTU PLIP peut aussi affecter la vitesse PLIP.
+.SH NOTE
+Si vous n'obtenez aucune réponse, il est fort probable que l'IRQ configurée
+soit mauvaise, et qu'elle nécessite une configuration avec ifconfig.
+Les quelques cas pour lesquels les paramètres par défaut sont trop rapides,
+arrivent lorque l'on utilise de longs cables. Quelque chose à ne pas faire,
+puisque le port parallèle n'est pas fait pour fonctionner avec de longs cables.
+.SH VOIR AUSSI
+.I ifconfig(8)
+.SH BUGS
+Non.
+.SH AUTEURS
+John Paul Morrison, <jmorriso@bogomips.ee.ubc.ca>, <ve7jpm@ve7jpm.ampr.org>
+.SH TRADUCTION
+Jean-Michel VANSTEENE (J.M.Vansteene@frcl.bull.fr)
--- /dev/null
+.TH SLATTACH 8 "12 Feb 1994" "" ""
+.SH NOM
+slattach \- attache une interface réseau à une ligne série
+.SH SYNOPSIS
+.B "slattach [-dehlLmnqv] [-c commande] [-p proto] [-s vitesse] [tty]"
+.br
+.SH DESCRIPTION
+.B Slattach
+est un minuscule programme qui peut être utilisé pour attacher
+un terminal normal ("série") dans un des différents modes "réseau",
+ceci vous permettant de l'utiliser pour des liaisons point-Ã -point
+vers d'autres systèmes.
+.SH OPTIONS
+.TP
+.B "[-c commande]"
+Exécute
+.B `commande'
+lorsque la ligne est suspendue. Ceci peut être utilisé pour lancer
+des scripts ou réétablir des connexions quand un lien tombe.
+.TP
+.B "[-d]"
+Valide le débogage. Utile pour déterminer pourquoi une configuration
+ne fonctionne pas.
+.TP
+.B "[-h]"
+Termine lorsque la porteuse est perdue. Ceci fonctionne à la fois sur
+les périphériques /dev/tty et /dev/cua en contrôlant directement
+l'état de la porteuse toutes les 15 secondes.
+.TP
+.B "[-v]"
+Valide le mode verbeux. Utile pour les shell scripts.
+.TP
+.B "[-q]"
+Opère en mode silencieux - pas de messages du tout.
+.TP
+.B "[-l]"
+Crée un fichier de vérouillage pour le périphérique comme
+pour UUCP dans /var/spool/uucp.
+.TP
+.B "[-n]"
+Equivalent à la commande "mesg n".
+.TP
+.B "[-m]"
+\fBn'\fPinitialise \fBpas\fP la ligne en mode raw 8 bits.
+.TP
+.B "[-e]"
+Termine correctement après l'initialisation du périphérique,
+au lieu d'attendre que la ligne soit suspendue.
+.TP
+.B "[-L]"
+Valide les opérations 3 lignes. Le terminal est mis en mode CLOCAL,
+la surveillance de porteuse est invalidée.
+.TP
+.B "[-p proto]"
+Définit le protocole spécifique à utiliser sur la ligne.
+La valeur par défaut est positionnée Ã
+.B "cslip"
+, i.e. SLIP compressé. Les autres valeurs possibles sont :
+.B "slip"
+(SLIP normal),
+.B "adaptive"
+(CSLIP/SLIP adaptatifs),
+.B "ppp"
+(Protocole Point-Ã -Point)
+et
+.B "kiss"
+(protocole AX.25 TNC).
+L'argument spécifique
+.B "tty"
+peut être utilisé pour refaire passer le périphérique en
+fonctionnement série normal. L'utilisation du mode 'ppp' n'est en
+principe pas utilise puisque ppp nécessite un démon additionnel
+.B pppd
+pour être actif sur la ligne. Pour les connexions `kiss', le programme
+.B axattach
+doit être utilisé.
+.TP
+.B "[-s vitesse]"
+Définit la vitesse de la ligne, différente de la valeur par défaut.
+.PP
+Si aucun argument n'est donné, la ligne courante du terminal
+(habituellement liée au login) est utilisée. Autrement, une tentative
+est effectuée pour obtenir le port du terminal indiqué, puis il est
+vérouillé et ouvert.
+.SH FICHIERS
+.I /dev/cua* /var/spool/uucp/LCK.*
+.SH BUGS
+Aucun connu.
+.SH VOIR AUSSI
+axattach(8), dip(8) pppd(8), sliplogin(8).
+.SH AUTEURS
+Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+.br
+Alan Cox, <Alan.Cox@linux.org>
+.br
+Miquel van Smoorenburg, <miquels@drinkel.ow.org>
+.br
+George Shearer, <gshearer@one.net>
+.br
+Yossi Gottlieb, <yogo@math.tau.ac.il>
+.br
+.SH TRADUCTION
+Jean-Michel VANSTEENE (J.M.Vansteene@frcl.bull.fr)
--- /dev/null
+/*
+
+ plipconfig.c: plip-ifconfig program for the Linux PLIP device driver
+ Copyright (c) 1994 John Paul Morrison (VE7JPM).
+
+ version 0.2
+
+ Changed by Alan Cox, to reflect the way SIOCDEVPRIVATE is meant to work
+ and for the extra parameter added by Niibe.
+
+ plipconfig is a quick hack to set PLIP parameters by using driver
+ ioctls. plipconfig will no doubt be revised many times as the Linux
+ PLIP driver and Linux 1.1 mutates.
+
+*/
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2, as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 675 Mass Ave, Cambridge MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_plip.h>
+#include "config.h"
+#include "intl.h"
+
+int opt_a = 0;
+int opt_i = 0;
+int opt_v = 0;
+int skfd = -1;
+
+struct ifreq ifr;
+struct plipconf *plip;
+
+void usage(void)
+{
+ fprintf(stderr, _("Usage: plipconfig [-a] [-i] [-v] interface\n"));
+ fprintf(stderr, _(" [nibble NN] [trigger NN]\n"));
+ exit(-1);
+}
+
+void print_plip(void)
+{
+ printf(_("%s\tnibble %lu trigger %lu\n"), ifr.ifr_name, plip->nibble, plip->trigger);
+}
+
+int main(int argc, char **argv)
+{
+ int ret = 0;
+ char **spp;
+
+ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ exit(-1);
+ }
+ /* Find any options. */
+ argc--;
+ argv++;
+ while (argv[0] && *argv[0] == '-') {
+ if (!strcmp(*argv, "-a"))
+ opt_a = 1;
+ if (!strcmp(*argv, "-v"))
+ opt_v = 1;
+ argv++;
+ argc--;
+ }
+
+ if (argc == 0)
+ usage();
+
+ spp = argv;
+ strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
+ plip=(struct plipconf *)&ifr.ifr_data;
+
+ plip->pcmd = PLIP_GET_TIMEOUT; /* get current settings for device */
+ if (ioctl(skfd, SIOCDEVPLIP, &ifr) < 0) {
+ perror("ioctl");
+ exit(-1);
+ }
+ if (*spp == (char *) NULL) {
+ print_plip();
+ (void) close(skfd);
+ exit(0);
+ }
+ while (*spp != (char *) NULL) {
+ if (!strcmp(*spp, "nibble")) {
+ if (*++spp == NULL)
+ usage();
+ plip->nibble = atoi(*spp);
+ spp++;
+ continue;
+ }
+ if (!strcmp(*spp, "trigger")) {
+ if (*++spp == NULL)
+ usage();
+ plip->trigger = atoi(*spp);
+ spp++;
+ continue;
+ }
+ usage();
+ }
+
+ plip->pcmd = PLIP_SET_TIMEOUT;
+ if (ioctl(skfd, SIOCDEVPLIP, &ifr) < 0)
+ perror("ioctl");
+
+ print_plip();
+
+ /* Close the socket. */
+ (void) close(skfd);
+
+ return (ret);
+}
--- /dev/null
+/*
+ * slattach A program for handling dialup IP connecions.
+ * This program forces a TTY line to go into a special
+ * terminal line discipline, so that it can be used for
+ * network traffic instead of the regular terminal I/O.
+ *
+ * Usage: slattach [-ehlmnqv] [ -k keepalive ] [ -o outfill ]
+ * [-c cmd] [-s speed] [-p protocol] tty | -
+ *
+ * Version: @(#)slattach.c 1.1.30 03/01/95
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Copyright 1988-1993 MicroWalt Corporation
+ *
+ * Modified:
+ * Alan Cox, <A.Cox@swansea.ac.uk> , July 16 1994
+ * Miquel van Smoorenburg, <miquels@drinkel.ow.org>, October 1994
+ * George Shearer, <gshearer@one.net>, January 3, 1995
+ * Yossi Gottlieb, <yogo@math.tau.ac.il>, February 11, 1995
+ * Peter Tobias, <tobias@et-inf.fho-emden.de>, July 30 1995
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/if_slip.h>
+
+#if defined(__GLIBC__)
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
+# include <termbits.h>
+#else
+# include <termios.h>
+#endif
+#endif
+
+#include "pathnames.h"
+#include "net-support.h"
+#include "version.h"
+#include "config.h"
+#include "intl.h"
+
+#ifndef _PATH_LOCKD
+#define _PATH_LOCKD "/var/lock" /* lock files */
+#endif
+#ifndef _UID_UUCP
+#define _UID_UUCP "uucp" /* owns locks */
+#endif
+
+
+#define DEF_PROTO "cslip"
+
+
+char *Release = RELEASE,
+ *Version = "@(#) slattach 1.1.91 (12-Feb-95)";
+
+
+struct {
+ char *speed;
+ int code;
+} tty_speeds[] = { /* table of usable baud rates */
+ { "50", B50 }, { "75", B75 },
+ { "110", B110 }, { "300", B300 },
+ { "600", B600 }, { "1200", B1200 },
+ { "2400", B2400 }, { "4800", B4800 },
+ { "9600", B9600 },
+#ifdef B14400
+ { "14400", B14400 },
+#endif
+#ifdef B19200
+ { "19200", B19200 },
+#endif
+#ifdef B38400
+ { "38400", B38400 },
+#endif
+#ifdef B57600
+ { "57600", B57600 },
+#endif
+#ifdef B115200
+ { "115200", B115200 },
+#endif
+ { NULL, 0 }
+};
+struct termios tty_saved, /* saved TTY device state */
+ tty_current; /* current TTY device state */
+int tty_sdisc, /* saved TTY line discipline */
+ tty_ldisc, /* current TTY line discipline */
+ tty_fd = -1; /* TTY file descriptor */
+int opt_c = 0; /* "command" to run at exit */
+int opt_e = 0; /* "activate only" flag */
+int opt_h = 0; /* "hangup" on carrier loss */
+#ifdef SIOCSKEEPALIVE
+int opt_k = 0; /* "keepalive" value */
+#endif
+int opt_l = 0; /* "lock it" flag */
+int opt_L = 0; /* clocal flag */
+int opt_m = 0; /* "set RAW mode" flag */
+int opt_n = 0; /* "set No Mesg" flag */
+#ifdef SIOCSOUTFILL
+int opt_o = 0; /* "outfill" value */
+#endif
+int opt_q = 0; /* "quiet" flag */
+int opt_d = 0; /* debug flag */
+int opt_v = 0; /* Verbose flag */
+
+/* Disable any messages to the input channel of this process. */
+static int
+tty_nomesg(int fd)
+{
+ if (opt_n == 0) return(0);
+ return(fchmod(fd, 0600));
+}
+
+/* Check for an existing lock file on our device */
+static int
+tty_already_locked(char *nam)
+{
+ int i = 0, pid = 0;
+ FILE *fd = (FILE *)0;
+
+ /* Does the lock file on our device exist? */
+ if ((fd = fopen(nam, "r")) == (FILE *)0)
+ return(0); /* No, return perm to continue */
+
+ /* Yes, the lock is there. Now let's make sure */
+ /* at least there's no active process that owns */
+ /* that lock. */
+ i = fscanf(fd, "%d", &pid);
+ (void) fclose(fd);
+
+ if (i != 1) /* Lock file format's wrong! Kill't */
+ return(0);
+
+ /* We got the pid, check if the process's alive */
+ if (kill(pid, 0) == 0) /* it found process */
+ return(1); /* Yup, it's running... */
+
+ /* Dead, we can proceed locking this device... */
+ return(0);
+}
+
+/* Lock or unlock a terminal line. */
+static int
+tty_lock(char *path, int mode)
+{
+ static char saved_path[PATH_MAX];
+ static int saved_lock = 0;
+ struct passwd *pw;
+ int fd;
+ char apid[16];
+
+ /* We do not lock standard input. */
+ if ((opt_l == 0) || ((path == NULL) && (saved_lock == 0))) return(0);
+
+ if (mode == 1) { /* lock */
+ sprintf(saved_path, "%s/LCK..%s", _PATH_LOCKD, path);
+ if (tty_already_locked(saved_path)) {
+ fprintf(stderr, _("slattach: /dev/%s already locked!\n"), path);
+ return(-1);
+ }
+ if ((fd = creat(saved_path, 0644)) < 0) {
+ if (errno != EEXIST)
+ if (opt_q == 0) fprintf(stderr,
+ _("slattach: tty_lock: (%s): %s\n"),
+ saved_path, strerror(errno));
+ return(-1);
+ }
+ sprintf(apid, "%10d\n", getpid());
+ if (write(fd, apid, strlen(apid)) != strlen(apid)) {
+ fprintf(stderr, _("slattach: cannot write PID file\n"));
+ close(fd);
+ unlink(saved_path);
+ return(-1);
+ }
+
+ (void) close(fd);
+
+ /* Make sure UUCP owns the lockfile. Required by some packages. */
+ if ((pw = getpwnam(_UID_UUCP)) == NULL) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_lock: UUCP user %s unknown!\n"),
+ _UID_UUCP);
+ return(0); /* keep the lock anyway */
+ }
+ (void) chown(saved_path, pw->pw_uid, pw->pw_gid);
+ saved_lock = 1;
+ } else { /* unlock */
+ if (saved_lock != 1) return(0);
+ if (unlink(saved_path) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_unlock: (%s): %s\n", saved_path,
+ strerror(errno));
+ return(-1);
+ }
+ saved_lock = 0;
+ }
+
+ return(0);
+}
+
+
+/* Find a serial speed code in the table. */
+static int
+tty_find_speed(char *speed)
+{
+ int i;
+
+ i = 0;
+ while (tty_speeds[i].speed != NULL) {
+ if (!strcmp(tty_speeds[i].speed, speed)) return(tty_speeds[i].code);
+ i++;
+ }
+ return(-EINVAL);
+}
+
+
+/* Set the number of stop bits. */
+static int
+tty_set_stopbits(struct termios *tty, char *stopbits)
+{
+ if (opt_d) printf("slattach: tty_set_stopbits: %c\n", *stopbits);
+ switch(*stopbits) {
+ case '1':
+ tty->c_cflag &= ~CSTOPB;
+ break;
+
+ case '2':
+ tty->c_cflag |= CSTOPB;
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+ return(0);
+}
+
+
+/* Set the number of data bits. */
+static int
+tty_set_databits(struct termios *tty, char *databits)
+{
+ if (opt_d) printf("slattach: tty_set_databits: %c\n", *databits);
+ tty->c_cflag &= ~CSIZE;
+ switch(*databits) {
+ case '5':
+ tty->c_cflag |= CS5;
+ break;
+
+ case '6':
+ tty->c_cflag |= CS6;
+ break;
+
+ case '7':
+ tty->c_cflag |= CS7;
+ break;
+
+ case '8':
+ tty->c_cflag |= CS8;
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+ return(0);
+}
+
+
+/* Set the type of parity encoding. */
+static int
+tty_set_parity(struct termios *tty, char *parity)
+{
+ if (opt_d) printf("slattach: tty_set_parity: %c\n", *parity);
+ switch(toupper(*parity)) {
+ case 'N':
+ tty->c_cflag &= ~(PARENB | PARODD);
+ break;
+
+ case 'O':
+ tty->c_cflag &= ~(PARENB | PARODD);
+ tty->c_cflag |= (PARENB | PARODD);
+ break;
+
+ case 'E':
+ tty->c_cflag &= ~(PARENB | PARODD);
+ tty->c_cflag |= (PARENB);
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+ return(0);
+}
+
+
+/* Set the line speed of a terminal line. */
+static int
+tty_set_speed(struct termios *tty, char *speed)
+{
+ int code;
+
+ if (opt_d) printf("slattach: tty_set_speed: %s\n", speed);
+ if ((code = tty_find_speed(speed)) < 0) return(code);
+ tty->c_cflag &= ~CBAUD;
+ tty->c_cflag |= code;
+ return(0);
+}
+
+
+/* Put a terminal line in a transparent state. */
+static int
+tty_set_raw(struct termios *tty)
+{
+ int i;
+ int speed;
+
+ for(i = 0; i < NCCS; i++)
+ tty->c_cc[i] = '\0'; /* no spec chr */
+ tty->c_cc[VMIN] = 1;
+ tty->c_cc[VTIME] = 0;
+ tty->c_iflag = (IGNBRK | IGNPAR); /* input flags */
+ tty->c_oflag = (0); /* output flags */
+ tty->c_lflag = (0); /* local flags */
+ speed = (tty->c_cflag & CBAUD); /* save current speed */
+ tty->c_cflag = (CRTSCTS | HUPCL | CREAD); /* UART flags */
+ if (opt_L)
+ tty->c_cflag |= CLOCAL;
+ tty->c_cflag |= speed; /* restore speed */
+ return(0);
+}
+
+
+/* Fetch the state of a terminal. */
+static int
+tty_get_state(struct termios *tty)
+{
+ if (ioctl(tty_fd, TCGETS, tty) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_get_state: %s\n", strerror(errno));
+ return(-errno);
+ }
+ return(0);
+}
+
+
+/* Set the state of a terminal. */
+static int
+tty_set_state(struct termios *tty)
+{
+ if (ioctl(tty_fd, TCSETS, tty) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_set_state: %s\n", strerror(errno));
+ return(-errno);
+ }
+ return(0);
+}
+
+
+/* Get the line discipline of a terminal line. */
+static int
+tty_get_disc(int *disc)
+{
+ if (ioctl(tty_fd, TIOCGETD, disc) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_get_disc: %s\n", strerror(errno));
+ return(-errno);
+ }
+ return(0);
+}
+
+
+/* Set the line discipline of a terminal line. */
+static int
+tty_set_disc(int disc)
+{
+ if (disc == -1) disc = tty_sdisc;
+
+ if (ioctl(tty_fd, TIOCSETD, &disc) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_set_disc(%d, %d): %s\n", tty_fd,
+ disc, strerror(errno));
+ return(-errno);
+ }
+ return(0);
+}
+
+
+/* Fetch the name of the network interface attached to this terminal. */
+static int
+tty_get_name(char *name)
+{
+ if (ioctl(tty_fd, SIOCGIFNAME, name) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_get_name: %s\n", strerror(errno));
+ return(-errno);
+ }
+ return(0);
+}
+
+
+/* Hangup the line. */
+static int
+tty_hangup(void)
+{
+ struct termios tty;
+
+ tty = tty_current;
+ (void) tty_set_speed(&tty, "0");
+ if (tty_set_state(&tty) < 0) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_hangup(DROP): %s\n"), strerror(errno));
+ return(-errno);
+ }
+
+ (void) sleep(1);
+
+ if (tty_set_state(&tty_current) < 0) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_hangup(RAISE): %s\n"), strerror(errno));
+ return(-errno);
+ }
+ return(0);
+}
+
+
+/* Close down a terminal line. */
+static int
+tty_close(void)
+{
+ (void) tty_set_disc(tty_sdisc);
+ (void) tty_hangup();
+ (void) tty_lock(NULL, 0);
+ return(0);
+}
+
+
+/* Open and initialize a terminal line. */
+static int
+tty_open(char *name, char *speed)
+{
+ char path[PATH_MAX];
+ register char *sp;
+ int fd;
+
+ /* Try opening the TTY device. */
+ if (name != NULL) {
+ if ((sp = strrchr(name, '/')) != (char *)NULL) *sp++ = '\0';
+ else sp = name;
+ sprintf(path, "/dev/%s", sp);
+ if (tty_lock(sp, 1)) return(-1); /* can we lock the device? */
+ if ((fd = open(path, O_RDWR)) < 0) {
+ if (opt_q == 0) fprintf(stderr,
+ "slattach: tty_open(%s, RW): %s\n",
+ path, strerror(errno));
+ return(-errno);
+ }
+ tty_fd = fd;
+ if (opt_d) printf("slattach: tty_open: %s (%d) ", path, fd);
+ } else {
+ tty_fd = 0;
+ sp = (char *)NULL;
+ }
+
+ /* Fetch the current state of the terminal. */
+ if (tty_get_state(&tty_saved) < 0) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot get current state!\n"));
+ return(-errno);
+ }
+ tty_current = tty_saved;
+
+ /* Fetch the current line discipline of this terminal. */
+ if (tty_get_disc(&tty_sdisc) < 0) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot get current line disc!\n"));
+ return(-errno);
+ }
+ tty_ldisc = tty_sdisc;
+
+ /* Put this terminal line in a 8-bit transparent mode. */
+ if (opt_m == 0) {
+ if (tty_set_raw(&tty_current) < 0) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot set RAW mode!\n"));
+ return(-errno);
+ }
+
+ /* Set the default speed if we need to. */
+ if (speed != NULL) {
+ if (tty_set_speed(&tty_current, speed) != 0) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot set %s bps!\n"),
+ speed);
+ return(-errno);
+ }
+ }
+
+ /* Set up a completely 8-bit clean line. */
+ if (tty_set_databits(&tty_current, "8") ||
+ tty_set_stopbits(&tty_current, "1") ||
+ tty_set_parity(&tty_current, "N")) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: tty_open: cannot set 8N1 mode!\n"));
+ return(-errno);
+ }
+
+ /* Set the new line mode. */
+ if ((fd = tty_set_state(&tty_current)) < 0) return(fd);
+ }
+
+ /* OK, line is open. Do we need to "silence" it? */
+ (void) tty_nomesg(tty_fd);
+
+ return(0);
+}
+
+
+/* Catch any signals. */
+static void
+sig_catch(int sig)
+{
+/* (void) signal(sig, sig_catch); */
+ tty_close();
+ exit(0);
+}
+
+
+static void
+usage(void)
+{
+ char *usage_msg = "Usage: slattach [-ehlLmnqv] "
+#ifdef SIOCSKEEPALIVE
+ "[-k keepalive] "
+#endif
+#ifdef SIOCSOUTFILL
+ "[-o outfill] "
+#endif
+ "[-c cmd] [-s speed] [-p protocol] tty | -\n";
+
+ fprintf(stderr, usage_msg);
+ exit(1);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char path[128];
+ char buff[128];
+ char *speed = NULL;
+ char *proto = DEF_PROTO;
+ char *extcmd = (char *)0;
+ struct hwtype *ht;
+ char *sp;
+ int s;
+
+ strcpy(path, "");
+
+ /* Scan command line for any arguments. */
+ opterr = 0;
+ while ((s = getopt(argc, argv, "c:ehlLmnp:qs:vd"
+#ifdef SIOCSKEEPALIVE
+ "k:"
+#endif
+#ifdef SIOCSOUTFILL
+ "o:"
+#endif
+ )) != EOF) switch(s) {
+ case 'c':
+ extcmd = optarg;
+ break;
+
+ case 'e':
+ opt_e = 1 - opt_e;
+ break;
+
+ case 'h':
+ opt_h = 1 - opt_h;
+ break;
+
+#ifdef SIOCSKEEPALIVE
+ case 'k':
+ opt_k = atoi(optarg);
+ break;
+#endif
+
+ case 'L':
+ opt_L = 1 - opt_L;
+ break;
+
+ case 'l':
+ opt_l = 1 - opt_l;
+ break;
+
+ case 'm':
+ opt_m = 1 - opt_m;
+ break;
+
+ case 'n':
+ opt_n = 1 - opt_n;
+ break;
+
+#ifdef SIOCSOUTFILL
+ case 'o':
+ opt_o = atoi(optarg);
+ break;
+#endif
+
+ case 'p':
+ proto = optarg;
+ break;
+
+ case 'q':
+ opt_q = 1 - opt_q;
+ break;
+
+ case 's':
+ speed = optarg;
+ break;
+
+ case 'd':
+ opt_d = 1 - opt_d;
+ break;
+
+ case 'v':
+ opt_v = 1 - opt_v;
+ break;
+
+ default:
+ usage();
+ }
+
+ activate_init();
+
+ /* Check the protocol. */
+ if ((ht = get_hwtype(proto)) == NULL && strcmp(proto, "tty")) {
+ if (opt_q == 0) fprintf(stderr, _("slattach: unsupported protocol %s\n"), proto);
+ return(2);
+ }
+ if (ht == NULL) opt_m++;
+
+ /* Is a terminal given? */
+ if (optind != (argc - 1)) usage();
+ strncpy(path, argv[optind], 128);
+ if (!strcmp(path, "-")) {
+ opt_e = 1;
+ sp = NULL;
+ if (tty_open(NULL, speed) < 0) { return(3); }
+ } else {
+ if ((sp = strrchr(path, '/')) != NULL) *sp++ = '\0';
+ else sp = path;
+ if (tty_open(sp, speed) < 0) { return(3); }
+ }
+
+ /* Start the correct protocol. */
+ if (ht == NULL) {
+ tty_sdisc = N_TTY;
+ tty_close();
+ return(0);
+ }
+ (*ht->activate)(tty_fd);
+ if (opt_v == 1) {
+ tty_get_name(buff);
+ printf("%s started", proto);
+ if (sp != NULL) printf(" on %s", sp);
+ printf(" interface %s\n", buff);
+ }
+
+ /* Configure keepalive and outfill. */
+#ifdef SIOCSKEEPALIVE
+ if (opt_k && (ioctl(tty_fd, SIOCSKEEPALIVE, &opt_k) < 0))
+ fprintf(stderr, "slattach: ioctl(SIOCSKEEPALIVE): %s\n", strerror(errno));
+#endif
+#ifdef SIOCSOUTFILL
+ if (opt_o && (ioctl(tty_fd, SIOCSOUTFILL, &opt_o) < 0))
+ fprintf(stderr, "slattach: ioctl(SIOCSOUTFILL): %s\n", strerror(errno));
+#endif
+
+ (void) signal(SIGHUP, sig_catch);
+ (void) signal(SIGINT, sig_catch);
+ (void) signal(SIGQUIT, sig_catch);
+ (void) signal(SIGTERM, sig_catch);
+
+ /* Wait until we get killed if hanging on a terminal. */
+ if (opt_e == 0) {
+ while(1) {
+ if(opt_h == 1) { /* hangup on carrier loss */
+ int n = 0;
+
+ ioctl(tty_fd, TIOCMGET, &n);
+ if(!(n & TIOCM_CAR))
+ break;
+ sleep(15);
+ }
+ else
+ sleep(60);
+ };
+
+ tty_close();
+ if(extcmd!=(char *)0) /* external command on exit */
+ system(extcmd);
+ }
+ exit(0);
+}