home *** CD-ROM | disk | FTP | other *** search
- /* Low level AX.25 frame processing - address header */
-
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <ctype.h>
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "timer.h"
- #include "arp.h"
- #include "slip.h"
- #include "ax25.h"
- #include "lapb.h"
- #include "netrom.h"
- #include "ip.h"
-
- /* AX.25 broadcast address: "QST-0" in shifted ascii */
- struct ax25_addr ax25_bdcst = {
- 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1,
- ('0'<<1) | E,
- };
- char axbdcst[AXALEN]; /* Same thing, network format */
- struct ax25_addr mycall;
- int digipeat = 1; /* Controls digipeating */
- int32 digisent = 0; /* Number of digipeated packets */
- struct ax25mh mhlist[40]; /* mheard list - 40 entries */
-
- /* Send IP datagrams across an AX.25 link */
- int ax_send(struct mbuf *bp, struct interface *interface, int32 gateway,
- char precedence, char delay, char throughput, char reliability)
- {
- char *hw_addr;
- struct ax25_cb *axp;
- struct ax25 addr;
- struct ax25_addr destaddr;
- struct mbuf *tbp,*bptmp;
- extern int16 axwindow;
- int16 ssize,len,size;
- int segments,first;
-
- throughput = throughput;
- precedence = precedence;
-
- if((hw_addr = res_arp(interface,ARP_AX25,gateway,bp)) == NULLCHAR)
- return 0; /* Wait for address resolution */
-
- if(delay || (!reliability && (interface->flags == DATAGRAM_MODE))){
- /* Use UI frame */
- return (*interface->output)(interface,hw_addr,interface->hwaddr,PID_IP,bp);
- }
- /* Reliability is needed; use I-frames in AX.25 connection */
- memcpy(destaddr.call,hw_addr,ALEN);
- destaddr.ssid = hw_addr[ALEN];
-
- if((axp = find_ax25(&destaddr)) == NULLAX25)
- {
- /* Open a new connection */
- atohax25(&addr,hw_addr,(struct ax25_addr *)interface->hwaddr);
- axp = open_ax25(&addr,axwindow,(void (*)())ax_incom,NULLVFP,NULLVFP,interface,(char *)0);
- if(axp == NULLAX25)
- {
- free_p(bp);
- return -1;
- }
- }
-
- /* New-style frame segmenter. Returns queue of segmented fragments,
- * or original packet if small enough
- * See if packet is too small to segment. Note 1-byte grace factor
- * so the PID will not cause segmentation of a 256-byte IP datagram.
- */
- len = len_mbuf(bp);
- ssize = axp->paclen;
-
- if((bptmp = alloc_mbuf(len+1)) == NULLBUF)
- {
- free_p(bp);
- return -1;
- }
- bptmp->data[0] = PID_IP;
- bptmp->cnt = 1;
- bptmp->cnt += pullup(&bp,bptmp->data+1,len);
-
- if(len <= ssize + 1)
- { /* Too small to segment */
- send_ax25(axp,bptmp);
- return 0;
- }
-
- len = len_mbuf(bptmp);
- ssize -= 2; /* ssize now equal to data portion size */
- segments = 1 + (len - 1) / ssize; /* # segments */
- first = 1;
-
- while(segments != 0){
- size = min(ssize,len_mbuf(bptmp));
- if((tbp = alloc_mbuf(size + 2)) == NULLBUF)
- break;
- tbp->data[0] = PID_SEGMENT;
- tbp->data[1] = --segments;
- if(first){
- tbp->data[1] |= SEG_FIRST;
- first = 0;
- }
- tbp->cnt = 2;
- tbp->cnt += pullup(&bptmp,tbp->data+2,size);
- send_ax25(axp,tbp);
- }
-
- return 0;
- }
- /* Add AX.25 link header and send packet.
- * Note that the calling order here must match ec_output
- * since ARP also uses it.
- */
- int ax_output(struct interface *interface, char *dest, char *source,
- char pid, struct mbuf *data)
- {
- struct mbuf *abp,*cbp;
- struct ax25 addr;
-
- /* Allocate mbuf for control and PID fields, and fill in */
- if((cbp = pushdown(data,2)) == NULLBUF)
- {
- free_p(data);
- return -1;
- }
- cbp->data[0] = UI;
- cbp->data[1] = pid;
-
- atohax25(&addr,dest,(struct ax25_addr *)source);
- if((abp = htonax25(&addr,cbp)) == NULLBUF)
- {
- free_p(cbp); /* Also frees data */
- return -1;
- }
- /* This shouldn't be necessary because redirection has already been
- * done at the IP router layer, but just to be safe...
- */
- if(interface->forw != NULLIF)
- return (*interface->forw->raw)(interface->forw,abp);
- else
- return (*interface->raw)(interface,abp);
- }
- /* Process incoming AX.25 packets.
- * After optional tracing, the address field is examined. If it is
- * directed to us as a digipeater, repeat it. If it is addressed to
- * us or to QST-0, kick it upstairs depending on the protocol ID.
- */
- void ax_recv(struct interface *interface, struct mbuf *bp)
- {
- struct ax25_addr *ap;
- struct mbuf *hbp;
- char multicast;
- int nrnodes = 0;
- int mheard_entry, mheard_work;
- struct ax25_addr mhcall;
- time_t mheard_oldest;
- char control;
- struct ax25 hdr;
- struct ax25_cb *axp;
- struct ax25_addr ifcall;
- extern struct ax25_addr nr_nodebc ;
-
- /* Use the address associated with this interface */
- memcpy(ifcall.call,interface->hwaddr,ALEN);
- ifcall.ssid = interface->hwaddr[ALEN];
-
- /* Pull header off packet and convert to host structure */
- if(ntohax25(&hdr,&bp) < 0)
- {
- /* Something wrong with the header */
- free_p(bp);
- return;
- }
-
- /* mheard capture code lives here */
- mheard_entry = 0; /* start at the top of the list */
- mheard_work = 0; /* used for spotting oldest entry */
- time(&mheard_oldest); /* preload very new! */
- memcpy(&mhcall,&hdr.source,sizeof(struct ax25_addr));
- mhcall.ssid &= SSID; /* remove junk */
-
- for (mheard_work = 0; mheard_work < 40 ;mheard_work++)
- {
- if(memcmp(&mhlist[mheard_work].mheard_call,&mhcall,
- sizeof(struct ax25_addr)) == 0)
- {
- mheard_entry = mheard_work; /* existing entry */
- break; /* exit and update entry */
- }
- else
- {
- if(mhlist[mheard_work].mheard_time < mheard_oldest)
- {
- mheard_entry = mheard_work; /* oldest so far */
- mheard_oldest = mhlist[mheard_work].mheard_time;
- }
- }
- } /* loop until all parsed */
-
- memcpy(&mhlist[mheard_entry].mheard_call,&mhcall,
- sizeof(struct ax25_addr)); /* callsign */
-
- if(hdr.ndigis > 0)
- {
- if(hdr.digis[0].ssid & REPEATED)
- mhlist[mheard_entry].mheard_digi = 1; /* repeated */
- }
- else
- {
- mhlist[mheard_entry].mheard_digi = 0; /* directly */
- }
-
- time(&mhlist[mheard_entry].mheard_time); /* capture time */
-
- /* end of mheard capture code */
-
- /* Scan, looking for our call in the repeater fields, if any.
- * Repeat appropriate packets.
- */
- for(ap = &hdr.digis[0]; ap < &hdr.digis[hdr.ndigis]; ap++){
- if(ap->ssid & REPEATED)
- continue; /* Already repeated */
- /* Check if packet is directed to us as a digipeater */
- if(digipeat && addreq(ap,&ifcall)){
- /* Yes, kick it back out */
- ap->ssid |= REPEATED;
- if((hbp = htonax25(&hdr,bp)) != NULLBUF){
- if(interface->forw != NULLIF)
- (*interface->forw->raw)(interface->forw,hbp);
- else
- (*interface->raw)(interface,hbp);
- bp = NULLBUF;
- digisent++;
- }
- }
- free_p(bp); /* Dispose if not forwarded */
- return;
- }
- /* Packet has passed all repeaters, now look at destination */
- if(addreq(&hdr.dest,&ax25_bdcst)){
- multicast = 1; /* Broadcast packet */
- } else if(addreq(&hdr.dest,&ifcall)){
- multicast = 0; /* Packet directed at us */
- } else if(addreq(&hdr.dest,&nr_nodebc)){
- nrnodes = 1 ;
- } else {
- /* Not for us */
- free_p(bp);
- return;
- }
- if(bp == NULLBUF){
- /* Nothing left */
- return;
- }
- /* Sneak a peek at the control field. This kludge is necessary because
- * AX.25 lacks a proper protocol ID field between the address and LAPB
- * sublayers; a control value of UI indicates that LAPB is to be
- * bypassed.
- */
- control = *bp->data & ~PF;
- if(uchar(control) == UI){
- char pid;
-
- pullchar(&bp);
- if(pullone(&bp,&pid) != 1)
- return; /* No PID */
- /* NET/ROM is very poorly layered. The meaning of the stuff
- * following the PID of CF depends on what's in the AX.25 dest
- * field.
- */
- if(nrnodes){
- if(uchar(pid) == PID_NETROM)
- nr_nodercv(interface,&hdr.source,bp) ;
- else /* regular UI packets to "nodes" aren't for us */
- free_p(bp) ;
- return ;
- }
- /* Handle packets. Multi-frame messages are not allowed */
- switch(pid){
- case PID_IP:
- ip_route(bp,multicast);
- break;
- case PID_ARP:
- arp_input(interface,bp);
- break;
- default:
- free_p(bp);
- break;
- }
- return;
- }
-
- /* Everything from here down is LAPB stuff, so drop anything
- * not directed to us:
- */
-
- if (multicast || nrnodes) {
- free_p(bp) ;
- return ;
- }
-
- /* Find the source address in hash table */
- if((axp = find_ax25(&hdr.source)) == NULLAX25){
- /* Create a new ax25 entry for this guy,
- * insert into hash table keyed on his address,
- * and initialize table entries
- */
- if((axp = cr_ax25(&hdr.source)) == NULLAX25){
- free_p(bp);
- return;
- }
- axp->interface = interface;
- /* Swap source and destination, reverse digi string */
- axp->addr.dest = hdr.source;
- axp->addr.source = hdr.dest;
- if(hdr.ndigis > 0){
- int i,j;
-
- /* Construct reverse digipeater path */
- for(i=hdr.ndigis-1,j=0;i >= 0;i--,j++){
- axp->addr.digis[j] = hdr.digis[i];
- axp->addr.digis[j].ssid &= ~(E|REPEATED);
- }
- /* Scale timers to account for extra delay */
- axp->t1.start *= hdr.ndigis+1;
- axp->t2.start *= hdr.ndigis+1;
- axp->t3.start *= hdr.ndigis+1;
- }
- axp->addr.ndigis = hdr.ndigis;
- }
- if(hdr.cmdrsp == UNKNOWN)
- axp->proto = V1; /* Old protocol in use */
- else
- axp->proto = V2;
-
- lapb_input(axp,hdr.cmdrsp,bp);
- }
- /* Initialize AX.25 entry in arp device table */
- /* General purpose AX.25 frame output */
- int sendframe(struct ax25_cb *axp, char cmdrsp, char ctl,
- struct mbuf *data)
- {
- struct mbuf *hbp,*cbp;
- int i;
-
- if(axp == NULLAX25 || axp->interface == NULLIF)
- return -1;
-
- /* Add control field */
- if((cbp = pushdown(data,1)) == NULLBUF){
- free_p(data);
- return -1;
- }
- cbp->data[0] = ctl;
-
- axp->addr.cmdrsp = cmdrsp;
- /* Create address header */
- if((hbp = htonax25(&axp->addr,cbp)) == NULLBUF){
- free_p(cbp);
- return -1;
- }
- /* The packet is all ready, now send it */
- if(axp->interface->forw != NULLIF)
- i = (*axp->interface->forw->raw)(axp->interface->forw,hbp);
- else
- i = (*axp->interface->raw)(axp->interface,hbp);
-
- return i;
- }
- void axarp(void)
- {
- memcpy(axbdcst,ax25_bdcst.call,ALEN);
- axbdcst[ALEN] = ax25_bdcst.ssid;
-
- arp_init(ARP_AX25,AXALEN,PID_IP,PID_ARP,axbdcst,psax25,setpath);
- }
-