diff --git a/include/patty/ax25/frame.h b/include/patty/ax25/frame.h index 1cba2b0..006663c 100644 --- a/include/patty/ax25/frame.h +++ b/include/patty/ax25/frame.h @@ -12,11 +12,33 @@ + (mode == PATTY_AX25_SOCK_SABME? 2: 1) \ + (infolen > 0? 1 + infolen: 0)) +enum patty_ax25_frame_format { + PATTY_AX25_FRAME_NORMAL, + PATTY_AX25_FRAME_EXTENDED +}; + enum patty_ax25_frame_type { - PATTY_AX25_FRAME_UNKNOWN, - PATTY_AX25_FRAME_INFO, - PATTY_AX25_FRAME_SUPER, - PATTY_AX25_FRAME_UNNUMBERED + PATTY_AX25_FRAME_INFO = 0x00, + PATTY_AX25_FRAME_SUPER = 0x01, + PATTY_AX25_FRAME_UNNUMBERED = 0x03, + PATTY_AX25_FRAME_UNKNOWN = 0xff +}; + +enum patty_ax25_frame_u_type { + PATTY_AX25_FRAME_U_SABME = 0x6f, + PATTY_AX25_FRAME_U_SABM = 0x2f, + PATTY_AX25_FRAME_U_DISC = 0x43, + PATTY_AX25_FRAME_U_DM = 0x0f, + PATTY_AX25_FRAME_U_UA = 0x63, + PATTY_AX25_FRAME_U_FRMR = 0x87, + PATTY_AX25_FRAME_U_UI = 0x03, + PATTY_AX25_FRAME_U_XID = 0x8f, + PATTY_AX25_FRAME_U_TEST = 0xe3 +}; + +enum patty_ax25_frame_u_flags { + PATTY_AX25_FRAME_U_POLL = (1 << 4), + PATTY_AX25_FRAME_U_FINAL = (1 << 4) }; enum patty_ax25_frame_cr { @@ -34,19 +56,42 @@ typedef struct _patty_ax25_frame { uint16_t control; uint8_t proto; - enum patty_ax25_version version; - enum patty_ax25_frame_type type; - enum patty_ax25_frame_cr cr; - void *info; - size_t len; + size_t infolen; } patty_ax25_frame; ssize_t patty_ax25_frame_decode(patty_ax25_frame *frame, - void *data, + enum patty_ax25_frame_format format, + void *src, size_t len); +ssize_t patty_ax25_frame_encode(patty_ax25_frame *frame, + enum patty_ax25_frame_format format, + void *dest, + size_t len); + +enum patty_ax25_version patty_ax25_frame_version(patty_ax25_frame *frame); + +enum patty_ax25_frame_type patty_ax25_frame_type(patty_ax25_frame *frame); + +enum patty_ax25_frame_cr patty_ax25_frame_cr(patty_ax25_frame *frame); + ssize_t patty_ax25_frame_info(patty_ax25_frame *frame, void **info); +void patty_ax25_frame_copy_reply_address(patty_ax25_frame *rx, + patty_ax25_frame *tx); + +void patty_ax25_frame_set(patty_ax25_frame *frame, + uint16_t control, + uint8_t proto, + void *info, + size_t infolen); + +void patty_ax25_frame_set_ui(patty_ax25_frame *frame, + uint8_t flags, + uint8_t proto, + void *info, + size_t infolen); + #endif /* _PATTY_AX25_FRAME_H */ diff --git a/include/patty/ax25/if.h b/include/patty/ax25/if.h index 41655f4..a8e575d 100644 --- a/include/patty/ax25/if.h +++ b/include/patty/ax25/if.h @@ -55,8 +55,9 @@ enum patty_ax25_if_kiss_tnc_info_type { }; typedef struct _patty_ax25_if_kiss_tnc_info { - patty_ax25_addr addr; + patty_ax25_addr addr; enum patty_ax25_if_kiss_tnc_info_type type; + int fd; char path[256]; } patty_ax25_if_kiss_tnc_info; diff --git a/src/decode.c b/src/decode.c index 6d45ad2..f27fa62 100644 --- a/src/decode.c +++ b/src/decode.c @@ -121,17 +121,17 @@ static int frame_fprint(FILE *stream, goto error_io; } - if (frame->type == PATTY_AX25_FRAME_INFO) { + if (PATTY_AX25_CONTROL_INFO(frame->control)) { if (fprintf(stream, " type I poll %d ns %d nr %d info %zu", PATTY_AX25_CONTROL_POLL(frame->control), PATTY_AX25_CONTROL_SEQ_SEND(frame->control), PATTY_AX25_CONTROL_SEQ_RECV(frame->control), - frame->len) < 0) { + frame->infolen) < 0) { goto error_io; } - } else if (frame->type == PATTY_AX25_FRAME_UNNUMBERED) { + } else if (PATTY_AX25_CONTROL_UNNUMBERED(frame->control)) { if (fprintf(stream, " type U info %zu", - frame->len) < 0) { + frame->infolen) < 0) { goto error_io; } } @@ -141,7 +141,7 @@ static int frame_fprint(FILE *stream, } if (frame->info) { - if (hexdump_fprint(stream, frame->info, frame->len) < 0) { + if (hexdump_fprint(stream, frame->info, frame->infolen) < 0) { goto error_io; } } @@ -189,7 +189,7 @@ int main(int argc, char **argv) { break; } - if (patty_ax25_frame_decode(&frame, buf, len) < 0) { + if (patty_ax25_frame_decode(&frame, PATTY_AX25_FRAME_NORMAL, buf, len) < 0) { perror("Unable to decode frame"); goto error_ax25_frame_decode; diff --git a/src/frame.c b/src/frame.c index f1b4d4a..4a3a622 100644 --- a/src/frame.c +++ b/src/frame.c @@ -99,20 +99,6 @@ static ssize_t decode_address(patty_ax25_frame *frame, 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. @@ -141,20 +127,12 @@ static ssize_t decode_info(patty_ax25_frame *frame, int info = 0; 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; @@ -172,11 +150,11 @@ static ssize_t decode_info(patty_ax25_frame *frame, if (info) { decoded++; - frame->proto = ((uint8_t *)data + offset)[1]; - frame->info = (void *)((uint8_t *)data + offset + decoded); - frame->len = size - offset - decoded; + frame->proto = ((uint8_t *)data + offset)[1]; + frame->info = (void *)((uint8_t *)data + offset + decoded); + frame->infolen = size - offset - decoded; - decoded += frame->len; + decoded += frame->infolen; } return decoded; @@ -186,7 +164,8 @@ error: } ssize_t patty_ax25_frame_decode(patty_ax25_frame *frame, - void *data, + enum patty_ax25_frame_format format, + void *src, size_t size) { ssize_t decoded; off_t offset = 0; @@ -196,7 +175,7 @@ ssize_t patty_ax25_frame_decode(patty_ax25_frame *frame, /* * First, decode the variable-length Address field. */ - if ((decoded = decode_address(frame, data, offset)) < 0) { + if ((decoded = decode_address(frame, src, offset)) < 0) { errno = EIO; goto error_decode; @@ -208,7 +187,7 @@ ssize_t patty_ax25_frame_decode(patty_ax25_frame *frame, * 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) { + if ((decoded = decode_info(frame, src, offset, size)) < 0) { errno = EIO; goto error_decode; @@ -222,6 +201,109 @@ error_decode: return -1; } +static ssize_t encode_address(patty_ax25_frame *frame, + void *dest, + size_t len) { + size_t i, + offset = 0, + hops = frame->hops > PATTY_AX25_MAX_HOPS? + PATTY_AX25_MAX_HOPS: frame->hops; + + if ((2 + hops) * sizeof(patty_ax25_addr) > len) { + goto error_toobig; + } + + memcpy((uint8_t *)dest + offset, &frame->dest, sizeof(patty_ax25_addr)); + offset += sizeof(patty_ax25_addr); + ((uint8_t *)dest)[offset-1] &= ~1; + + memcpy((uint8_t *)dest + offset, &frame->src, sizeof(patty_ax25_addr)); + offset += sizeof(patty_ax25_addr); + ((uint8_t *)dest)[offset-1] &= ~1; + + for (i=0; irepeaters[i].callsign[0] == '\0') { + break; + } + + memcpy((uint8_t *)dest + offset, + &frame->repeaters[i], + sizeof(patty_ax25_addr)); + + offset += sizeof(patty_ax25_addr); + } + + ((uint8_t *)dest)[offset-1] |= 1; + + return offset; + +error_toobig: + return -1; +} + +ssize_t patty_ax25_frame_encode(patty_ax25_frame *frame, + enum patty_ax25_frame_format format, + void *dest, + size_t len) { + size_t offset = 0; + + offset = encode_address(frame, dest, len); + + switch (format) { + case PATTY_AX25_FRAME_NORMAL: + ((uint8_t *)dest)[offset++] = frame->control; + + break; + + case PATTY_AX25_FRAME_EXTENDED: + ((uint8_t *)dest)[offset++] = (frame->control & 0xff00) >> 8; + ((uint8_t *)dest)[offset++] = frame->control & 0xf00ff; + + break; + } + + if (PATTY_AX25_CONTROL_INFO(frame->control)) { + if (1 + offset + frame->infolen > len) { + goto error_toobig; + } + + ((uint8_t *)dest)[offset++] = frame->proto; + + memcpy((uint8_t *)dest + offset, frame->info, frame->infolen); + + offset += frame->infolen; + } + + return offset; + +error_toobig: + return -1; +} + +enum patty_ax25_version patty_ax25_frame_version(patty_ax25_frame *frame) { + return PATTY_AX25_ADDRESS_SSID_C(frame->src.ssid) == + PATTY_AX25_ADDRESS_SSID_C(frame->dest.ssid)? + PATTY_AX25_2_0: PATTY_AX25_OLD; +} + +enum patty_ax25_frame_type patty_ax25_frame_type(patty_ax25_frame *frame) { + if (PATTY_AX25_CONTROL_INFO(frame->control)) { + return PATTY_AX25_FRAME_INFO; + } else if (PATTY_AX25_CONTROL_SUPER(frame->control)) { + return PATTY_AX25_FRAME_SUPER; + } else if (PATTY_AX25_CONTROL_UNNUMBERED(frame->control)) { + return PATTY_AX25_FRAME_UNNUMBERED; + } + + return PATTY_AX25_FRAME_UNKNOWN; +} + +enum patty_ax25_frame_cr patty_ax25_frame_cr(patty_ax25_frame *frame) { + return PATTY_AX25_ADDRESS_SSID_C(frame->src.ssid)? + PATTY_AX25_FRAME_RESPONSE: + PATTY_AX25_FRAME_COMMAND; +} + ssize_t patty_ax25_frame_info(patty_ax25_frame *frame, void **info) { if (frame == NULL || frame->info == NULL || info == NULL) { @@ -232,8 +314,47 @@ ssize_t patty_ax25_frame_info(patty_ax25_frame *frame, *info = frame->info; - return frame->len; + return frame->infolen; error_invalid_args: return -1; } + +void patty_ax25_frame_copy_reply_address(patty_ax25_frame *rx, + patty_ax25_frame *tx) { + size_t i, + max = rx->hops > PATTY_AX25_MAX_HOPS? PATTY_AX25_MAX_HOPS: rx->hops; + + memcpy(&tx->dest, &rx->src, sizeof(patty_ax25_addr)); + memcpy(&tx->src, &rx->dest, sizeof(patty_ax25_addr)); + + memset(&tx->repeaters, '\0', sizeof(tx->repeaters)); + + for (i=0; irepeaters[i], &rx->repeaters[max-i-1], sizeof(patty_ax25_addr)); + } + + tx->hops = rx->hops; +} + +void patty_ax25_frame_set(patty_ax25_frame *frame, + uint16_t control, + uint8_t proto, + void *info, + size_t infolen) { + frame->control = control; + frame->proto = proto; + frame->info = info; + frame->infolen = infolen; +} + +void patty_ax25_frame_set_ui(patty_ax25_frame *frame, + uint8_t flags, + uint8_t proto, + void *info, + size_t infolen) { + frame->control = PATTY_AX25_FRAME_U_UI | flags; + frame->proto = proto; + frame->info = info; + frame->infolen = infolen; +} diff --git a/src/server.c b/src/server.c index 10c7659..821bfd8 100644 --- a/src/server.c +++ b/src/server.c @@ -287,6 +287,19 @@ error_dict_delete_established: return -1; } +static int sock_delete_by_addrpair(patty_dict *dict, + patty_ax25_addr *local, + patty_ax25_addr *remote) { + uint32_t hash; + + patty_hash_init(&hash); + patty_ax25_addr_hash(&hash, local); + patty_ax25_addr_hash(&hash, remote); + patty_hash_end(&hash); + + return patty_dict_delete_with_hash(dict, hash); +} + static inline void watch_fd(patty_ax25_server *server, int fd) { FD_SET(fd, &server->fds_watch); @@ -1028,23 +1041,69 @@ static int handle_clients(patty_ax25_server *server) { return patty_dict_each(server->clients, handle_client, server); } -static int handle_packet_rx(patty_ax25_server *server, - patty_ax25_if *iface, - void *buf, - size_t len) { - patty_ax25_frame frame; +static void copy_reply_repeaters(patty_ax25_addr *to, + patty_ax25_addr *from, + unsigned int hops) { + unsigned int i, + max = hops > PATTY_AX25_MAX_HOPS? + PATTY_AX25_MAX_HOPS: hops; - if (patty_ax25_frame_decode(&frame, buf, len) < 0) { + memset(to, '\0', PATTY_AX25_MAX_HOPS * sizeof(patty_ax25_addr)); + + for (i=0; isocks_pending_accept, + &frame_rx.dest)) == NULL) { + + if (send_dm(iface, &frame.src, &frame.dest, NULL) < 0) { + goto error_io; + } + + sock->status = PATTY_AX25_SOCK_ESTABLISHED; + sock->mode = PATTY_AX25_SOCK_SABM; + + memcpy(&sock->local, &frame.dest, sizeof(patty_ax25_sock)); + memcpy(&sock->remote, &frame.src, sizeof(patty_ax25_sock)); + + copy_reply_repeaters(&sock->repeaters, + &frame.repeaters, + sock->hops); + + if (sock_delete_by_addrpair(server->socks_pending_accept, + &sock->local, + &sock->remote) < 0) { + goto error_io; + } + + if (sock_save_by_addrpair(server->socks_established, + sock, + &sock->local, + &sock->remote) < 0) { + goto error_io; + } + } else { + if (send_frmr(iface, &frame.src, &frame.dest, NULL) < 0) { + goto error_io; + } + } + } return 0; @@ -1070,7 +1129,7 @@ static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) { goto done; } - if (handle_packet_rx(server, iface, buf, readlen) < 0) { + if (handle_frame_rx(server, iface, buf, readlen) < 0) { goto error_io; } diff --git a/src/sock.c b/src/sock.c index 047e4d9..3755880 100644 --- a/src/sock.c +++ b/src/sock.c @@ -34,9 +34,11 @@ static size_t copy_addr_to_buf(patty_ax25_sock *sock, uint8_t *buf, size_t offse memcpy(&buf[offset], &sock->remote, sizeof(patty_ax25_addr)); offset += sizeof(patty_ax25_addr); + buf[offset-1] &= ~1; memcpy(&buf[offset], &sock->local, sizeof(patty_ax25_addr)); offset += sizeof(patty_ax25_addr); + buf[offset-1] &= ~1; for (i=0; ihops; i++) { memcpy(&buf[offset], &sock->repeaters[i], sizeof(patty_ax25_addr));