/* AX25 header conversion routines
 * Copyright 1991 Phil Karn, KA9Q
 */
#include "global.h"
#ifdef AX25
#include "mbuf.h"
#include "proc.h"
#include "ax25.h"
  
/* Convert a host-format AX.25 header into a mbuf ready for transmission */
struct mbuf *
htonax25(hdr,data)
register struct ax25 *hdr;
struct mbuf *data;
{
    struct mbuf *bp;
    register char *cp;
    register int16 i;
  
    if(hdr == (struct ax25 *)NULL || hdr->ndigis > MAXDIGIS)
        return NULLBUF;
  
    /* Allocate space for return buffer */
    i = AXALEN * (2 + hdr->ndigis);
    bp = pushdown(data,i);
  
    /* Now convert */
    cp = bp->data;      /* cp -> dest field */
  
    /* Generate destination field */
    memcpy(cp,hdr->dest,AXALEN);
    if(hdr->cmdrsp == LAPB_COMMAND)
        cp[ALEN] |= C;  /* Command frame sets C bit in dest */
    else
        cp[ALEN] &= ~C;
    cp[ALEN] &= ~E; /* Dest E-bit is always off */
  
    cp += AXALEN;       /* cp -> source field */
  
    /* Generate source field */
    memcpy(cp,hdr->source,AXALEN);
    if(hdr->cmdrsp == LAPB_RESPONSE)
        cp[ALEN] |= C;
    else
        cp[ALEN] &= ~C;
    /* Set E bit on source address if no digis */
    if(hdr->ndigis == 0){
        cp[ALEN] |= E;
        return bp;
    }
  
    cp += AXALEN;       /* cp -> first digi field */
  
    /* All but last digi get copied with E bit off */
    for(i=0; i < hdr->ndigis; i++){
        memcpy(cp,hdr->digis[i],AXALEN);
        if(i < hdr->ndigis - 1)
            cp[ALEN] &= ~E;
        else
            cp[ALEN] |= E;  /* Last digipeater has E bit set */
        if(i < hdr->nextdigi)
            cp[ALEN] |= REPEATED;
        else
            cp[ALEN] &= ~REPEATED;
        cp += AXALEN;       /* cp -> next digi field */
    }
    return bp;
}
/* Convert a network-format AX.25 header into a host format structure
 * Return -1 if error, number of addresses if OK
 */
int
ntohax25(hdr,bpp)
register struct ax25 *hdr;  /* Output structure */
struct mbuf **bpp;
{
    register char *axp;
  
    if(pullup(bpp,hdr->dest,AXALEN) < AXALEN)
        return -1;
  
    if(pullup(bpp,hdr->source,AXALEN) < AXALEN)
        return -1;
  
    /* Process C bits to get command/response indication */
    if((hdr->source[ALEN] & C) == (hdr->dest[ALEN] & C))
        hdr->cmdrsp = LAPB_UNKNOWN;
    else if(hdr->source[ALEN] & C)
        hdr->cmdrsp = LAPB_RESPONSE;
    else
        hdr->cmdrsp = LAPB_COMMAND;
  
    hdr->ndigis = 0;
    hdr->nextdigi = 0;
    if(hdr->source[ALEN] & E)
        return 2;   /* No digis */
  
    /* Count and process the digipeaters */
    axp = hdr->digis[0];
    while(hdr->ndigis < MAXDIGIS && pullup(bpp,axp,AXALEN) == AXALEN){
        hdr->ndigis++;
        if(axp[ALEN] & REPEATED)
            hdr->nextdigi++;
        if(axp[ALEN] & E)   /* Last one */
            return hdr->ndigis + 2;
        axp += AXALEN;
    }
    return -1;  /* Too many digis */
}
#endif /* AX25 */
  
