#include #include #include static ssize_t frame_decode_address(patty_ax25_address *address, void *data, off_t offset) { int i, space = 0; uint8_t ssid = ((uint8_t *)data + offset)[6]; /* * First, unpack each callsign octet, ensuring all are within the 7 bit * ASCII space and do not have the extended bit set to 1. */ for (i=0; i<6; i++) { uint8_t b = ((uint8_t *)data + offset)[i]; uint8_t c = b >> 1; if (!PATTY_AX25_ADDRESS_CHAR_VALID(c) || PATTY_AX25_ADDRESS_OCTET_LAST(b)) { errno = EINVAL; goto error; } if (c == ' ') { /* * Take note if we have reached the end of the call sign. */ if (space == 0) { space = 1; } address->callsign[i] = '\0'; } else { /* * If we have already reached the end of the callsign, and a * non-space character is encountered, then the address is * erroneous. */ if (space) { errno = EINVAL; goto error; } address->callsign[i] = c; } } /* * Now, unpack the data from the SSID field. */ address->repeated = PATTY_AX25_ADDRESS_SSID_REPEATED(ssid); address->ssid = PATTY_AX25_ADDRESS_SSID_NUMBER(ssid); address->last = PATTY_AX25_ADDRESS_OCTET_LAST(ssid); return 7; error: return -1; } static ssize_t frame_decode_hops(patty_ax25_frame *frame, void *data, off_t start) { ssize_t decoded; off_t offset = start; int i; /* * Try to decode the AX.25-specified maximum number of hops in the current * frame. */ for (i=0; irepeaters[i], data, offset)) < 0) { goto error; } else { offset += decoded; } frame->hops++; if (frame->repeaters[i].last) { frame->repeated = frame->repeaters[i].repeated; break; } } /* * If the last hop does not have the address extension bit set, then * that's a big problem. */ if (frame->hops && !frame->repeaters[frame->hops-1].last) { errno = EINVAL; goto error; } return offset - start; error: return -1; } static ssize_t frame_decode_control(patty_ax25_frame *frame, void *data, off_t offset) { uint8_t control = ((uint8_t *)data + offset)[0]; size_t decoded = 0; int info = 0; frame->control = control; decoded++; if (PATTY_AX25_CONTROL_INFO(control)) { frame->type = PATTY_AX25_FRAME_INFO; info = 1; } else if (PATTY_AX25_CONTROL_SUPER(control)) { frame->type = PATTY_AX25_FRAME_SUPER; } else if (PATTY_AX25_CONTROL_UNNUMBERED(control)) { frame->type = PATTY_AX25_FRAME_UNNUMBERED; if (PATTY_AX25_CONTROL_UNNUMBERED_INFO(control)) { info = 1; } } else { frame->type = PATTY_AX25_FRAME_UNKNOWN; errno = EINVAL; goto error; } /* * If we've received either an Info or Unnumbered Info frame, then decode * the Protocol Identifier field, and calculate the location and size of * the payload as well. */ if (info) { decoded++; frame->proto = ((uint8_t *)data + offset)[1]; frame->payload = (void *)((uint8_t *)data + offset + decoded); frame->payloadsz = frame->size - offset - decoded; decoded += frame->payloadsz; } return decoded; error: return -1; } int patty_ax25_frame_decode(patty_ax25_frame *frame, void *data, size_t size) { ssize_t decoded; off_t offset = 0; memset(frame, '\0', sizeof(*frame)); frame->size = size; if ((decoded = frame_decode_address(&frame->dest, data, offset)) < 0) { goto error_decode; } else { offset += decoded; } /* * It would be considered erroneous if the destination address did have the * extension bit set to 1. */ if ((decoded = frame_decode_address(&frame->src, data, offset)) < 0) { goto error_decode; } else { offset += decoded; } /* * If the source address is not the final address in the frame, begin * decoding repeater addresses. */ if (!frame->src.last) { if ((decoded = frame_decode_hops(frame, data, offset)) < 0) { goto error_decode; } else { offset += decoded; } } /* * Now, decode the Control Field, as well as any Protocol Identifier that * may follow. */ if ((decoded = frame_decode_control(frame, data, offset)) < 0) { goto error_decode; } else { offset += decoded; } return offset; error_decode: return -1; }