1537 lines
45 KiB
C
Executable File
1537 lines
45 KiB
C
Executable File
/************************************************************************/
|
|
/* */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* *************** *************** */
|
|
/* ***************** ***************** */
|
|
/* *************** *************** */
|
|
/* ***** ***** TheNetNode */
|
|
/* ***** ***** Portable */
|
|
/* ***** ***** Network */
|
|
/* ***** ***** Software */
|
|
/* */
|
|
/* File src/l3ip.c (maintained by: DG1KWA) */
|
|
/* */
|
|
/* This file is part of "TheNetNode" - Software Package */
|
|
/* */
|
|
/* Copyright (C) 1998 - 2008 NORD><LINK e.V. Braunschweig */
|
|
/* */
|
|
/* This program is free software; you can redistribute it and/or modify */
|
|
/* it under the terms of the NORD><LINK ALAS (Allgemeine Lizenz fuer */
|
|
/* Amateurfunk Software) as published by Hans Georg Giese (DF2AU) */
|
|
/* on 13/Oct/1992; either version 1, or (at your option) any later */
|
|
/* version. */
|
|
/* */
|
|
/* This program is distributed WITHOUT ANY WARRANTY only for further */
|
|
/* development and learning purposes. See the ALAS (Allgemeine Lizenz */
|
|
/* fuer Amateurfunk Software). */
|
|
/* */
|
|
/* You should have received a copy of the NORD><LINK ALAS (Allgemeine */
|
|
/* Lizenz fuer Amateurfunk Software) along with this program; if not, */
|
|
/* write to NORD><LINK e.V., Hinter dem Berge 5, D-38108 Braunschweig */
|
|
/* */
|
|
/* Dieses Programm ist PUBLIC DOMAIN, mit den Einschraenkungen durch */
|
|
/* die ALAS (Allgemeine Lizenz fuer Amateurfunk Software), entweder */
|
|
/* Version 1, veroeffentlicht von Hans Georg Giese (DF2AU), */
|
|
/* am 13.Oct.1992, oder (wenn gewuenscht) jede spaetere Version. */
|
|
/* */
|
|
/* Dieses Programm wird unter Haftungsausschluss vertrieben, aus- */
|
|
/* schliesslich fuer Weiterentwicklungs- und Lehrzwecke. Naeheres */
|
|
/* koennen Sie der ALAS (Allgemeine Lizenz fuer Amateurfunk Software) */
|
|
/* entnehmen. */
|
|
/* */
|
|
/* Sollte dieser Software keine ALAS (Allgemeine Lizenz fuer Amateur- */
|
|
/* funk Software) beigelegen haben, wenden Sie sich bitte an */
|
|
/* NORD><LINK e.V., Hinter dem Berge 5, D-38108 Braunschweig */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#include "tnn.h"
|
|
|
|
#ifdef IPROUTE
|
|
static void send_ip_mb(MBHEAD *, unsigned, ipaddr, unsigned);
|
|
|
|
char QST[] = {'Q', 'S', 'T', ' ', ' ', ' ', '\140'};
|
|
|
|
ipaddr my_ip_addr = 0x00000000L; /* default: eigene IP */
|
|
ipaddr bcast_ip_addr = 0x00000000L; /* default: meine BCAST-IP */
|
|
int my_ip_bits = 0; /* default: Subnet-Bits */
|
|
|
|
#ifdef IPROUTEMOD
|
|
/* alle nicht definierten IP-Adressen */
|
|
/* an die my_default_ip_addr schicken */
|
|
ipaddr my_default_ip_addr = 0x00000000L;
|
|
#endif /* IPROUTEMOD */
|
|
|
|
/* Globale Variablen */
|
|
|
|
LHEAD IP_Routes; /* Tabelle mit den eingetragenen Routen */
|
|
LHEAD Arp_tab; /* Tabelle mit den ARP-Requests */
|
|
LHEAD iprxfl; /* Empfangene IP-Frames */
|
|
LHEAD arprxfl; /* Empfangene ARP-Frames */
|
|
|
|
ARP arp; /* ARP Header */
|
|
|
|
MIB_ENTRY Ip_mib[NUMIPMIB + 1] =
|
|
{
|
|
{"", {0}},
|
|
{"ipForwarding", {1}},
|
|
{"ipDefaultTTL", {32}},
|
|
{"ipInReceives", {0}},
|
|
{"ipInHdrErrors", {0}},
|
|
{"ipInAddrErrors", {0}},
|
|
{"ipForwDatagrams", {0}},
|
|
{"ipInUnknownProtos", {0}},
|
|
{"ipInDiscards", {0}},
|
|
{"ipInDelivers", {0}},
|
|
{"ipOutRequests", {0}},
|
|
{"ipOutDiscards", {0}},
|
|
{"ipOutNoRoutes", {0}},
|
|
{"ipReasmTimeout", {TLB}},
|
|
{"ipReasmReqds", {0}},
|
|
{"ipReasmOKs", {0}},
|
|
{"ipReasmFails", {0}},
|
|
{"ipFragOKs", {0}},
|
|
{"ipFragFails", {0}},
|
|
{"ipFragCreates", {0}}
|
|
};
|
|
|
|
WORD ipnat = 600;
|
|
|
|
IPPORTPAR IPpar[L2PNUM + 1]; /* fuer jeden L2-Port + NETROM */
|
|
|
|
UWORD ARPcounter; /* ARP-Timing */
|
|
UWORD ARPtimer;
|
|
|
|
ULONG ip_cksum;
|
|
|
|
/************************************************************************
|
|
* Function : send_ip_mb
|
|
*
|
|
* Inputs : mhbp - Ein Messagebuffer
|
|
* port - Der L2-Port zum Senden (oder NETROM_PORT)
|
|
* gateway - Zieladdresse
|
|
* tos
|
|
*
|
|
* Returns : Fehler-Code
|
|
*
|
|
* Operation: Ein Frame an ein Gateways senden
|
|
*
|
|
*----------------------------------------------------------------------*/
|
|
static void
|
|
send_ip_mb(MBHEAD *mhbp, unsigned port, ipaddr gateway, unsigned tos)
|
|
{
|
|
#ifdef KERNELIF
|
|
if (port == KERNEL_PORT)
|
|
{
|
|
ifip_frame_to_kernel(mhbp);
|
|
return;
|
|
}
|
|
#endif
|
|
if (port == NETROM_PORT)
|
|
nr_iface(mhbp, gateway);
|
|
else
|
|
l2_iface(mhbp, port, gateway, tos);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : ipinit
|
|
*
|
|
* Inputs : none
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Operation: Initialisation des IP-Gateways beim Softwarestart
|
|
*
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
ipinit(void) /* Router initialisation */
|
|
{
|
|
register int i;
|
|
|
|
inithd(&iprxfl);
|
|
inithd(&arprxfl);
|
|
|
|
inithd(&IP_Routes);
|
|
inithd(&Arp_tab);
|
|
|
|
#ifdef TCP_STACK
|
|
/* TCP-Stack Initialisieren. */
|
|
StackInitTCP();
|
|
#endif /* TCP_STACK */
|
|
|
|
/* NET/ROM MUSS immer freigeschaltet bleiben ! */
|
|
for (i = 0; i <= L2PNUM; i++)
|
|
{
|
|
IPpar[i].ipMode = ARP_OK + IP_FORWARDING;
|
|
}
|
|
|
|
ARPcounter = ARPtimer = 60;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : IP service
|
|
*
|
|
* Inputs : None
|
|
*
|
|
* Returns : None
|
|
*
|
|
* Operation: Alle empfangenen IP-Frames aus der Empfangsliste holen und
|
|
* verarbeiten, eventuell ARP ausloesen
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
ipserv(void)
|
|
{
|
|
register MBHEAD *mbhd;
|
|
|
|
/* die Empfangsliste durchgehen und jedes Frame durch den Router */
|
|
/* schicken */
|
|
while ((mbhd = (MBHEAD *)iprxfl.head) != (MBHEAD *)&iprxfl)
|
|
{
|
|
ulink((LEHEAD *)mbhd);
|
|
ip_route(mbhd); /* Frames an den ip_router */
|
|
dealmb(mbhd);
|
|
}
|
|
|
|
/* jetzt verarbeiten wir die ARP-Frames */
|
|
while ((mbhd = (MBHEAD *)arprxfl.head) != (MBHEAD *)&arprxfl)
|
|
{
|
|
ulink((LEHEAD *)mbhd);
|
|
arp_service(mbhd); /* Frames an den arp_service */
|
|
dealmb(mbhd);
|
|
}
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Ein Frame for a single frame. Called by ip server
|
|
*
|
|
* Inputs : Zeiger auf das Frame, das geroutet werden soll
|
|
*
|
|
* Returns : None
|
|
*
|
|
* Operation: Leitet das Frame weiter oder generiert ein ICMP-Frame, das
|
|
* Frame wird segmentiert, wenn der Sendelayer das erlaubt hat
|
|
* ---------------------------------------------------------------------*/
|
|
void
|
|
ip_route(MBHEAD *mbhd) /* Internet server */
|
|
{
|
|
register unsigned int i; /* genereller Zaehler */
|
|
register MBHEAD *tbp; /* Buffer fuer Ausgabe (z.B. ICMP) */
|
|
char huge *rxnxt; /* die Position in mbhd merken */
|
|
static IP ip; /* Structure zum decodieren des */
|
|
/* IP-Header */
|
|
int strict; /* Flag (opt-Feld) strict-routing */
|
|
ipaddr gateway; /* Addresse des gefundenen Gateways */
|
|
IP_ROUTE *rp; /* Pointer um die Route zu finden */
|
|
unsigned length; /* Anzahl der Datenbytes im Frame */
|
|
unsigned offset; /* Offset fuer Fragmentation */
|
|
BOOLEAN rxbroadcast; /* ist es ein Broadcast-Frame? */
|
|
BOOLEAN mf_flag; /* More Flag bei Fragmentation */
|
|
unsigned char *opt,
|
|
*ptr; /* Pointers bei den option-Flags */
|
|
unsigned char opt_len; /* Length bei option-Flags */
|
|
unsigned ip_len; /* Ip-Header Laenge */
|
|
unsigned mtu; /* mtu fuer das Interface bei tx */
|
|
|
|
#ifdef KERNELIF
|
|
/* die eingeschleusten Frames vom Kernel vorbeimogeln */
|
|
if (mbhd->l2port != KERNEL_PORT)
|
|
{
|
|
#endif
|
|
if ( (mbhd->l2fflg != L2CIP)
|
|
|| (!IPpar[mbhd->l2port].ipMode & IP_FORWARDING))
|
|
return;
|
|
#ifdef KERNELIF
|
|
}
|
|
#endif
|
|
rxnxt = mbhd->mbbp; /* Anfang des Headers merken */
|
|
ip_len = getchr(mbhd); /* Laenge und Version lesen */
|
|
ip.version = (ip_len >> 4) & 0x0f; /* Versionsnummer */
|
|
ip_len = (ip_len & 0x0f) << 2; /* und Laenge in Bytes */
|
|
mbhd->mbbp = rxnxt; /* zurueck an den Anfang */
|
|
if ( (mbhd->mbpc - (--mbhd->mbgc)) < IPLEN
|
|
|| (ip_len < IPLEN)
|
|
|| (ip.version != IPVERSION)
|
|
#ifdef __WIN32__
|
|
|| cksum(NULLHEADER, mbhd, (unsigned short)ip_len) != 0)
|
|
#else
|
|
|| cksum(NULLHEADER, mbhd, ip_len) != 0)
|
|
#endif /* WIN32 */
|
|
{
|
|
ipInHdrErrors++;
|
|
return;
|
|
}
|
|
|
|
/* jetzt wird der IP-Header ausgewertet */
|
|
getchr(mbhd); /* skip length/version */
|
|
ip.tos = getchr(mbhd);
|
|
ip.length = get16(mbhd);
|
|
ip.id = get16(mbhd);
|
|
ip.offset = get16(mbhd);
|
|
ip.flags.mf = (ip.offset & 0x2000) ? 1 : 0;
|
|
ip.flags.df = (ip.offset & 0x4000) ? 1 : 0;
|
|
ip.offset = (ip.offset & 0x1fff) << 3;
|
|
ip.ttl = getchr(mbhd);
|
|
ip.protocol = getchr(mbhd);
|
|
ip.checksum = get16(mbhd);
|
|
ip.source = get32(mbhd);
|
|
ip.dest = get32(mbhd);
|
|
|
|
/* ist das Ziel eine Broadcast-Addresse ? */
|
|
rxbroadcast = is_broadcast_address(ip.dest);
|
|
|
|
/* Optionsfeld auswerten */
|
|
if ((ip.optlen = ip_len - IPLEN) != 0)
|
|
for (i = 0; i < ip.optlen; i++)
|
|
ip.options[i] = getchr(mbhd);
|
|
length = ip.length - ip_len;
|
|
|
|
/* wenn das Frame direkt an uns gerichtet ist und wir keinen Speicher */
|
|
/* mehr haben, muessen wir bescheid sagen */
|
|
if (!rxbroadcast && nmbfre < 256)
|
|
icmp_output(&ip, mbhd, ICMP_QUENCH, 0, NULLICMP);
|
|
|
|
/* Optionsfelder auswerten */
|
|
strict = 0;
|
|
for (opt = ip.options; opt < &ip.options[ip.optlen]; opt += opt_len)
|
|
{
|
|
opt_len = opt[1];
|
|
if ((opt[0] & OPT_NUMBER) == IP_EOL)
|
|
break;
|
|
|
|
switch (opt[0] & OPT_NUMBER)
|
|
{
|
|
case IP_NOOP:
|
|
opt_len = 1;
|
|
break;
|
|
|
|
case IP_SSROUTE:
|
|
strict = 1;
|
|
|
|
case IP_LSROUTE:
|
|
if (!is_my_ip_addr(ip.dest))
|
|
break;
|
|
if (opt[2] >= opt_len)
|
|
break;
|
|
ptr = opt + opt[2] - 1;
|
|
|
|
memcpy(&ip.dest, ptr, 4);
|
|
memcpy(ptr, &my_ip_addr, 4);
|
|
|
|
opt[2] += 4;
|
|
break;
|
|
case IP_RROUTE:
|
|
if (opt[2] >= opt_len)
|
|
{
|
|
if (!rxbroadcast)
|
|
{
|
|
union icmp_args icmp_args;
|
|
|
|
icmp_args.pointer = IPLEN + opt - ip.options;
|
|
icmp_output(&ip, mbhd, ICMP_PARAM_PROB, 0, &icmp_args);
|
|
}
|
|
return;
|
|
}
|
|
ptr = opt + opt[2] - 1;
|
|
memcpy(ptr, &my_ip_addr, 4);
|
|
opt += 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef TCP_STACK
|
|
/* Protokoll TCP, */
|
|
if ( (ip.protocol == TCP_PTCL)
|
|
/* und an mich. */
|
|
&&(is_my_ip_addr(ip.dest)))
|
|
{
|
|
/* An TCP-Stack weiterleiten. */
|
|
TCPIPProcess(&ip, mbhd);
|
|
return;
|
|
}
|
|
#endif /* TCP_STACK */
|
|
|
|
if ((is_my_ip_addr(ip.dest)) || rxbroadcast)
|
|
{
|
|
if ( !rxbroadcast && !ip.flags.mf && ip.offset == 0
|
|
&& ip.protocol == ICMP_PTCL)
|
|
{
|
|
icmp_input(&ip, mbhd);
|
|
ipInReceives++;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (!rxbroadcast)
|
|
icmp_output(&ip, mbhd, ICMP_DEST_UNREACH,
|
|
ICMP_PROT_UNREACH, NULLICMP);
|
|
ipInUnknownProtos++;
|
|
return;
|
|
}
|
|
}
|
|
|
|
ipForwDatagrams++;
|
|
|
|
/* Wenn die Lifetime des Frames abgelaufen ist, Frame vernichten und */
|
|
/* Sender benachrichtigen */
|
|
if (--ip.ttl == 0)
|
|
{
|
|
icmp_output(&ip, mbhd, ICMP_TIME_EXCEED, 0, NULLICMP);
|
|
ipInHdrErrors++;
|
|
return;
|
|
}
|
|
|
|
/* Einen passenden Eintrag in der routing-Tabelle finden, wenn nichts */
|
|
/* passt, einen NetSearch durchfuehren (zZ noch nicht implementiert), */
|
|
/* wenn wir dort auch nichts finden, * wird das Frame vernichtet. */
|
|
#ifndef IPROUTEMOD
|
|
if ((rp = rt_find(ip.dest)) == NULLROUTE)
|
|
{
|
|
icmp_output(&ip, mbhd, ICMP_DEST_UNREACH,
|
|
ICMP_HOST_UNREACH, NULLICMP);
|
|
ipOutNoRoutes++;
|
|
return;
|
|
}
|
|
#else /* IPROUTEMOD */
|
|
if ((rp = rt_find(ip.dest)) == NULLROUTE)
|
|
{ /* Auf default-route pruefen. */
|
|
if ((rp = rt_find(my_default_ip_addr)) == NULLROUTE)
|
|
{
|
|
icmp_output(&ip, mbhd, ICMP_DEST_UNREACH,
|
|
ICMP_HOST_UNREACH, NULLICMP);
|
|
ipOutNoRoutes++;
|
|
return;
|
|
}
|
|
}
|
|
#endif /* IPROUTEMOD */
|
|
|
|
/* Den naechsten IP-Router berechnen, an den wir das Frame schicken */
|
|
/* (z.B. das Gateway). Wenn der Eintrag kein Gateway aufweist, dann */
|
|
/* die Zieladdresse nehmen. Wenn das Gateway nicht das Ziel ist, aber */
|
|
/* strictes Routen gefordert wurde, denn Fehler melden ! */
|
|
gateway = rp->gateway == 0L ? ip.dest : rp->gateway;
|
|
if (strict && gateway != ip.dest)
|
|
{
|
|
icmp_output(&ip, mbhd, ICMP_DEST_UNREACH,
|
|
ICMP_ROUTE_FAIL, NULLICMP);
|
|
ipOutNoRoutes++;
|
|
return;
|
|
}
|
|
|
|
/* Maximale Blockgroese lesen, auf Segmentation pruefen Bei NET/ROM */
|
|
/* wird immer eine MTU von 236 angenommen, da NET/ROM selber einen */
|
|
/* Segmenter enthaelt, wird dieser notfalls zuschlagen. */
|
|
#ifndef KERNELIF
|
|
mtu = (rp->port == NETROM_PORT) ? 236 : portpar[rp->port].mtu;
|
|
#else
|
|
switch(rp->port)
|
|
{
|
|
case NETROM_PORT: mtu = 236;
|
|
break;
|
|
/* Fuer den Kernel eine Extrawurst */
|
|
case KERNEL_PORT: mtu = 1500;
|
|
break;
|
|
|
|
default: mtu = portpar[rp->port].mtu;
|
|
}
|
|
#endif
|
|
|
|
/* Frame ist klein genug, dass es ohne Fragmentierung geroutet werden kann */
|
|
/* Alle Frames vom Kernel sollten hier lang gehen */
|
|
if (ip.length <= mtu)
|
|
{
|
|
if ((tbp = htonip(&ip, mbhd, 0)) == NULL)
|
|
return;
|
|
|
|
send_ip_mb(tbp, rp->port, gateway, ip.tos);
|
|
return;
|
|
}
|
|
|
|
/* Das Frame ist zu gross, duerfen wir es zerlegen ? */
|
|
if (ip.flags.df && rp->port == NETROM) /* nein, Fehler melden */
|
|
{
|
|
union icmp_args icmp_args;
|
|
|
|
icmp_args.mtu = mtu;
|
|
icmp_output(&ip, mbhd, ICMP_DEST_UNREACH,
|
|
ICMP_FRAG_NEEDED, &icmp_args);
|
|
ipFragFails++;
|
|
return;
|
|
}
|
|
|
|
/* Das Frame bei NETROM aufspalten */
|
|
if (rp->port == NETROM)
|
|
{
|
|
offset = ip.offset;
|
|
mf_flag = ip.flags.mf;
|
|
while (length != 0)
|
|
{
|
|
unsigned fragsize;
|
|
|
|
ip.offset = offset;
|
|
if (length + ip_len <= mtu)
|
|
{
|
|
fragsize = length;
|
|
ip.flags.mf = mf_flag;
|
|
}
|
|
else
|
|
{
|
|
fragsize = (mtu - ip_len) & 0xfff8;
|
|
ip.flags.mf = 1;
|
|
}
|
|
ip.length = fragsize + ip_len;
|
|
if ((tbp = htonip(&ip, NULLBUF, 0)) == NULL)
|
|
return;
|
|
|
|
for (i = fragsize; i != 0; i--)
|
|
putchr(getchr(mbhd), tbp);
|
|
send_ip_mb(tbp, rp->port, gateway, ip.tos);
|
|
ipFragCreates++;
|
|
offset += fragsize;
|
|
length -= fragsize;
|
|
}
|
|
}
|
|
|
|
/* Frame ist zu gross, aber wir nehmen eine AX25- Fragmentierung vor */
|
|
else
|
|
{
|
|
if ((tbp = htonip(&ip, mbhd, 0)) == NULL)
|
|
return;
|
|
|
|
send_ip_mb(tbp, rp->port, gateway, ip.tos);
|
|
}
|
|
ipFragOKs++;
|
|
return;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : In der Routing-Tabelle den Weg zu einem Ziel suchen
|
|
*
|
|
* Inputs : IP addresse
|
|
*
|
|
* Returns : Entweder zeiger auf den Tabelleneintrag oder NULL
|
|
*
|
|
* Operation: Erst schauen ob der Cache-Eintrag passt, ansonsten wird die
|
|
* Tabelle in absteigender Reihenfolge der Addressbits, wenn
|
|
* einer passt, gehts los
|
|
*----------------------------------------------------------------------*/
|
|
IP_ROUTE *
|
|
rt_find(register ipaddr target)
|
|
{
|
|
register IP_ROUTE *iprp;
|
|
ipaddr temp = target;
|
|
register unsigned bits = 32;
|
|
|
|
/* Routentabelle durchgehen, passenden Eintrag suchen */
|
|
for (iprp = (IP_ROUTE *)IP_Routes.head;
|
|
iprp != (IP_ROUTE *)&IP_Routes;
|
|
iprp = (IP_ROUTE *)iprp->nextip)
|
|
{
|
|
if (bits > iprp->bits)
|
|
temp &= ~0L << (32 - (bits = iprp->bits));
|
|
|
|
/* Route gefunden */
|
|
if (iprp->dest == temp)
|
|
return (iprp);
|
|
}
|
|
|
|
return (NULLROUTE);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : den IP-Header aufbauen und in ein Buffer speichern
|
|
*
|
|
* Inputs : Zeiger auf den Header, den Buffer, Daten & Ckecksum Flag
|
|
*
|
|
* Returns : Zeiger auf den neuen Buffer im Netzwerk-format
|
|
*
|
|
* Operation: einen neuen Buffer erstellen, den Header abspeichern,
|
|
* und wenn data nicht NULL ist, die Daten reinspeichern
|
|
*----------------------------------------------------------------------*/
|
|
MBHEAD *
|
|
htonip(register IP * iphdr, MBHEAD *data, BOOLEAN cflag)
|
|
{
|
|
unsigned hdr_len;
|
|
register unsigned i;
|
|
register MBHEAD *bufpoi;
|
|
unsigned fl_offs;
|
|
unsigned checksum;
|
|
char huge *ptr,
|
|
huge * cksum_ptr;
|
|
|
|
hdr_len = IPLEN + iphdr->optlen;
|
|
if ((bufpoi = ((MBHEAD *)allocb(ALLOC_MBHEAD))) == NULL)
|
|
return(NULL);
|
|
|
|
#ifdef __WIN32__
|
|
putchr((char)((IPVERSION << 4) | (hdr_len >> 2)), bufpoi);
|
|
#else
|
|
putchr((IPVERSION << 4) | (hdr_len >> 2), bufpoi);
|
|
#endif /* WIN32 */
|
|
putchr(iphdr->tos, bufpoi);
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)iphdr->length, bufpoi);
|
|
put16((unsigned short)iphdr->id, bufpoi);
|
|
#else
|
|
put16(iphdr->length, bufpoi);
|
|
put16(iphdr->id, bufpoi);
|
|
#endif /* WIN32 */
|
|
fl_offs = iphdr->offset >> 3;
|
|
if (iphdr->flags.df)
|
|
fl_offs |= 0x4000;
|
|
if (iphdr->flags.mf)
|
|
fl_offs |= 0x2000;
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)fl_offs, bufpoi);
|
|
#else
|
|
put16(fl_offs, bufpoi);
|
|
#endif /* WIN32 */
|
|
putchr(iphdr->ttl, bufpoi);
|
|
putchr(iphdr->protocol, bufpoi);
|
|
cksum_ptr = bufpoi->mbbp;
|
|
put16(0, bufpoi);
|
|
put32(iphdr->source, bufpoi);
|
|
put32(iphdr->dest, bufpoi);
|
|
for (i = 0; i < iphdr->optlen; i++)
|
|
putchr(iphdr->options[i], bufpoi);
|
|
ptr = bufpoi->mbbp;
|
|
i = bufpoi->mbpc;
|
|
rwndmb(bufpoi);
|
|
#ifdef __WIN32__
|
|
checksum = cflag ? iphdr->checksum : cksum(NULLHEADER, bufpoi, (unsigned short)hdr_len);
|
|
#else
|
|
checksum = cflag ? iphdr->checksum : cksum(NULLHEADER, bufpoi, hdr_len);
|
|
#endif /* WIN32 */
|
|
bufpoi->mbbp = cksum_ptr;
|
|
bufpoi->mbpc = 10;
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)checksum, bufpoi);
|
|
#else
|
|
put16(checksum, bufpoi);
|
|
#endif /* WIN32 */
|
|
bufpoi->mbbp = ptr;
|
|
bufpoi->mbpc = i;
|
|
if (data != NULL)
|
|
{
|
|
i = data->mbpc - data->mbgc;
|
|
while (i--)
|
|
putchr(getchr(data), bufpoi);
|
|
}
|
|
return (bufpoi);
|
|
}
|
|
|
|
/* ***********************************************************************
|
|
* Function : Ein IP datagramm senden
|
|
* Modelled after the example interface on p 32 of RFC 791
|
|
*
|
|
* Inputs :
|
|
*
|
|
* Returns :
|
|
*
|
|
* Operation: Netzwerk-Header erzeugen, Daten anfuegen und so tun, als ob
|
|
* wir das Frame empfangen haetten
|
|
* ---------------------------------------------------------------------*/
|
|
int
|
|
ip_send(ipaddr source, /* source address */
|
|
ipaddr dest, /* Destination address */
|
|
unsigned protocol, /* Protocol */
|
|
unsigned tos, /* Type of service */
|
|
unsigned ttl, /* Time-to-live */
|
|
MBHEAD *bp, /* Data portion of datagram */
|
|
unsigned short length, /* Optional length of data portion */
|
|
unsigned short id, /* Optional identification */
|
|
unsigned df) /* Don't-fragment flag */
|
|
{
|
|
register MBHEAD *tbp;
|
|
IP ip; /* Pointer to IP header */
|
|
register IP *ipptr = &ip;
|
|
static unsigned short id_cntr; /* Datagram serial number */
|
|
|
|
ipOutRequests++;
|
|
|
|
if (length == 0 && bp != NULL)
|
|
length = bp->mbpc - bp->mbgc;
|
|
|
|
/* Fill in IP header */
|
|
ipptr->tos = tos;
|
|
ipptr->length = IPLEN + length;
|
|
ipptr->id = (id == 0) ? id_cntr++ : id;
|
|
ipptr->offset = 0;
|
|
ipptr->flags.mf = 0;
|
|
ipptr->flags.df = df;
|
|
ipptr->ttl = (ttl == 0) ? ipDefaultTTL : ttl;
|
|
ipptr->protocol = protocol;
|
|
ipptr->source = source;
|
|
ipptr->dest = dest;
|
|
ipptr->optlen = 0;
|
|
if ((tbp = htonip(&ip, bp, 0)) == NULL)
|
|
{
|
|
dealmb(bp);
|
|
return(1);
|
|
}
|
|
dealmb(bp);
|
|
tbp->l2fflg = L2CIP;
|
|
rwndmb(tbp);
|
|
tbp->l2port = NETROM_PORT; /* der Port ist immer eingeschaltet */
|
|
relink((LEHEAD *)tbp, (LEHEAD *)iprxfl.tail);
|
|
return (0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Ip Router Interface zu NET/ROM
|
|
*
|
|
* Inputs : Frame zum senden, die Gateway-Addresse, tos-flag
|
|
*
|
|
* Returns : nix
|
|
*
|
|
* Operation: Das Frame wird nach der arp-Tabelle addressiert und in die
|
|
* L3-Sendeliste gehaengt
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
nr_iface(MBHEAD *mhbp, ipaddr gateway)
|
|
{
|
|
register unsigned i;
|
|
register MBHEAD *mb;
|
|
register ARP_TAB *arp;
|
|
NODE *np;
|
|
|
|
/* den passenden ARP-Eintrag suchen und pruefen, ob der Node bekannt */
|
|
/* und erreichbar ist */
|
|
if ( (arp = res_arp(gateway, ARP_NETROM)) != NULLARP
|
|
&& (iscall(arp->callsign, &np, NULL, DG)))
|
|
{
|
|
l4pidx = l4pcid = NR_PROTO_IP; /* NETROM IP Family */
|
|
l4ahd2 = l4ahd3 = 0; /* unbenutzt ... */
|
|
l4aopc = NR4_OP_PID; /* NET/ROM Opcode fuer IP */
|
|
mb = gennhd(); /* L3/L4 Header erzeugen */
|
|
rwndmb(mhbp); /* Zurueckspulen zum senden */
|
|
i = mhbp->mbpc - mhbp->mbgc; /* Daten kopieren */
|
|
while (i--)
|
|
putchr(getchr(mhbp), mb);
|
|
mb->l2link = (LNKBLK *)np; /* Zielnode setzen */
|
|
mb->l4type = L4TNORMAL; /* Prioritaet setzen */
|
|
relink((LEHEAD *)mb, (LEHEAD *)l3txl.tail); /* nur umhaengen */
|
|
}
|
|
dealmb(mhbp);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : AX.25 Handler fuer den ip router
|
|
*
|
|
* Inputs : wie oben fuer NET/ROM
|
|
*
|
|
* Returns : nothing
|
|
*
|
|
* Operation: Feststellen, ob dg oder vc, dann Frame senden
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
l2_iface(MBHEAD *mhbp, unsigned port, ipaddr gateway, unsigned tos)
|
|
{
|
|
register ARP_TAB *arp;
|
|
PTCENT *ptcp;
|
|
#ifdef EAX25
|
|
MHEARD *mhp = NULL;
|
|
#endif
|
|
|
|
|
|
/* IP-Pid setzen */
|
|
rwndmb(mhbp);
|
|
mhbp->l2fflg = L2CIP;
|
|
|
|
/* find the arp entry. Die if none ! */
|
|
if ((arp = res_arp(gateway, ARP_AX25)) == NULLARP)
|
|
{
|
|
arp_request(gateway, ARP_AX25, port);
|
|
dealmb(mhbp);
|
|
}
|
|
|
|
/* Now check to see if we are going to DG or VC it */
|
|
else
|
|
if ( (arp->dgmode & 1)
|
|
|| ( (arp->dgmode == 0)
|
|
&& ( tos & DELAY
|
|
|| ( !(tos & RELIABILITY)
|
|
/* && (ipPar[port].ipMode & DG_OK) */
|
|
))))
|
|
{
|
|
#ifdef __WIN32__
|
|
sdui(arp->digi, arp->callsign, myid, (char)port, mhbp);
|
|
#else
|
|
sdui(arp->digi, arp->callsign, myid, port, mhbp);
|
|
#endif /* WIN32 */
|
|
dealmb(mhbp);
|
|
}
|
|
else
|
|
/* Virtual Circuit */
|
|
{
|
|
#ifdef __WIN32__
|
|
lnkpoi = getlnk((unsigned char)port, myid, arp->callsign, arp->digi);
|
|
#else
|
|
lnkpoi = getlnk(port, myid, arp->callsign, arp->digi);
|
|
#endif /* WIN32 */
|
|
if (lnkpoi)
|
|
{
|
|
if (lnkpoi->state == L2SDSCED)
|
|
{
|
|
ptcp = ptctab + g_uid(lnkpoi, L2_USER);
|
|
ptcp->state = D_IPLINK;
|
|
ptcp->ublk = NULL;
|
|
ptcp->p_uid = NO_UID;
|
|
#ifdef EAX25
|
|
/* TEST DG9OBU */
|
|
/* Call in L2-MHeard suchen */
|
|
if ((mhp = mh_lookup(&l2heard, arp->callsign)) != NULL)
|
|
{
|
|
if ( (mhp->eax_link == TRUE) /* mit EAX.25 gehoert */
|
|
&& (portpar[mhp->port].eax_behaviour >= 1) /* und auf Port erlaubt */
|
|
)
|
|
{
|
|
lnkpoi->bitmask = 0x7F;
|
|
#ifdef __WIN32__
|
|
lnkpoi->maxframe = (unsigned char)portpar[lnkpoi->liport].maxframe_eax;
|
|
#else
|
|
lnkpoi->maxframe = portpar[lnkpoi->liport].maxframe_eax;
|
|
#endif /* WIN32 */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
newlnk(); /* eventuell erst aufbauen */
|
|
}
|
|
rwndmb(mhbp);
|
|
i3tolnk(mhbp->l2fflg, lnkpoi, mhbp); /* -> ab in den Link */
|
|
}
|
|
else
|
|
dealmb(mhbp);
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Function : Reverse ARP fuer eine Addresse/Hardwaretyp durchfuehren
|
|
*
|
|
* Inputs : Pointer to internet address and a hardware ( arp ) type
|
|
*
|
|
* Returns : Pointer to entry in arp table or a null pointer
|
|
*
|
|
* Operation: Die Tabelle linear durchsuchen ob ein Eintrag passt
|
|
*----------------------------------------------------------------------*/
|
|
ARP_TAB *
|
|
res_arp(register ipaddr target, register unsigned hwtype)
|
|
{
|
|
register ARP_TAB *arprp;
|
|
|
|
for (arprp = (ARP_TAB *) Arp_tab.head;
|
|
arprp != (ARP_TAB *) & Arp_tab;
|
|
arprp = (ARP_TAB *) arprp->nextar)
|
|
#ifdef __WIN32__
|
|
if ( (char)hwtype == arprp->hwtype
|
|
#else
|
|
if ( hwtype == arprp->hwtype
|
|
#endif /* WIN32 */
|
|
&& arprp->dest == target)
|
|
return (arprp);
|
|
return (NULLARP);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Eine ICMP-Antwort an den Absender des Frames zurueck
|
|
* schicken, der Aufrufer gibt das Frame frei!
|
|
*
|
|
* Inputs :
|
|
*
|
|
* Returns : nix
|
|
*
|
|
* Operation: Did you ever hear the one about the vampire rabbit ?
|
|
* Note lots of standard icmp bits are commented out.
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
icmp_output(IP *ip, /* Header of offending datagram */
|
|
register MBHEAD *data, /* Data portion of datagram */
|
|
unsigned type, /* Codes to send */
|
|
unsigned code,
|
|
union icmp_args *args)
|
|
{
|
|
MBHEAD *bp,
|
|
*bp2;
|
|
ICMP icmp; /* ICMP protocol header */
|
|
unsigned short length; /* Total length of reply */
|
|
register unsigned short i;
|
|
char huge *rxnxt;
|
|
|
|
if ((unsigned char)ip->protocol == ICMP_PTCL)
|
|
{
|
|
/* Den Header durchsuchen, ob es sicher ist, eine ICMP Nachricht */
|
|
/* zurueckzuschicken */
|
|
rxnxt = data->mbbp;
|
|
i = getchr(data) & 0xff;
|
|
data->mbbp = rxnxt;
|
|
data->mbgc--;
|
|
switch (i)
|
|
{
|
|
case ICMP_ECHO_REPLY:
|
|
case ICMP_ECHO:
|
|
case ICMP_TIMESTAMP:
|
|
case ICMP_TIME_REPLY:
|
|
case ICMP_INFO_RQST:
|
|
case ICMP_INFO_REPLY:
|
|
break; /* These are all safe */
|
|
default:
|
|
/* Auf eine Fehlermeldung keine Fehlermeldung senden (gibt */
|
|
/* sonst einen netten Ping-Pong) */
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Berechnen, wieviel wir vom Frame zurueckschicken wollen, das sind */
|
|
/* maximal der fremde Header und 8 Bytes */
|
|
i = data->mbpc - data->mbgc;
|
|
if (i > 8)
|
|
i = 8;
|
|
length = i + ICMPLEN + IPLEN + ip->optlen;
|
|
|
|
/* Den Header neu aufbauen */
|
|
if ((bp = htonip(ip, NULLBUF, 1)) == NULL)
|
|
return;
|
|
|
|
/* Die Antwort-Daten hineinkopieren */
|
|
while (i--)
|
|
putchr(getchr(data), bp);
|
|
icmp.type = type;
|
|
icmp.code = code;
|
|
icmp.args.unused = 0;
|
|
|
|
switch (type)
|
|
{
|
|
/* case ICMP_ECHO:
|
|
icmpOutEchos++;
|
|
break;
|
|
|
|
case ICMP_ECHO_REPLY:
|
|
icmpOutEchoReps++;
|
|
break;
|
|
|
|
case ICMP_INFO_RQST:
|
|
break;
|
|
|
|
case ICMP_INFO_REPLY:
|
|
break;
|
|
|
|
case ICMP_TIMESTAMP:
|
|
icmpOutTimestamps++;
|
|
break;
|
|
|
|
case ICMP_ADDR_MASK:
|
|
icmpOutAddrMasks++;
|
|
break;
|
|
|
|
case ICMP_ADDR_MASK_REPLY:
|
|
icmpOutAddrMaskReps++;
|
|
break;
|
|
|
|
case ICMP_TIME_EXCEED:
|
|
icmpOutTimeExcds++;
|
|
break;
|
|
|
|
case ICMP_QUENCH:
|
|
icmpOutSrcQuenchs++;
|
|
break;
|
|
*/
|
|
case ICMP_PARAM_PROB:
|
|
/* icmpOutParmProbs++;
|
|
*/ icmp.args.pointer = args->pointer;
|
|
break;
|
|
|
|
case ICMP_REDIRECT:
|
|
/* icmpOutRedirects++;
|
|
*/ icmp.args.address = args->address;
|
|
break;
|
|
|
|
case ICMP_TIME_REPLY:
|
|
/* icmpOutTimestampReps++;
|
|
*/ icmp.args.echo.id = args->echo.id;
|
|
icmp.args.echo.seq = args->echo.seq;
|
|
break;
|
|
|
|
case ICMP_DEST_UNREACH:
|
|
if (icmp.code == ICMP_FRAG_NEEDED)
|
|
icmp.args.mtu = args->mtu;
|
|
/* icmpOutDestUnreachs++;
|
|
*/ break;
|
|
}
|
|
|
|
/* Jetzt generieren wir das eigentliche ICMP-Frame */
|
|
if ((bp2 = htonicmp(&icmp, bp)) == NULL)
|
|
{
|
|
dealmb(bp);
|
|
return;
|
|
}
|
|
dealmb(bp);
|
|
|
|
ip_send(my_ip_addr, ip->source, ICMP_PTCL, ip->tos,
|
|
0, bp2, length, 0, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Einen ICMP Echo Request erzeugen und absenden
|
|
*
|
|
* Inputs : Zieladdresse, Sequenznummer und id, ein optionales
|
|
* Laengenfeld (maximal 4 Bytes) zur freien Verwendung
|
|
*
|
|
* Returns : int - TRUE wenn das Frame erzeugt wurde
|
|
*
|
|
* Operation: Ein Frame anlegen und an die Zieladdresse schicken
|
|
*----------------------------------------------------------------------*/
|
|
BOOLEAN
|
|
pingem(ipaddr target, int seq, int id, int len, char *opt)
|
|
{
|
|
MBHEAD *bp,
|
|
*data;
|
|
ICMP icmp; /* ICMP protocol header */
|
|
|
|
/* Pruefen, ob Ziel irgendwie erreichbar ist */
|
|
if (rt_find(target) == NULLROUTE)
|
|
return (FALSE);
|
|
|
|
if ((data = ((MBHEAD *)allocb(ALLOC_MBHEAD))) == NULL)
|
|
return(FALSE);
|
|
|
|
put32(tic10, data); /* aktuelle Uhrzeit hineinschreiben */
|
|
put32((ULONG)userpo, data); /* und den User */
|
|
while (len--)
|
|
putchr(*opt++, data); /* Optionsfeld schreiben */
|
|
|
|
/* icmpOutEchos++; icmpOutMsgs++; */
|
|
|
|
icmp.type = ICMP_ECHO;
|
|
icmp.code = 0;
|
|
icmp.args.echo.seq = seq;
|
|
icmp.args.echo.id = id;
|
|
|
|
if ((bp = (htonicmp(&icmp, data))) == NULL)
|
|
{
|
|
dealmb(data);
|
|
return(FALSE);
|
|
}
|
|
|
|
dealmb(data);
|
|
if (ip_send(my_ip_addr, target, ICMP_PTCL, LOW_DELAY, 0, bp, 0, 0, 0) == TRUE)
|
|
return(FALSE);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Einen ICMP-Header erzeugen, Daten hineinkopieren
|
|
*
|
|
* Inputs : Zeiger auf den ICMP-Header und Daten
|
|
*
|
|
* Returns : Zeiger auf das fertige Frame
|
|
*
|
|
* Operation: Well, there was this traveller in Transylvania,
|
|
*----------------------------------------------------------------------*/
|
|
MBHEAD *
|
|
htonicmp(register ICMP * icmp, MBHEAD *data)
|
|
{
|
|
register MBHEAD *bp;
|
|
unsigned short checksum;
|
|
register unsigned putcnt;
|
|
/* char huge *nxtchr; */
|
|
char huge *cksum_ptr;
|
|
|
|
if ((bp = ((MBHEAD *)allocb(ALLOC_MBHEAD))) == NULL)
|
|
return(NULL);
|
|
|
|
putchr(icmp->type, bp);
|
|
putchr(icmp->code, bp);
|
|
cksum_ptr = bp->mbbp;
|
|
put16(0, bp); /* Clear checksum */
|
|
|
|
switch (icmp->type)
|
|
{
|
|
case ICMP_DEST_UNREACH:
|
|
put16(0, bp);
|
|
if (icmp->code == ICMP_FRAG_NEEDED) /* Deering/Mogul max MTU
|
|
indication */
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)icmp->args.mtu, bp);
|
|
#else
|
|
put16(icmp->args.mtu, bp);
|
|
#endif /* WIN32 */
|
|
else
|
|
put16(0, bp);
|
|
break;
|
|
|
|
case ICMP_PARAM_PROB:
|
|
putchr(icmp->args.pointer, bp);
|
|
putchr(0, bp);
|
|
put16(0, bp);
|
|
break;
|
|
|
|
case ICMP_REDIRECT:
|
|
put32(icmp->args.address, bp);
|
|
break;
|
|
|
|
case ICMP_ECHO:
|
|
case ICMP_ECHO_REPLY:
|
|
case ICMP_TIMESTAMP:
|
|
case ICMP_TIME_REPLY:
|
|
case ICMP_INFO_RQST:
|
|
case ICMP_INFO_REPLY:
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)icmp->args.echo.id, bp);
|
|
put16((unsigned short)icmp->args.echo.seq, bp);
|
|
#else
|
|
put16(icmp->args.echo.id, bp);
|
|
put16(icmp->args.echo.seq, bp);
|
|
#endif /* WIN32 */
|
|
break;
|
|
|
|
default:
|
|
put16(0, bp);
|
|
put16(0, bp);
|
|
break;
|
|
}
|
|
rwndmb(data);
|
|
putcnt = data->mbpc;
|
|
while (putcnt--)
|
|
putchr(getchr(data), bp);
|
|
|
|
/* Compute checksum, and stash result */
|
|
putcnt = bp->mbpc;
|
|
rwndmb(bp);
|
|
checksum = cksum(NULLHEADER, bp, bp->mbpc);
|
|
bp->mbbp = cksum_ptr;
|
|
bp->mbpc = 2;
|
|
put16(checksum, bp);
|
|
bp->mbpc = putcnt;
|
|
rwndmb(bp);
|
|
return (bp);
|
|
}
|
|
|
|
/* ***********************************************************************
|
|
* Function : Behandlung von eingehenden ICMP-Frames
|
|
*
|
|
* Inputs : Dekodierter IP-Header und Framedaten
|
|
*
|
|
* Returns : nix
|
|
*
|
|
* Operation: Nur eine sehr einfache ICMP-Behandlung durchfuehren, um
|
|
* PING-Anfragen zu beantworten.
|
|
* ---------------------------------------------------------------------*/
|
|
void
|
|
icmp_input(register IP * ip, register MBHEAD *bp)
|
|
{
|
|
MBHEAD *tbp;
|
|
register MBHEAD *bp2;
|
|
ICMP icmp;
|
|
unsigned length,
|
|
i;
|
|
ULONG ping_tic;
|
|
USRBLK *ping_user;
|
|
char buf[50];
|
|
UWORD adr[4];
|
|
|
|
length = ip->length - IPLEN - ip->optlen;
|
|
#ifdef __WIN32__
|
|
if (cksum(NULLHEADER, bp, (unsigned short)length) != 0)
|
|
#else
|
|
if (cksum(NULLHEADER, bp, length) != 0)
|
|
#endif /* WIN32 */
|
|
return;
|
|
if (bp->mbpc - bp->mbgc < 8)
|
|
return;
|
|
icmp.type = getchr(bp);
|
|
icmp.code = getchr(bp);
|
|
|
|
/* fremde Pings beantworten */
|
|
if (icmp.type == ICMP_ECHO)
|
|
{
|
|
get16(bp);
|
|
icmp.args.echo.id = get16(bp);
|
|
icmp.args.echo.seq = get16(bp);
|
|
icmp.type = ICMP_ECHO_REPLY;
|
|
bp2 = (MBHEAD *)allocb(ALLOC_MBHEAD);
|
|
if (length > 8)
|
|
{
|
|
i = length - 8;
|
|
while (i--)
|
|
putchr(getchr(bp), bp2);
|
|
}
|
|
if ((tbp = htonicmp(&icmp, bp2)) == NULL)
|
|
{
|
|
dealmb(bp2);
|
|
return;
|
|
}
|
|
dealmb(bp2);
|
|
ip_send(ip->dest, ip->source, ICMP_PTCL,
|
|
#ifdef __WIN32__
|
|
ip->tos, 0, tbp, (unsigned char)length, 0, 0);
|
|
#else
|
|
ip->tos, 0, tbp, length, 0, 0);
|
|
#endif /* WIN32 */
|
|
return;
|
|
}
|
|
|
|
/* eigene Pings dem User ausgeben */
|
|
if (icmp.type == ICMP_ECHO_REPLY)
|
|
{
|
|
get16(bp);
|
|
get16(bp); /* id */
|
|
get16(bp); /* seq */
|
|
ping_tic = get32(bp);
|
|
ping_user = (void *)get32(bp);
|
|
|
|
ping_tic = (tic10 - ping_tic) * 10;
|
|
if (ping_tic <= 10)
|
|
ping_tic = 10;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
#ifdef __WIN32__
|
|
adr[i] = (unsigned short)(ip->source >> 8 * i) & 0xff;
|
|
#else
|
|
adr[i] = (ip->source >> 8 * i) & 0xff;
|
|
#endif /* WIN32 */
|
|
sprintf(buf, "%d.%d.%d.%d rtt = %lums, ttl = %u",
|
|
adr[3], adr[2], adr[1], adr[0], ping_tic, ip->ttl);
|
|
#ifdef SEND_ASYNC_RESFIX
|
|
/* Sicher ist sicher. */
|
|
buf[256] = 0;
|
|
#endif /* SEND_ASYNC_RESFIX */
|
|
send_async_response(ping_user, "Ping response from ", buf);
|
|
}
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Ein "end-around-carry adjustment" durchfuehren
|
|
*
|
|
* Inputs : aktuelle Checksumme
|
|
*
|
|
* Returns : korrigierte Pruefsumme
|
|
*
|
|
* Operation:
|
|
*
|
|
*----------------------------------------------------------------------*/
|
|
unsigned short
|
|
eac(long sum)
|
|
{
|
|
register unsigned short csum;
|
|
|
|
#ifdef __WIN32__
|
|
sum = csum = (sum >> 16) + (sum & 0xffff);
|
|
#else
|
|
while ((csum = sum >> 16) != 0)
|
|
sum = csum + (sum & 0xffffL);
|
|
#endif /* WIN32 */
|
|
return ((unsigned short)(sum & 0xffffL)); /* nur 16 bits */
|
|
}
|
|
|
|
/* ***********************************************************************
|
|
* Function : Checksum an mhtyp, with optional pseudo-header
|
|
*
|
|
* Inputs : pseudo header, buffer to checksum and byte count
|
|
*
|
|
* Returns : unsigned integer checksum with eac corrected
|
|
*
|
|
* Operation: add up all bytes in a long, in perverse arpa way then eac
|
|
* ---------------------------------------------------------------------*/
|
|
unsigned short
|
|
cksum(register PSEUDO_HEADER * ph, register MBHEAD *m,
|
|
register unsigned short len)
|
|
{
|
|
long sum;
|
|
unsigned rxcnt;
|
|
char huge *rxchr;
|
|
|
|
sum = 0L;
|
|
|
|
/* Sum pseudo-header, if present */
|
|
if (ph != NULLHEADER)
|
|
{
|
|
#ifndef L1TCPIP
|
|
sum = ((unsigned *)(&ph->source))[0];
|
|
sum += ((unsigned *)(&ph->source))[1];
|
|
sum += ((unsigned *)(&ph->dest))[0];
|
|
sum += ((unsigned *)(&ph->dest))[1];
|
|
sum += ((unsigned)ph->protocol & 0xff);
|
|
sum += ((unsigned)ph->length);
|
|
#else
|
|
sum += (ph->source & 0xffffUL);
|
|
sum += ((ph->source >> 16) & 0xffffUL);
|
|
sum += (ph->dest & 0xffffUL);
|
|
sum += ((ph->dest >> 16) & 0xffffUL);
|
|
sum += (ph->protocol & 0xff);
|
|
sum += (ph->length);
|
|
#endif /* L1TCPIP */
|
|
}
|
|
|
|
rxcnt = m->mbgc;
|
|
rxchr = m->mbbp;
|
|
while (len > 0)
|
|
{
|
|
if (len > 1)
|
|
{
|
|
sum += (unsigned)get16(m);
|
|
len -= 2;
|
|
}
|
|
else
|
|
{
|
|
#ifndef L1TCPIP
|
|
sum += ((unsigned)getchr(m) & 0xFF00);
|
|
#else
|
|
sum += ((getchr(m) << 8) & 0xFF00);
|
|
#endif /* L1TCPIP */
|
|
len--;
|
|
}
|
|
}
|
|
m->mbgc = rxcnt;
|
|
m->mbbp = rxchr;
|
|
return ((unsigned short)(~eac(sum) & 0xffff));
|
|
}
|
|
|
|
/* **********************************************************************
|
|
* Function : ARP service zur Beantwortung von ARP-Requests und
|
|
* die Auswertung der Antworten
|
|
*
|
|
* Inputs : Zeiger auf das ARP-Frame
|
|
*
|
|
* Returns : nix
|
|
*
|
|
* Outputs : UI Frame mit dem Ergebnis der Bearbeitung
|
|
*
|
|
* Operation: Wenn nach uns gefragt wurde, oder nach einem Eintrag, der
|
|
* als published gekennzeichnet ist, dann beantworten
|
|
* ---------------------------------------------------------------------*/
|
|
void
|
|
arp_service(MBHEAD *mhbp)
|
|
{
|
|
unsigned char arp_not_revarp;
|
|
/* char *ptr; */
|
|
register MBHEAD *mbhd = mhbp;
|
|
register ARP_TAB *ap;
|
|
register unsigned i;
|
|
ARP_TAB *atp;
|
|
IP_ROUTE *ipr;
|
|
|
|
/* ARP auf dem Port erlaubt ? */
|
|
if (!(IPpar[mbhd->l2port].ipMode & ARP_OK))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Hardware korrekt ? */
|
|
if ((arp.hardware = get16(mbhd)) != ARP_AX25)
|
|
{
|
|
/* arp_stat.badtype++; */
|
|
return;
|
|
}
|
|
|
|
/* Protokoll ok ? */
|
|
if ((arp.protocol = get16(mbhd)) != L2CIP)
|
|
{
|
|
/* arp_stat.badtype++; */
|
|
return;
|
|
}
|
|
|
|
arp.hwalen = getchr(mbhd);
|
|
arp.pralen = getchr(mbhd);
|
|
|
|
/* Laenge(n) ok ? */
|
|
if (arp.hwalen > MAXHWALEN || arp.pralen != sizeof(ipaddr))
|
|
{
|
|
/* arp_stat.badlen++; */
|
|
return;
|
|
}
|
|
|
|
/* Opcode */
|
|
arp.opcode = get16(mbhd);
|
|
|
|
/* Quell- und Ziel-Adressen (jeweils Call und IP-Adress) */
|
|
getfid((char *)arp.shwaddr, mbhd);
|
|
arp.sprotaddr = get32(mbhd);
|
|
getfid((char *)arp.thwaddr, mbhd);
|
|
arp.tprotaddr = get32(mbhd);
|
|
|
|
/* Frame an "QST ? */
|
|
if (cmpid((char *)arp.shwaddr, QST))
|
|
{
|
|
/* arp_stat.badaddr++; */
|
|
return;
|
|
}
|
|
|
|
ap = res_arp(arp.sprotaddr, arp.hardware);
|
|
|
|
/* IP-Adresse anhand des ARP-Requests lernen */
|
|
if ( (((i = is_my_ip_addr(arp.tprotaddr)) != 0) && ap == NULLARP)
|
|
|| (ap != NULLARP && ap->timer != 0))
|
|
{
|
|
/* ARP-Eintrag machen (mit Timeout) */
|
|
arp_add(arp.sprotaddr, mbhd->l2port, (char *)arp.shwaddr, "", 2, ARPtimer, 1, FALSE);
|
|
|
|
/* Falls der Weg zum neu eingetragenen Host nicht oder von einer */
|
|
/* Route erfasst wird, die die Frames auf einem anderen Port als dem */
|
|
/* Port auf dem das ARP empfangen wurde aussenden wuerde, dann eine */
|
|
/* explizite /32 Route zu diesem Host auf dem ARP-Empfangsport eintragen. */
|
|
ipr = rt_find((ipaddr)arp.sprotaddr);
|
|
|
|
if ( (ipr == NULLROUTE)
|
|
|| ( (ipr != NULLROUTE)
|
|
&& (ipr->port != mbhd->l2port)
|
|
)
|
|
)
|
|
rt_add(arp.sprotaddr, 32, 0L, mbhd->l2port, 0, 0, 0, TRUE);
|
|
}
|
|
|
|
if ( arp.opcode == REVARP_REQUEST
|
|
|| ( arp.opcode == ARP_REQUEST
|
|
&& ( (i /* = is_my_ip_addr(&arp.tprotaddr) */ )
|
|
|| ( (ap = res_arp(arp.tprotaddr, arp.hardware)) != NULLARP
|
|
&& ap->publish_flag))))
|
|
{
|
|
arp_not_revarp = (arp.opcode == ARP_REQUEST);
|
|
if (!arp_not_revarp)
|
|
for (atp = (ARP_TAB *) Arp_tab.head;
|
|
atp != (ARP_TAB *) & Arp_tab;
|
|
atp = (ARP_TAB *) atp->nextar)
|
|
if ((i = cmpid(atp->callsign, (char *)arp.thwaddr)) != 0)
|
|
break;
|
|
if (arp_not_revarp || (i && ap->publish_flag))
|
|
{
|
|
if (arp_not_revarp)
|
|
{
|
|
cpyid((char *)arp.thwaddr, (char *)arp.shwaddr);
|
|
/* if (arp.hardware == ARP_AX25) */
|
|
arp.thwaddr[arp.hwalen - 1] |= 1;
|
|
}
|
|
|
|
cpyid((char *)arp.shwaddr, i ? myid : ap->callsign);
|
|
arp.tprotaddr = arp_not_revarp ? arp.sprotaddr : ap->dest;
|
|
arp.sprotaddr = i ? my_ip_addr : ap->dest;
|
|
arp.opcode = arp_not_revarp ? ARP_REPLY : REVARP_REPLY;
|
|
arp_send(mhbp->l2port, (char *)arp.thwaddr);
|
|
/* Arp_stat.inreq++; */
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Einen ARP request/response Frame senden ( L2 AX25 )
|
|
*
|
|
* Inputs : Internes ARP-Frame und Port
|
|
*
|
|
* Returns : nix
|
|
*
|
|
* Outputs : UI Frame mit ARP request/response
|
|
*
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
arp_send(unsigned port, char *hwaddr)
|
|
{
|
|
register MBHEAD *mbhd;
|
|
|
|
mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD);
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)arp.hardware, mbhd);
|
|
put16((unsigned short)arp.protocol, mbhd);
|
|
#else
|
|
put16(arp.hardware, mbhd);
|
|
put16(arp.protocol, mbhd);
|
|
#endif /* WIN32 */
|
|
putchr(arp.hwalen, mbhd);
|
|
putchr(arp.pralen, mbhd);
|
|
#ifdef __WIN32__
|
|
put16((unsigned short)arp.opcode, mbhd);
|
|
#else
|
|
put16(arp.opcode, mbhd);
|
|
#endif /* WIN32 */
|
|
putfid((char *)arp.shwaddr, mbhd);
|
|
put32(arp.sprotaddr, mbhd);
|
|
putfid((char *)arp.thwaddr, mbhd);
|
|
put32(arp.tprotaddr, mbhd);
|
|
mbhd->l2fflg = L2CARP;
|
|
rwndmb(mbhd);
|
|
#ifdef __WIN32__
|
|
sdui("", hwaddr, myid, (char)port, mbhd);
|
|
#else
|
|
sdui("", hwaddr, myid, port, mbhd);
|
|
#endif /* WIN32 */
|
|
dealmb(mbhd);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : Ein ARP request Frame senden (L2 AX25 UI)
|
|
*
|
|
* Inputs : Internes ARP-Frame und der port
|
|
*
|
|
* Returns : nix
|
|
*
|
|
* Outputs : UI Frame mit ARP request senden
|
|
*
|
|
*----------------------------------------------------------------------*/
|
|
void
|
|
arp_request(ipaddr gateway, unsigned hwtype, unsigned port)
|
|
{
|
|
register unsigned i;
|
|
|
|
arp.hardware = hwtype;
|
|
arp.protocol = L2CIP;
|
|
arp.hwalen = L2IDLEN;
|
|
arp.pralen = sizeof(ipaddr);
|
|
arp.opcode = ARP_REQUEST;
|
|
cpyid((char *)arp.shwaddr, myid);
|
|
arp.sprotaddr = my_ip_addr;
|
|
arp.tprotaddr = gateway;
|
|
for (i = 0; i < L2IDLEN; i++)
|
|
arp.thwaddr[i] = 0;
|
|
arp_send(port, QST);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* Neue Status-Meldung verarbeiten */
|
|
/* 0=nicht verwendet, 1=connectet, 2=disconnectet, 3=busy, 4=Failure */
|
|
/*----------------------------------------------------------------------*/
|
|
BOOLEAN
|
|
l2toip(WORD status)
|
|
{
|
|
ARP_TAB *ap;
|
|
PTCENT *ptcp;
|
|
const char *viap;
|
|
|
|
viap = ndigipt(lnkpoi->viaidl);
|
|
|
|
if (!cmpid(lnkpoi->srcid, myid))
|
|
return (FALSE);
|
|
for (ap = (ARP_TAB *) Arp_tab.head;
|
|
ap != (ARP_TAB *) & Arp_tab;
|
|
ap = (ARP_TAB *) ap->nextar)
|
|
if ( (ap->port == lnkpoi->liport)
|
|
&& cmpidl(ap->digi, viap)
|
|
&& cmpid(ap->callsign, lnkpoi->dstid))
|
|
{
|
|
ptcp = ptctab + g_uid(lnkpoi, L2_USER);
|
|
switch (status)
|
|
{
|
|
case L2MCONNT:
|
|
case L2MLRESF:
|
|
case L2MLREST:
|
|
if (ptcp->state != D_IPLINK)
|
|
ptcp->state = U_IPLINK;
|
|
ptcp->ublk = NULL;
|
|
ptcp->p_uid = NO_UID;
|
|
break;
|
|
|
|
case L2MDISCF:
|
|
case L2MBUSYF:
|
|
case L2MFAILW:
|
|
clrptc(g_uid(lnkpoi, L2_USER));
|
|
}
|
|
return (TRUE); /* Meldung verarbeitet */
|
|
}
|
|
return (FALSE);
|
|
}
|
|
#endif
|
|
|
|
/* End of src/l3ip.c */
|