00001
00041 #include "ax25.h"
00042 #include "cfg/cfg_ax25.h"
00043
00044 #include <algo/crc_ccitt.h>
00045
00046 #define LOG_LEVEL AX25_LOG_LEVEL
00047 #define LOG_FORMAT AX25_LOG_FORMAT
00048 #include <cfg/log.h>
00049
00050 #include <string.h>
00051 #include <ctype.h>
00052
00053 #if CONFIG_AX25_RPT_LST
00054 #define AX25_SET_REPEATED(msg, idx, val) \
00055 do \
00056 { \
00057 if (val) \
00058 (msg)->rpt_flags |= BV(idx) ; \
00059 else \
00060 (msg)->rpt_flags &= ~BV(idx) ; \
00061 } while(0)
00062 #endif
00063
00064 #define DECODE_CALL(buf, addr) \
00065 for (unsigned i = 0; i < sizeof((addr)); i++) \
00066 { \
00067 char c = (*(buf)++ >> 1); \
00068 (addr)[i] = (c == ' ') ? '\x0' : c; \
00069 }
00070
00071 static void ax25_decode(AX25Ctx *ctx)
00072 {
00073 AX25Msg msg;
00074 uint8_t *buf = ctx->buf;
00075
00076 DECODE_CALL(buf, msg.dst.call);
00077 msg.dst.ssid = (*buf++ >> 1) & 0x0F;
00078
00079 DECODE_CALL(buf, msg.src.call);
00080 msg.src.ssid = (*buf >> 1) & 0x0F;
00081
00082 LOG_INFO("SRC[%.6s-%d], DST[%.6s-%d]\n", msg.src.call, msg.src.ssid, msg.dst.call, msg.dst.ssid);
00083
00084
00085 #if CONFIG_AX25_RPT_LST
00086 for (msg.rpt_cnt = 0; !(*buf++ & 0x01) && (msg.rpt_cnt < countof(msg.rpt_lst)); msg.rpt_cnt++)
00087 {
00088 DECODE_CALL(buf, msg.rpt_lst[msg.rpt_cnt].call);
00089 msg.rpt_lst[msg.rpt_cnt].ssid = (*buf >> 1) & 0x0F;
00090 AX25_SET_REPEATED(&msg, msg.rpt_cnt, (*buf & 0x80));
00091
00092 LOG_INFO("RPT%d[%.6s-%d]%c\n", msg.rpt_cnt,
00093 msg.rpt_lst[msg.rpt_cnt].call,
00094 msg.rpt_lst[msg.rpt_cnt].ssid,
00095 (AX25_REPEATED(&msg, msg.rpt_cnt) ? '*' : ' '));
00096 }
00097 #else
00098 while (!(*buf++ & 0x01))
00099 {
00100 char rpt[6];
00101 uint8_t ssid;
00102 DECODE_CALL(buf, rpt);
00103 ssid = (*buf >> 1) & 0x0F;
00104 LOG_INFO("RPT[%.6s-%d]\n", rpt, ssid);
00105 }
00106 #endif
00107
00108 msg.ctrl = *buf++;
00109 if (msg.ctrl != AX25_CTRL_UI)
00110 {
00111 LOG_WARN("Only UI frames are handled, got [%02X]\n", msg.ctrl);
00112 return;
00113 }
00114
00115 msg.pid = *buf++;
00116 if (msg.pid != AX25_PID_NOLAYER3)
00117 {
00118 LOG_WARN("Only frames without layer3 protocol are handled, got [%02X]\n", msg.pid);
00119 return;
00120 }
00121
00122 msg.len = ctx->frm_len - 2 - (buf - ctx->buf);
00123 msg.info = buf;
00124 LOG_INFO("DATA: %.*s\n", msg.len, msg.info);
00125
00126 if (ctx->hook)
00127 ctx->hook(&msg);
00128 }
00129
00130
00141 void ax25_poll(AX25Ctx *ctx)
00142 {
00143 int c;
00144
00145 while ((c = kfile_getc(ctx->ch)) != EOF)
00146 {
00147 if (!ctx->escape && c == HDLC_FLAG)
00148 {
00149 if (ctx->frm_len >= AX25_MIN_FRAME_LEN)
00150 {
00151 if (ctx->crc_in == AX25_CRC_CORRECT)
00152 {
00153 LOG_INFO("Frame found!\n");
00154 ax25_decode(ctx);
00155 }
00156 else
00157 {
00158 LOG_INFO("CRC error, computed [%04X]\n", ctx->crc_in);
00159 }
00160 }
00161 ctx->sync = true;
00162 ctx->crc_in = CRC_CCITT_INIT_VAL;
00163 ctx->frm_len = 0;
00164 continue;
00165 }
00166
00167 if (!ctx->escape && c == HDLC_RESET)
00168 {
00169 LOG_INFO("HDLC reset\n");
00170 ctx->sync = false;
00171 continue;
00172 }
00173
00174 if (!ctx->escape && c == AX25_ESC)
00175 {
00176 ctx->escape = true;
00177 continue;
00178 }
00179
00180 if (ctx->sync)
00181 {
00182 if (ctx->frm_len < CONFIG_AX25_FRAME_BUF_LEN)
00183 {
00184 ctx->buf[ctx->frm_len++] = c;
00185 ctx->crc_in = updcrc_ccitt(c, ctx->crc_in);
00186 }
00187 else
00188 {
00189 LOG_INFO("Buffer overrun");
00190 ctx->sync = false;
00191 }
00192 }
00193 ctx->escape = false;
00194 }
00195
00196 if (kfile_error(ctx->ch))
00197 {
00198 LOG_ERR("Channel error [%04x]\n", kfile_error(ctx->ch));
00199 kfile_clearerr(ctx->ch);
00200 }
00201 }
00202
00203 static void ax25_putchar(AX25Ctx *ctx, uint8_t c)
00204 {
00205 if (c == HDLC_FLAG || c == HDLC_RESET
00206 || c == AX25_ESC)
00207 kfile_putc(AX25_ESC, ctx->ch);
00208 ctx->crc_out = updcrc_ccitt(c, ctx->crc_out);
00209 kfile_putc(c, ctx->ch);
00210 }
00211
00212 static void ax25_sendCall(AX25Ctx *ctx, const AX25Call *addr, bool last)
00213 {
00214 unsigned len = MIN(sizeof(addr->call), strlen(addr->call));
00215
00216 for (unsigned i = 0; i < len; i++)
00217 {
00218 uint8_t c = addr->call[i];
00219 ASSERT(isalnum(c) || c == ' ');
00220 c = toupper(c);
00221 ax25_putchar(ctx, c << 1);
00222 }
00223
00224
00225 if (len < sizeof(addr->call))
00226 for (unsigned i = 0; i < sizeof(addr->call) - len; i++)
00227 ax25_putchar(ctx, ' ' << 1);
00228
00229
00230
00231
00232 uint8_t ssid = 0x60 | (addr->ssid << 1) | (last ? 0x01 : 0);
00233 ax25_putchar(ctx, ssid);
00234 }
00235
00245 void ax25_sendVia(AX25Ctx *ctx, const AX25Call *path, size_t path_len, const void *_buf, size_t len)
00246 {
00247 const uint8_t *buf = (const uint8_t *)_buf;
00248 ASSERT(path);
00249 ASSERT(path_len >= 2);
00250
00251 ctx->crc_out = CRC_CCITT_INIT_VAL;
00252 kfile_putc(HDLC_FLAG, ctx->ch);
00253
00254
00255
00256 for (size_t i = 0; i < path_len; i++)
00257 ax25_sendCall(ctx, &path[i], (i == path_len - 1));
00258
00259 ax25_putchar(ctx, AX25_CTRL_UI);
00260 ax25_putchar(ctx, AX25_PID_NOLAYER3);
00261
00262 while (len--)
00263 ax25_putchar(ctx, *buf++);
00264
00265
00266
00267
00268
00269 uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff;
00270 uint8_t crch = (ctx->crc_out >> 8) ^ 0xff;
00271 ax25_putchar(ctx, crcl);
00272 ax25_putchar(ctx, crch);
00273
00274 ASSERT(ctx->crc_out == AX25_CRC_CORRECT);
00275
00276 kfile_putc(HDLC_FLAG, ctx->ch);
00277 }
00278
00279 static void print_call(KFile *ch, const AX25Call *call)
00280 {
00281 kfile_printf(ch, "%.6s", call->call);
00282 if (call->ssid)
00283 kfile_printf(ch, "-%d", call->ssid);
00284 }
00285
00291 void ax25_print(KFile *ch, const AX25Msg *msg)
00292 {
00293 print_call(ch, &msg->src);
00294 kfile_putc('>', ch);
00295 print_call(ch, &msg->dst);
00296
00297 #if CONFIG_AX25_RPT_LST
00298 for (int i = 0; i < msg->rpt_cnt; i++)
00299 {
00300 kfile_putc(',', ch);
00301 print_call(ch, &msg->rpt_lst[i]);
00302
00303
00304 if (AX25_REPEATED(msg, i))
00305 kfile_putc('*', ch);
00306 }
00307 #endif
00308
00309 kfile_printf(ch, ":%.*s\n", msg->len, msg->info);
00310 }
00311
00312
00320 void ax25_init(AX25Ctx *ctx, KFile *channel, ax25_callback_t hook)
00321 {
00322 ASSERT(ctx);
00323 ASSERT(channel);
00324
00325 memset(ctx, 0, sizeof(*ctx));
00326 ctx->ch = channel;
00327 ctx->hook = hook;
00328 ctx->crc_in = ctx->crc_out = CRC_CCITT_INIT_VAL;
00329 }