/* Low level AX.25 frame processing - address header */ #include #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 /* 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 */ int digisent = 0; /* DG2KK: counts frames to be digipeated */ /* Send IP datagrams across an AX.25 link */ int ax_send(bp,interface,gateway,precedence,delay,throughput,reliability) struct mbuf *bp; struct interface *interface; int32 gateway; char precedence; char delay; char throughput; char reliability; { char *hw_addr,*res_arp(); struct ax25_cb *axp,*find_ax25(),*open_ax25(); struct ax25 addr; struct ax25_addr destaddr; struct mbuf *tbp; extern int16 axwindow; void ax_incom(); int16 size,bsize,seq; if((hw_addr = res_arp(interface,ARP_AX25,gateway,bp)) == NULLCHAR) return; /* Wait for address resolution */ if(delay || (!reliability && (interface->flags == DATAGRAM_MODE))){ /* Use UI frame */ (*interface->output)(interface,hw_addr, interface->hwaddr,PID_FIRST|PID_LAST|PID_IP,bp); return; } /* 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 || axp->state != CONNECTED){ /* Open a new connection or reinitialize the old one */ atohax25(&addr,hw_addr,(struct ax25_addr *)interface->hwaddr); axp = open_ax25(&addr,axwindow,ax_incom,NULLVFP,NULLVFP,interface,(char *)0); if(axp == NULLAX25){ free_p(bp); return; } } /* If datagram is too big for one frame, send all but the last with * the extension PID. Note: the copy to a new buf is necessary because * AX.25 may continue retransmitting the frame after a local TCB has * gone away, and using the buf directly would cause heap garbage to be * transmitted. Besides, nobody would ever use AX.25 anywhere * high performance is needed anyway... */ bsize = len_mbuf(bp); seq = 0; while(bsize != 0){ size = min(bsize,axp->paclen); /* Allocate buffer, allowing space for PID */ if((tbp = alloc_mbuf(size + 1)) == NULLBUF) break; /* out of memory! */ *tbp->data = PID_IP; if(seq++ == 0) *tbp->data |= PID_FIRST; /* First in sequence */ if(size == bsize) *tbp->data |= PID_LAST; /* That's all of it */ /* else more to follow */ tbp->cnt = 1; tbp->cnt += pullup(&bp,tbp->data + 1,size); send_ax25(axp,tbp); bsize -= size; } free_p(bp); /* Shouldn't be necessary */ } /* Add AX.25 link header and send packet. * Note that the calling order here must match ec_output * since ARP also uses it. */ ax_output(interface,dest,source,pid,bp) struct interface *interface; char *dest; /* Destination AX.25 address (7 bytes, shifted) */ /* Also includes digipeater string */ char *source; /* Source AX.25 address (7 bytes, shifted) */ char pid; /* Protocol ID */ struct mbuf *bp; /* Data field (follows PID) */ { struct mbuf *abp,*cbp,*htonax25(); struct ax25 addr; atohax25(&addr,dest,(struct ax25_addr *)source); if((abp = htonax25(&addr)) == NULLBUF){ free_p(bp); return; } /* Allocate mbuf for control and PID fields, and fill in */ if((cbp = alloc_mbuf((int16)2)) == NULLBUF){ free_p(abp); free_p(bp); return; } cbp->data[0] = UI; cbp->data[1] = pid; cbp->cnt = 2; /* Link everything together and ship it */ abp->next = cbp; cbp->next = bp; (*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. */ int ax_recv(interface,bp) struct interface *interface; struct mbuf *bp; { void ip_route(),arp_input(); struct ax25_addr *ap; struct mbuf *htonax25(),*hbp; char multicast = 0; char nrnodes = 0; /* DG2KK */ char control; struct ax25 hdr; struct ax25_cb *axp,*find_ax25(),*cr_ax25(); struct ax25_addr ifcall; extern struct ax25_addr nr_nodebc; /* we need to use the call for 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; } /* 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 */ /* Count frames to be digipeated, even if digipeat is off * (DG2KK) */ if (addreq(ap,&mycall)) digisent++; /* Check if packet is directed to us as a digipeater */ if(digipeat && addreq(ap,&mycall)){ /* Yes, kick it back out */ ap->ssid |= REPEATED; if((hbp = htonax25(&hdr)) != NULLBUF){ hbp->next = bp; if(interface->forw != NULLIF) (*interface->forw->raw)(interface->forw,hbp); else (*interface->raw)(interface,hbp); bp = NULLBUF; } } 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,&mycall)){ /* DG2KK: was: &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(control == UI){ char pid; (void) pullchar(&bp); if(pullup(&bp,&pid,1) != 1) return; /* No PID */ /* DG2KK: new from netrom version */ if (nrnodes) { if ((pid & (PID_FIRST | PID_LAST | PID_PID)) == (PID_NETROM | PID_FIRST | PID_LAST)) nr_nodercv(interface,&hdr.source,bp); else /* regular UI packets to "nodes" aren't for us */ free_p(bp); return; } else { /* Handle packets. Multi-frame messages are not allowed */ switch(pid & (PID_FIRST | PID_LAST | PID_PID)){ case (PID_IP | PID_FIRST | PID_LAST): ip_route(bp,multicast); break; case (PID_ARP | PID_FIRST | PID_LAST): arp_input(interface,bp); break; default: free_p(bp); break; } return; } } /* If the packet was an I packet not directed to us, * we should drop it here (shouldn't we, Phil?) */ if (nrnodes || multicast) { 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 */ ASSIGN(axp->addr.dest,hdr.source); ASSIGN(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++){ ASSIGN(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); } /* General purpose AX.25 frame output */ sendframe(axp,cmdrsp,ctl,bp) struct ax25_cb *axp; char cmdrsp; char ctl; struct mbuf *bp; { struct mbuf *hbp,*cbp,*htonax25(); if(axp == NULL){ printf("NULL AXP!!\n"); return; } if(axp->interface == NULLIF){ printf("NULL IF PTR!!\n"); return; } axp->addr.cmdrsp = cmdrsp; /* Create address header */ hbp = htonax25(&axp->addr); /* Add control field */ if((cbp = alloc_mbuf(1)) == NULLBUF){ free_p(bp); free_p(hbp); return; } *cbp->data = ctl; cbp->cnt = 1; /* Link together and send */ cbp->next = bp; hbp->next = cbp; if(axp->interface->raw != NULL) (*axp->interface->raw)(axp->interface,hbp); else { printf("NULL RAW POINTER!!\n"); fflush(stdout); } if(cmdrsp == COMMAND) start_timer(&axp->t1); } /* Initialize AX.25 entry in arp device table */ axarp() { int psax25(),setpath(); memcpy(axbdcst,ax25_bdcst.call,ALEN); axbdcst[ALEN] = ax25_bdcst.ssid; arp_init(ARP_AX25,AXALEN,PID_FIRST|PID_LAST|PID_IP, PID_FIRST|PID_LAST|PID_ARP,axbdcst,psax25,setpath); }