From 0fceb64d25ff3d9586549bb43d971c5eef904330 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 7 Jun 1999 10:23:42 +0200 Subject: Import ax25-apps 0.0.1 from tarball --- ax25rtd/listener.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 ax25rtd/listener.c (limited to 'ax25rtd/listener.c') diff --git a/ax25rtd/listener.c b/ax25rtd/listener.c new file mode 100644 index 0000000..27b8622 --- /dev/null +++ b/ax25rtd/listener.c @@ -0,0 +1,579 @@ +/* $Id: listener.c,v 1.9 1997/06/05 18:56:08 oe1kib Exp oe1kib $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * 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. + * + * 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. + * + */ + + /* TODO: Should add partial path to ax25_route if we are one of the + * digipeaters. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pathnames.h" +#include "ax25rtd.h" + + +/* FIXME */ +static unsigned long get_from_arp(unsigned char *data, int size) +{ + if (size < 16) + return 0; + + return ntohl(0); +} + +static unsigned long get_from_ip(unsigned char *data, int size) +{ + unsigned long adr; + + if ((*data & 0xf)*4 < IPLEN) + return 0; + + adr = data[12] << 24; /* NETWORK byte order */ + adr += data[13] << 16; + adr += data[14] << 8; + adr += data[15]; + + return ntohl(adr); /* HOST byte order */ +} + +int call_is_mycall(config *config, ax25_address *call) +{ + int k; + + for (k = 0; k < config->nmycalls; k++) + if (!memcmp(call, &config->mycalls[k], AXLEN)) + return 1; + return 0; +} + +/* + * This catches *all* invalid callsigns, unlike ax25validate. + */ + +static int check_ax25_addr(unsigned char *buf) +{ + int k; + unsigned char c; + + /* must start with at least one capital letter or digit */ + for (k=0; k < 6; k++) { + c = buf[k] >> 1; + if (c == ' ') break; + if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) + return 1; + } + + /* NULL address is invalid */ + if (k == 0) + return 1; + + /* remaining fields must consist of spaces only */ + for (k++; k < 6; k++) + if (buf[k] >> 1 != ' ') + return 1; + + return 0; +} + +static inline void invert_digipeater_path(ax25_address *digipeater, int ndigi) +{ + int k, m; + ax25_address fdigi; + + if (ndigi == 0) + return; + + ndigi--; + + memcpy(&fdigi, &digipeater[0], AXLEN); + + for (m = 0,k = ndigi; k > 0; k--, m++) + memcpy(&digipeater[m], &digipeater[k], AXLEN); + + memcpy(&digipeater[ndigi], &fdigi, AXLEN); +} + +int set_arp(config *config, long ip, ax25_address *call) +{ + struct sockaddr_in *isa; + struct sockaddr_ax25 *asa; + struct arpreq arp; + int fds; + + if (!config->ip_add_arp) + return 0; + + fds = socket(AF_INET, SOCK_DGRAM, 0); + + memset((char *) &arp, 0, sizeof(arp)); + + isa = (struct sockaddr_in *) &arp.arp_pa; + asa = (struct sockaddr_ax25 *) &arp.arp_ha; + + isa->sin_family = AF_INET; + isa->sin_port = 0; + isa->sin_addr.s_addr = ip; + + asa->sax25_family = AF_AX25; + asa->sax25_ndigis = 0; + asa->sax25_call = *call; + + arp.arp_flags = ATF_PERM | ATF_COM; + strcpy(arp.arp_dev, config->dev); + + if (ioctl(fds, SIOCSARP, &arp) < 0) + { + invalidate_ip_route(ip); + perror("routspy: SIOCSARP"); + close(fds); + return 1; + } + close(fds); + return 0; +} + +int set_route(config *config, long ip) +{ + struct rtentry rt; + struct sockaddr_in *isa; + char origdev[16], buf[1024]; + long ipr; + int fds; + FILE *fp; + + fp = fopen(PROC_IP_ROUTE_FILE, "r"); + if (fp == NULL) + { + invalidate_ip_route(ip); + return 1; + } + + fgets(buf, sizeof(buf)-1, fp); /* discard header */ + while (fgets(buf, sizeof(buf)-1, fp) != NULL) + { + sscanf(buf, "%s %lx", origdev, &ipr); + if (ipr == ip) + { + if (dev_get_config(origdev) == NULL) + { + invalidate_ip_route(ip); + fclose(fp); + return 1; + } + else + { + del_kernel_ip_route(origdev, ip); + } + } + + } + fclose(fp); + + if (!config->ip_add_route) + return 0; + + fds = socket(AF_INET, SOCK_DGRAM, 0); + + memset((char *) &rt, 0, sizeof(rt)); + + isa = (struct sockaddr_in *) &rt.rt_dst; + + isa->sin_family = AF_INET; + isa->sin_port = 0; + isa->sin_addr.s_addr = ip; + + rt.rt_flags = RTF_UP | RTF_HOST; + rt.rt_dev = config->dev; + + if (config->tcp_irtt != 0) + { + rt.rt_irtt = config->tcp_irtt; + rt.rt_flags |= RTF_IRTT; + } + + isa = (struct sockaddr_in *) &rt.rt_genmask; + isa->sin_addr.s_addr = 0xffffffff; + + if (ioctl(fds, SIOCADDRT, &rt) < 0) + { + invalidate_ip_route(ip); + perror("ax25rtd: IP SIOCADDRT"); + close(fds); + return 1; + } + close(fds); + return 0; +} + +int del_kernel_ip_route(char *dev, long ip) +{ + int fds; + struct rtentry rt; + struct sockaddr_in *isa; + config *config; + + config = dev_get_config(dev); + if (config == NULL || !config->ip_add_route) + return 0; + + fds = socket(AF_INET, SOCK_DGRAM, 0); + + memset((char *) &rt, 0, sizeof(struct rtentry)); + + isa = (struct sockaddr_in *) &rt.rt_dst; + + isa->sin_family = AF_INET; + isa->sin_addr.s_addr = ip; + + rt.rt_flags = RTF_UP | RTF_HOST; + rt.rt_dev = dev; + + if (ioctl(fds, SIOCDELRT, &rt) < 0) + { + perror("ax25rtd: IP SIOCDELRT"); + close(fds); + return 1; + } + close(fds); + return 0; +} + +int set_ax25_route(config *config, ax25_rt_entry *rt) +{ + struct ax25_routes_struct ax25_route; + int fds, k; + + if (!config->ax25_add_route) + return 0; + + ax25_route.port_addr = config->mycalls[0]; + ax25_route.dest_addr = rt->call; + ax25_route.digi_count = rt->ndigi; + + for (k = 0; k < rt->ndigi; k++) + ax25_route.digi_addr[k] = rt->digipeater[k]; + + fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + + if (ioctl(fds, SIOCADDRT, &ax25_route) < 0) + { + perror("ax25rtd: AX.25 SIOCADDRT"); + close(fds); + return 1; + } + + close(fds); + return 0; +} + +int del_kernel_ax25_route(char *dev, ax25_address *call) +{ + struct ax25_routes_struct ax25_route; + int fds; + config *config; + + config = dev_get_config(dev); + if (config == NULL || !config->ax25_add_route) + return 0; + + ax25_route.port_addr = config->mycalls[0]; + ax25_route.dest_addr = *call; + + fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + + if (ioctl(fds, SIOCDELRT, &ax25_route) < 0) + { + perror("ax25rtd: AX.25 SIOCDELRT"); + close(fds); + return 1; + } + + close(fds); + return 0; +} + +int set_ipmode(config *config, ax25_address *call, int ipmode) +{ + struct ax25_route_opt_struct ax25_opt; + int fds; + + if (!config->ip_adjust_mode) + return 0; + + ax25_opt.port_addr = config->mycalls[0]; + ax25_opt.dest_addr = *call; + ax25_opt.cmd = AX25_SET_RT_IPMODE; + ax25_opt.arg = ipmode? 'V':'C'; + + fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + + if (ioctl(fds, SIOCAX25OPTRT, &ax25_opt) < 0) + { + perror("ax25rtd: SIOCAX25OPTRT"); + close(fds); + return 1; + } + + close(fds); + return 0; + +} + +/* Yes, the code *IS* ugly... */ + +#define SKIP(o) {data+=(o); size-=(o);} +void ax25_receive(int sock) +{ + unsigned char buf[1500]; + unsigned char *data; + unsigned long ip; + struct sockaddr sa; + ax25_address srccall, destcall, digipeater[AX25_MAX_DIGIS]; + char extseq = 0; + int size, asize, action, ipmode, ctl, pid, ndigi, kdigi, mine; + time_t stamp; + config *config; + ax25_rt_entry * ax25rt; + + asize = sizeof(sa); + if ((size = recvfrom(sock, buf, sizeof(buf), 0, &sa, &asize)) < 0) + { + perror("recvfrom"); + save_cache(); + daemon_shutdown(1); + } + + stamp = time(NULL); + ip = 0; + pid = ctl = 0; + + config = dev_get_config(sa.sa_data); + + if (config == NULL) + return; + + data = buf; + + /* + * KISS data? + */ + + if (*data != 0) + return; + + SKIP(1); + + /* valid frame? */ + + if (size < (2*AXLEN+1)) + return; + + /* + * Get destination callsign + */ + + if (check_ax25_addr(data)) + return; + + memcpy(&destcall, data, AXLEN); + destcall.ax25_call[6] &= 0x1e; + SKIP(AXLEN); + + mine = call_is_mycall(config, &destcall); + + /* + * Get Source callsign + */ + + if (check_ax25_addr(data)) + return; + + memcpy(&srccall, data, AXLEN); + srccall.ax25_call[6] &= 0x1e; + SKIP(ALEN); + + /* + * How long is our control field? + */ + + extseq = ~(*data) & SSSID_SPARE; + + /* + * Extract digipeaters + */ + + ndigi = 0; + while (((*data) & HDLCAEB) != HDLCAEB) + { + SKIP(1); + if (size <= 0 || check_ax25_addr(data)) + return; + + if (ndigi < AX25_MAX_DIGIS) + memcpy(&digipeater[ndigi++], data, AXLEN); + else + return; + + + SKIP(ALEN); + } + + SKIP(1); + if (size <= 0) + return; + + /* + * Get type of frame + */ + + if ((*data & LAPB_S) == LAPB_I) + ctl = LAPB_I; + else + { + ctl = *data; + if (extseq == 0) + ctl &= ~LAPB_PF; + } + + /* + * Check if info frame and get PID + */ + + if (ctl == LAPB_I || ctl == LAPB_UI) + { + SKIP(extseq? 2:1); + if (size <= 0) + return; + + /* Get PID */ + + pid = *data; + + if (pid == PID_SEGMENT) + { + SKIP(1); + if (size <= 0) + return; + pid = 0; + + if (*data && SEG_FIRST) + { + pid = *data; + SKIP(1); + if (size <= 0) + return; + } + } + } + + /* + * See if it is fully digipeated (TODO: or if we are the next digipeater) + */ + + for (kdigi = 0; kdigi < ndigi; kdigi++) + { + if ((digipeater[kdigi].ax25_call[6] & AX25_REPEATED) != AX25_REPEATED) + return; + + digipeater[kdigi].ax25_call[6] &= 0x1e; + } + + invert_digipeater_path(digipeater, ndigi); + + /* + * Are we allowed to add it to our routing table? + */ + + if (mine || !config->ax25_for_me) + { + if (!mine && ndigi == 0 && config->ax25_add_default) + { + ndigi = config->ax25_default_path.fsa_ax25.sax25_ndigis; + for (kdigi = 0; kdigi < ndigi; kdigi++) + if (!memcmp(&srccall, &config->ax25_default_path.fsa_digipeater[kdigi], AXLEN)) + break; + + if (ndigi == kdigi) + memcpy(digipeater, config->ax25_default_path.fsa_digipeater, ndigi*AXLEN); + else + ndigi = 0; + } + + ax25rt = update_ax25_route(config, &srccall, ndigi, digipeater, stamp); + + if (ax25rt != NULL) + set_ax25_route(config, ax25rt); + } + + /* + * Now see if it carries IP traffic + */ + + switch(pid) + { + case PID_ARP: + SKIP(1); + if (size > 0) + ip = get_from_arp(data, size); + break; + case PID_IP: + if (!mine) + return; + + SKIP(1); + if (size > 0) + ip = get_from_ip(data, size); + break; + default: + return; + } + + /* + * And adjust routes/arp/ipmode if we are allowed to... + */ + + ipmode = (ctl == LAPB_I); + + if (ip != 0) + { + action = update_ip_route(config, ip, ipmode, &srccall, stamp); + + if (action & NEW_ROUTE) + if (set_route(config, ip)) + return; + + if (action & NEW_ARP) + if (set_arp(config, ip, &srccall)) + return; + + if (action & NEW_IPMODE) + if (set_ipmode(config, &srccall, ipmode)) + return; + } +} -- cgit v1.2.3