/* Low level AX.25 routines: * callsign conversion * control block management * * Copyright 1991 Phil Karn, KA9Q */ #include #include "global.h" #include "mbuf.h" #include "timer.h" #include "ax25.h" #include "lapb.h" #include struct ax25_cb *Ax25_cb; /* Default AX.25 parameters */ int32 T3init = 0; /* No keep-alive polling */ int16 Maxframe = 1; /* Stop and wait */ int16 N2 = 10; /* 10 retries */ int16 Axwindow = 2048; /* 2K incoming text before RNR'ing */ int16 Paclen = 256; /* 256-byte I fields */ int16 Pthresh = 128; /* Send polls for packets larger than this */ int32 Axirtt = 5000; /* Initial round trip estimate, ms */ int16 Axversion = V1; /* Protocol version */ int32 Blimit = 30; /* Retransmission backoff limit */ /* Look up entry in connection table */ struct ax25_cb * find_ax25(addr) register char *addr; { register struct ax25_cb *axp; struct ax25_cb *axlast = NULLAX25; /* Search list */ for(axp = Ax25_cb; axp != NULLAX25; axlast=axp,axp = axp->next){ if(addreq(axp->remote,addr)){ if(axlast != NULLAX25){ /* Move entry to top of list to speed * future searches */ axlast->next = axp->next; axp->next = Ax25_cb; Ax25_cb = axp; } return axp; } } return NULLAX25; } /* Remove entry from connection table */ void del_ax25(conn) struct ax25_cb *conn; { register struct ax25_cb *axp; struct ax25_cb *axlast = NULLAX25; for(axp = Ax25_cb; axp != NULLAX25; axlast=axp,axp = axp->next){ if(axp == conn) break; } if(axp == NULLAX25) return; /* Not found */ /* Remove from list */ if(axlast != NULLAX25) axlast->next = axp->next; else Ax25_cb = axp->next; /* Timers should already be stopped, but just in case... */ stop_timer(&axp->t1); stop_timer(&axp->t3); /* Free allocated resources */ free_q(&axp->txq); free_q(&axp->rxasm); free_q(&axp->rxq); free((char *)axp); } /* Create an ax25 control block. Allocate a new structure, if necessary, * and fill it with all the defaults. The caller * is still responsible for filling in the reply address */ struct ax25_cb * cr_ax25(addr) char *addr; { register struct ax25_cb *axp; if(addr == NULLCHAR) return NULLAX25; if((axp = find_ax25(addr)) == NULLAX25){ /* Not already in table; create an entry * and insert it at the head of the chain */ axp = (struct ax25_cb *)callocw(1,sizeof(struct ax25_cb)); axp->next = Ax25_cb; Ax25_cb = axp; } axp->user = -1; axp->state = LAPB_DISCONNECTED; axp->maxframe = Maxframe; axp->window = Axwindow; axp->paclen = Paclen; axp->proto = Axversion; /* Default, can be changed by other end */ axp->pthresh = Pthresh; axp->n2 = N2; axp->srt = Axirtt; set_timer(&axp->t1,2*axp->srt); axp->t1.func = recover; axp->t1.arg = axp; set_timer(&axp->t3,T3init); axp->t3.func = pollthem; axp->t3.arg = axp; /* Always to a receive and state upcall as default */ axp->r_upcall = s_arcall; axp->s_upcall = s_ascall; return axp; } /* * setcall - convert callsign plus substation ID of the form * "KA9Q-0" to AX.25 (shifted) address format * Address extension bit is left clear * Return -1 on error, 0 if OK */ int setcall(out,call) char *out; char *call; { int csize; unsigned ssid; register int i; register char *dp; char c; if(out == NULLCHAR || call == NULLCHAR || *call == '\0') return -1; /* Find dash, if any, separating callsign from ssid * Then compute length of callsign field and make sure * it isn't excessive */ dp = strchr(call,'-'); if(dp == NULLCHAR) csize = strlen(call); else csize = dp - call; if(csize > ALEN) return -1; /* Now find and convert ssid, if any */ if(dp != NULLCHAR){ dp++; /* skip dash */ ssid = atoi(dp); if(ssid > 15) return -1; } else ssid = 0; /* Copy upper-case callsign, left shifted one bit */ for(i=0;i> 1) & 0x7f; if(c != ' ') *cp++ = c; } if((*addr & SSID) != 0) sprintf(cp,"-%d",(*addr >> 1) & 0xf); /* ssid */ else *cp = '\0'; return e; } /* Figure out the frame type from the control field * This is done by masking out any sequence numbers and the * poll/final bit after determining the general class (I/S/U) of the frame */ int16 ftype(control) register int control; { if((control & 1) == 0) /* An I-frame is an I-frame... */ return I; if(control & 2) /* U-frames use all except P/F bit for type */ return (int16)(uchar(control) & ~PF); else /* S-frames use low order 4 bits for type */ return (int16)(uchar(control) & 0xf); } void lapb_garbage(red) int red; { register struct ax25_cb *axp; for(axp=Ax25_cb;axp != NULLAX25;axp = axp->next){ mbuf_crunch(&axp->rxq); mbuf_crunch(&axp->rxasm); } }