/* process.c Handle processing and routing of AX25 frames * * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc. * This software may be freely used, distributed, or modified, providing * this header is not removed. * * This is the only module that knows about the internal structure of * AX25 frames. */ /* * Dual port additions by M.Durrant VE3PNX and D.J.Dionne Feb 4, 1995 */ #include #include #include #include "ax25ipd.h" /* if dual port the upper nibble will have a value of 1 (not 0) */ #define FROM_PORT2(p) (((*(p+1))&0x10)!=0) #define FOR_PORT2(p) (addrmatch(p,mycallsign2) || addrmatch(p,myalias2)) /* ve3djf and ve3pnx addition above */ #define IS_LAST(p) (((*(p+6))&0x01)!=0) #define NOT_LAST(p) (((*(p+6))&0x01)==0) #define REPEATED(p) (((*(p+6))&0x80)!=0) #define NOTREPEATED(p) (((*(p+6))&0x80)==0) #define IS_ME(p) (addrmatch(p,mycallsign) || addrmatch(p,myalias) || addrmatch(p,mycallsign2) || addrmatch(p,myalias2) ) #define NOT_ME(p) (!(addrmatch(p,mycallsign) || addrmatch(p,myalias) || addrmatch(p,mycallsign2) || addrmatch(p,myalias2) ) ) #define ARE_DIGIS(f) (((*(f+13))&0x01)==0) #define NO_DIGIS(f) (((*(f+13))&0x01)!=0) #define SETREPEATED(p) (*(p+6))|=0x80 #define SETLAST(p) (*(p+6))|=0x01 static unsigned char bcbuf[256]; /* Must be larger than bc_text!!! */ static int bclen; /* The size of bcbuf */ /* * Initialize the process variables */ void process_init(void) { bclen = -1; /* flag that we need to rebuild the bctext */ } /* * handle a frame given us by the kiss routines. The buf variable is * a pointer to an AX25 frame. Note that the AX25 frame from kiss does * not include the CRC bytes. These are computed by this routine, and * it is expected that the buffer we have has room for the CRC bytes. * We will either dump this frame, or send it via the IP interface. * * If we are in digi mode, we validate in several ways: * a) we must be the next digi in line to pick up the packet * b) the next site to get the packet (the next listed digi, or * the destination if we are the last digi) must be known to * us via the route table. * If we pass validation, we then set the digipeated bit for our entry * in the packet, compute the CRC, and send the packet to the IP * interface. * * If we are in tnc mode, we have less work to do. * a) the next site to get the packet (the next listed digi, or * the destination) must be known to us via the route table. * If we pass validation, we compute the CRC, and send the packet to * the IP interface. */ void from_kiss(unsigned char *buf, int l) { unsigned char *a, *ipaddr; if (l < 15) { LOGL2("from_kiss: dumped - length wrong!\n"); stats.kiss_tooshort++; return; } if (loglevel > 2) dump_ax25frame("from_kiss: ", buf, l); if (digi) { /* if we are in digi mode */ a = next_addr(buf); if (NOT_ME(a)) { stats.kiss_not_for_me++; LOGL4("from_kiss: (digi) dumped - not for me\n"); return; } if (a == buf) { /* must be a digi */ stats.kiss_i_am_dest++; LOGL2 ("from_kiss: (digi) dumped - I am destination!\n"); return; } SETREPEATED(a); a = next_addr(buf); /* find who gets it after us */ } else { /* must be tnc mode */ a = next_addr(buf); #ifdef TNC_FILTER if (IS_ME(a)) { LOGL2 ("from_kiss: (tnc) dumped - addressed to self!\n"); return; } #endif } /* end of tnc mode */ /* Lookup the IP address for this route */ ipaddr = call_to_ip(a); if (ipaddr == NULL) { if (is_call_bcast(a)) { /* Warning - assuming buffer has room for 2 bytes */ add_crc(buf, l); l += 2; send_broadcast(buf, l); } else { stats.kiss_no_ip_addr++; LOGL2 ("from_kiss: dumped - cannot figure out where to send this!\n"); } return; } else { /* Warning - assuming buffer has room for 2 bytes */ add_crc(buf, l); l += 2; send_ip(buf, l, ipaddr); if (is_call_bcast(a)) { send_broadcast(buf, l); } } } /* * handle a frame given us by the IP routines. The buf variable is * a pointer to an AX25 frame. * Note that the frame includes the CRC bytes, which we dump ASAP. * We will either dump this frame, or send it via the KISS interface. * * If we are in digi mode, we only validate that: * a) we must be the next digi in line to pick up the packet * If we pass validation, we then set the digipeated bit for our entry * in the packet, and send the packet to the KISS send routine. * * If we are in tnc mode, we validate pretty well nothing, just like a * real TNC... #define FILTER_TNC will change this. * We simply send the packet to the KISS send routine. */ void from_ip(unsigned char *buf, int l) { int port = 0; unsigned char *a; if (!ok_crc(buf, l)) { stats.ip_failed_crc++; LOGL2("from_ip: dumped - CRC incorrect!\n"); return; } l = l - 2; /* dump the blasted CRC */ if (l < 15) { stats.ip_tooshort++; LOGL2("from_ip: dumped - length wrong!\n"); return; } if (loglevel > 2) dump_ax25frame("from_ip: ", buf, l); if (digi) { /* if we are in digi mode */ a = next_addr(buf); if (NOT_ME(a)) { stats.ip_not_for_me++; LOGL2("from_ip: (digi) dumped - not for me!\n"); return; } if (a == buf) { /* must be a digi */ stats.ip_i_am_dest++; LOGL2 ("from_ip: (digi) dumped - I am destination!\n"); return; } if (dual_port == 1 && FOR_PORT2(a)) { port = 0x10; } SETREPEATED(a); } else { /* must be tnc mode */ a = next_addr(buf); #ifdef TNC_FILTER if (NOT_ME(a)) { LOGL2 ("from_ip: (tnc) dumped - I am not destination!\n"); return; } #endif } /* end of tnc mode */ if (!ttyfd_bpq) send_kiss(port, buf, l); else { send_bpq(buf, l); } } /* * Send an ID frame out the KISS port. */ void do_beacon(void) { int i; unsigned char *p; if (bclen == 0) return; /* nothing to do! */ if (bclen < 0) { /* build the id string */ p = bcbuf; *p++ = ('I' << 1); *p++ = ('D' << 1); *p++ = (' ' << 1); *p++ = (' ' << 1); *p++ = (' ' << 1); *p++ = (' ' << 1); *p++ = '\0' | 0x60; /* SSID, set reserved bits */ for (i = 0; i < 6; i++) *p++ = mycallsign[i]; *p++ = mycallsign[6] | 0x60; /* ensure reserved bits are set */ SETLAST(bcbuf + 7); /* Set the E bit -- last address */ *p++ = 0x03; /* Control field -- UI frame */ *p++ = 0xf0; /* Protocol ID -- 0xf0 is no protocol */ strcpy((char *)p, bc_text); /* add the text field */ bclen = 16 + strlen(bc_text); /* adjust the length nicely */ } if (loglevel > 2) dump_ax25frame("do_beacon: ", bcbuf, bclen); stats.kiss_beacon_outs++; if (!ttyfd_bpq) send_kiss(0, bcbuf, bclen); else { send_bpq(bcbuf, bclen); } } /* * return true if the addresses supplied match * modified for wildcarding by vk5xxx */ int addrmatch(unsigned char *a, unsigned char *b) { if ((*a == '\0') || (*b == '\0')) return 0; if ((*a++ ^ *b++) & 0xfe) return 0; /* "K" */ if ((*a++ ^ *b++) & 0xfe) return 0; /* "A" */ if ((*a++ ^ *b++) & 0xfe) return 0; /* "9" */ if ((*a++ ^ *b++) & 0xfe) return 0; /* "W" */ if ((*a++ ^ *b++) & 0xfe) return 0; /* "S" */ if ((*a++ ^ *b++) & 0xfe) return 0; /* "B" */ if (((*b) & 0x1e) == 0) return 1; /* ssid 0 matches all ssid's */ if ((*a++ ^ *b) & 0x1e) return 0; /* ssid */ /* if ((*a++^*b++)&0x1e)return 0; ssid (how it was ...) */ return 1; } /* * return pointer to the next station to get this packet */ unsigned char *next_addr(unsigned char *f) { unsigned char *a; /* If no digis, return the destination address */ if (NO_DIGIS(f)) return f; /* check each digi field. The first one that hasn't seen it is the one */ a = f + 7; do { a += 7; if (NOTREPEATED(a)) return a; } while (NOT_LAST(a)); /* all the digis have seen it. return the destination address */ return f; } /* * tack on the CRC for the frame. Note we assume the buffer is long * enough to have the two bytes tacked on. */ void add_crc(unsigned char *buf, int l) { unsigned short int u; u = compute_crc(buf, l); buf[l] = u & 0xff; /* lsb first */ buf[l + 1] = (u >> 8) & 0xff; /* msb next */ } /* * Dump AX25 frame. */ void dump_ax25frame(char *t, unsigned char *buf, int l) { #ifdef DEBUG int i; #endif unsigned char *a; printf("%s AX25: (l=%3d) ", t, l); if (l < 15) { printf("Bogus size...\n"); return; } printf("%s -> ", call_to_a(buf + 7)); printf("%s", call_to_a(buf)); if (ARE_DIGIS(buf)) { printf(" v"); a = buf + 7; do { a += 7; printf(" %s", call_to_a(a)); if (REPEATED(a)) printf("*"); } while (NOT_LAST(a)); } printf("\n"); #ifdef DEBUG for (i = 0; i < l; i++) printf("%02x ", buf[i]); printf("\n"); #endif fflush(stdout); }