#include #include #include static ssize_t validate_station(void *data, off_t offset) { int i, space = 0; for (i=0; i> 1; if (!PATTY_AX25_ADDRESS_CHAR_VALID(c) || PATTY_AX25_ADDRESS_OCTET_LAST(b)) { errno = EINVAL; goto error; } if (c == ' ' && !space) { space = 1; } else if (space) { errno = EINVAL; goto error; } } return PATTY_AX25_ADDRESS_SIZE; error: return -1; } static ssize_t decode_hops(patty_ax25_frame *frame, void *data, off_t start) { ssize_t decoded; off_t offset = start; int i; patty_ax25_addr *addr = NULL; /* * Try to count the AX.25-specified maximum number of hops in the current * frame. */ for (i=0; ihops++; if (PATTY_AX25_ADDRESS_OCTET_LAST(addr->ssid)) { break; } } /* * If the last hop does not have the address extension bit set, then * that's a big problem. */ if (addr && PATTY_AX25_ADDRESS_OCTET_LAST(addr->ssid)) { errno = EINVAL; goto error; } return offset - start; error: return -1; } static ssize_t decode_address(patty_ax25_frame *frame, void *data, off_t start) { off_t offset = start; ssize_t decoded; if ((decoded = validate_station(data, offset)) < 0) { goto error; } else { offset += decoded; } if ((decoded = validate_station(data, offset)) < 0) { goto error; } else { offset += decoded; } /* * Determine whether the current frame is a Command or Response, and which * version of AX.25 this frame adheres to. */ if (PATTY_AX25_ADDRESS_SSID_C(frame->src.ssid)) { frame->cr = PATTY_AX25_FRAME_RESPONSE; frame->version = PATTY_AX25_ADDRESS_SSID_C(frame->dest.ssid)? PATTY_AX25_2_0: PATTY_AX25_OLD; } else { frame->cr = PATTY_AX25_FRAME_COMMAND; frame->version = PATTY_AX25_ADDRESS_SSID_C(frame->src.ssid)? PATTY_AX25_OLD: PATTY_AX25_2_0; } /* * If the source address is not the final address in the frame, begin * decoding repeater addresses. */ if (!PATTY_AX25_ADDRESS_OCTET_LAST(frame->src.ssid)) { if ((decoded = decode_hops(frame, data, offset)) < 0) { goto error; } else { offset += decoded; } } return offset - start; error: return -1; } static ssize_t decode_info(patty_ax25_frame *frame, void *data, off_t offset, size_t size) { 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->info = (void *)((uint8_t *)data + offset + decoded); frame->len = size - offset - decoded; decoded += frame->len; } return decoded; error: return -1; } ssize_t 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)); /* * First, decode the variable-length Address field. */ if ((decoded = decode_address(frame, data, offset)) < 0) { errno = EIO; goto error_decode; } else { offset += decoded; } /* * Next, decode the remaining Control Field, optional Protocol Identifier * field, and Info payload that may follow. */ if ((decoded = decode_info(frame, data, offset, size)) < 0) { errno = EIO; goto error_decode; } else { offset += decoded; } return offset; error_decode: return -1; } ssize_t patty_ax25_frame_info(patty_ax25_frame *frame, void **info) { if (frame == NULL || frame->info == NULL || info == NULL) { errno = EINVAL; goto error_invalid_args; } *info = frame->info; return frame->len; error_invalid_args: return -1; } int patty_ax25_frame_addresed_to(patty_ax25_frame *frame, const char *station, uint8_t ssid) { return strncmp(frame->dest.callsign, station, PATTY_AX25_CALLSIGN_LEN) == 0 && frame->dest.ssid == ssid; }