Browse Source

Reflector

master
Jeroen Vreeken 6 years ago
parent
commit
de5e106405
15 changed files with 577 additions and 117 deletions
  1. +10
    -4
      Makefile
  2. +1
    -0
      ca/21c73c2e.0
  3. +14
    -4
      dml_crypto.c
  4. +17
    -1
      dml_packet.c
  5. +296
    -84
      dml_reflector.c
  6. +7
    -0
      dml_reflector.conf
  7. +2
    -2
      dml_stream_client.c
  8. +9
    -3
      dml_streamer_ogg.c
  9. +25
    -18
      dml_trx.c
  10. +8
    -0
      dml_trx.conf
  11. +1
    -1
      dmld.c
  12. +102
    -0
      eth_ar.c
  13. +32
    -0
      eth_ar.h
  14. +46
    -0
      examples.txt
  15. +7
    -0
      key.txt

+ 10
- 4
Makefile View File

@ -18,14 +18,18 @@ DML_SRCS = \
TRX_SRCS = \
trx_codec2.c \
trx_control.c \
trx_sound.c
trx_sound.c \
ETH_AR_SRCS = \
eth_ar.c
DML_OBJS = $(DML_SRCS:.c=.o)
TRX_OBJS = $(TRX_SRCS:.c=.o)
ETH_AR_OBJS = $(ETH_AR_SRCS:.c=.o)
all: dmld dml_list dml_reflector dml_streamer_ogg dml_stream_client dml_trx
SRCS += $(DML_SRCS) $(TRX_SRCS)
SRCS += $(DML_SRCS) $(TRX_SRCS) $(ETH_AR_SRCS)
SRCS += dmld.c
dmld: $(DML_OBJS) dmld.o
@ -34,11 +38,11 @@ SRCS += dml_list.c
dml_list: $(DML_OBJS) dml_list.o
SRCS += dml_reflector.c
dml_reflector: $(DML_OBJS) dml_reflector.o
dml_reflector: $(DML_OBJS) $(ETH_AR_OBJS) dml_reflector.o
SRCS += dml_trx.c trx_sound.c
dml_trx_LDFLAGS += -lasound -lcodec2
dml_trx: $(DML_OBJS) $(TRX_OBJS) dml_trx.o
dml_trx: $(DML_OBJS) $(TRX_OBJS) $(ETH_AR_OBJS) dml_trx.o
SRCS += dml_streamer_ogg.c
dml_streamer_ogg: $(DML_OBJS) dml_streamer_ogg.o
@ -51,6 +55,8 @@ DEPS:=$(SRCS:.c=.d)
OBJS+=$(SRCS:.c=.o)
$(OBJS): Makefile
clean:
rm -rf $(OBJS) \
dml_list \


+ 1
- 0
ca/21c73c2e.0 View File

@ -0,0 +1 @@
ca.cert.pem

+ 14
- 4
dml_crypto.c View File

@ -20,6 +20,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <string.h>
X509_STORE *x509_store;
@ -69,7 +70,7 @@ static void free_chain(STACK_OF(X509) *chain)
int dml_crypto_cert_add_verify(void *certdata, size_t size, uint8_t id[DML_ID_SIZE])
{
STACK_OF(X509 *chain);
STACK_OF(X509) *chain;
uint8_t *data = certdata;
char *name;
@ -277,7 +278,12 @@ bool dml_crypto_verify(void *data, size_t len, uint8_t sig[DML_SIG_SIZE], struct
ECDSA_SIG_free(ecsig);
return ret;
if (ret != 1) {
unsigned int err = ERR_get_error();
fprintf(stderr, "ret: %d ERR: %d\n", ret, err);
}
return ret == 1;
}
int dml_crypto_sign(uint8_t sig[DML_SIG_SIZE], void *data, size_t len, struct dml_crypto_key *dk)
@ -290,8 +296,12 @@ int dml_crypto_sign(uint8_t sig[DML_SIG_SIZE], void *data, size_t len, struct dm
SHA256_Final(digest, &sha256);
ECDSA_SIG *ecsig = ECDSA_do_sign(digest, SHA256_DIGEST_LENGTH, dk->ec_key);
BN_bn2bin(ecsig->r, sig);
BN_bn2bin(ecsig->s, sig + 32);
memset(sig, 0, 64);
int r_off = 32 - BN_num_bytes(ecsig->r);
int s_off = 32 - BN_num_bytes(ecsig->s);
BN_bn2bin(ecsig->r, sig + r_off);
BN_bn2bin(ecsig->s, sig + 32 + s_off);
ECDSA_SIG_free(ecsig);
return 0;


+ 17
- 1
dml_packet.c View File

@ -417,7 +417,6 @@ int dml_packet_parse_data(uint8_t *data, uint16_t len,
size_t plen = len - DML_SIG_SIZE - sizeof(uint64_t);
*payload_len = plen;
fprintf(stderr, "payload len: %zd\n", plen);
bool verified = dml_crypto_verify(data, plen + sizeof(uint64_t),
data + plen + sizeof(uint64_t), dk);
@ -438,7 +437,24 @@ int dml_packet_parse_data(uint8_t *data, uint16_t len,
((uint64_t)data[plen + 7]);
if (!verified) {
int i;
fprintf(stderr, "invalid signature\n");
for (i = 0; i < plen; i++) {
fprintf(stderr, "%02x ", data[i]);
}
fprintf(stderr, "\n");
for (i = 0; i < sizeof(uint64_t); i++) {
fprintf(stderr, "%02x ", data[plen + i]);
}
fprintf(stderr, "\n");
for (i = 0; i < 256/8; i++) {
fprintf(stderr, "%02x ", data[plen + sizeof(uint64_t) + i]);
}
fprintf(stderr, "\n");
for (i = 0; i < 256/8; i++) {
fprintf(stderr, "%02x ", data[plen + sizeof(uint64_t) +256/8 + i]);
}
fprintf(stderr, "\n");
return -1;
}


+ 296
- 84
dml_reflector.c View File

@ -21,11 +21,19 @@
#include "dml_packet.h"
#include "dml.h"
#include "dml_id.h"
#include "dml_crypto.h"
#include "dml_config.h"
#include "dml_stream.h"
#include "eth_ar.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
uint8_t ref_id[DML_ID_SIZE];
char *mime = "audio/dml-codec2";
@ -35,127 +43,247 @@ char *description;
uint32_t bps = 6400;
uint16_t packet_id = 0;
struct dml_crypto_key *dk;
struct dml_connection *dml_con;
struct connection_data {
uint8_t id[DML_ID_SIZE];
uint16_t packet_id;
uint8_t *header = &(uint8_t){ 0 };
size_t header_size = 0;
struct connection_data *next;
};
struct dml_crypto_key *dk;
struct connection_data *data_list;
void recv_data(void *data, size_t size);
uint16_t connection_data_new_id(void)
static uint16_t alloc_data_id(void)
{
static uint16_t id = DML_PACKET_DATA;
struct connection_data *entry;
do {
for (entry = data_list; entry; entry = entry->next) {
if (entry->packet_id == id) {
id++;
if (!id)
id = DML_PACKET_DATA;
break;
}
}
if (!entry)
uint16_t id;
for (id = DML_PACKET_DATA; id >= DML_PACKET_DATA; id++)
if (!dml_stream_by_data_id(id))
return id;
} while(1);
return 0;
}
void reverse_connect(struct dml_connection *dc, uint8_t id[DML_ID_SIZE])
struct dml_stream_priv {
bool match_mime;
bool connected;
};
struct dml_stream_priv *stream_priv_new(void)
{
//todo check header mime type
//todo retrieve cert & verify
struct connection_data *entry;
for (entry = data_list; entry; entry = entry->next) {
if (!memcmp(entry->id, id, DML_ID_SIZE))
return;
}
entry = calloc(1, sizeof(struct connection_data));
if (!entry)
return;
memcpy(entry->id, id, DML_ID_SIZE);
entry->packet_id = connection_data_new_id();
entry->next = data_list;
data_list = entry;
dml_packet_send_connect(dc, id, entry->packet_id);
return calloc(1, sizeof(struct dml_stream_priv));
}
void reverse_disc(struct dml_connection *dc, uint8_t id[DML_ID_SIZE])
void stream_priv_free(struct dml_stream_priv *priv)
{
struct connection_data **entry;
free(priv);
}
static int connect(struct dml_stream *ds)
{
uint16_t data_id = alloc_data_id();
if (!data_id)
return -1;
printf("Connect to %p\n", ds);
dml_stream_data_id_set(ds, data_id);
dml_packet_send_connect(dml_con, dml_stream_id_get(ds), data_id);
struct dml_stream_priv *priv = dml_stream_priv_get(ds);
for (entry = &data_list; *entry; entry = &(*entry)->next) {
if (!memcmp((*entry)->id, id, DML_ID_SIZE)) {
struct connection_data *old = *entry;
*entry = old->next;
dml_packet_send_req_disc(dc, id);
free(old);
}
}
priv->connected = true;
return 0;
}
void rx_packet(struct dml_connection *dc, void *arg,
uint16_t id, uint16_t len, uint8_t *data)
{
printf("got id: %d\n", id);
// printf("got id: %d\n", id);
switch(id) {
case DML_PACKET_ROUTE: {
uint8_t hops;
uint8_t rid[DML_ID_SIZE];
struct dml_stream *ds;
if (dml_packet_parse_route(data, len, rid, &hops))
break;
if (hops == 255) {
ds = dml_stream_by_id(rid);
if (ds) {
stream_priv_free(dml_stream_priv_get(ds));
dml_stream_remove(ds);
}
} else {
ds = dml_stream_by_id_alloc(rid);
if (!ds)
break;
struct dml_stream_priv *priv = dml_stream_priv_get(ds);
if (!priv) {
dml_stream_priv_set(ds, stream_priv_new());
}
char *mime = dml_stream_mime_get(ds);
if (!mime)
dml_packet_send_req_description(dc, rid);
else if (priv->match_mime) {
struct dml_crypto_key *ck = dml_stream_crypto_get(ds);
if (!ck)
dml_packet_send_req_certificate(dc, rid);
}
}
break;
}
case DML_PACKET_DESCRIPTION: {
struct dml_stream *ds;
if (!(ds = dml_stream_update_description(data, len)))
break;
char *dmime = dml_stream_mime_get(ds);
uint8_t *rid = dml_stream_id_get(ds);
if (!strcmp(mime, dmime)) {
struct dml_stream_priv *priv = dml_stream_priv_get(ds);
priv->match_mime = true;
struct dml_crypto_key *ck = dml_stream_crypto_get(ds);
if (!ck)
dml_packet_send_req_certificate(dc, rid);
}
break;
}
case DML_PACKET_CERTIFICATE: {
uint8_t cid[DML_ID_SIZE];
void *cert;
size_t size;
struct dml_stream *ds;
if (dml_packet_parse_certificate(data, len, cid, &cert, &size))
break;
if ((ds = dml_stream_by_id(cid))) {
struct dml_stream_priv *priv = dml_stream_priv_get(ds);
if (priv && priv->match_mime) {
dml_crypto_cert_add_verify(cert, size, cid);
}
}
free(cert);
break;
}
case DML_PACKET_HEADER: {
/* our current codec2 use doesn't need a header */
break;
}
case DML_PACKET_REQ_DESCRIPTION: {
/* No need to unpack the request,
we only have one stream...*/
dml_packet_send_description(dc, ref_id,
DML_PACKET_DESCRIPTION_VERSION_0, bps,
mime, name, alias, description);
dml_packet_send_description(dc, ref_id,
DML_PACKET_DESCRIPTION_VERSION_0, bps, mime,
name, alias, description);
break;
}
case DML_PACKET_CONNECT: {
uint8_t id[DML_ID_SIZE];
uint8_t cid[DML_ID_SIZE];
dml_packet_parse_connect(data, len, id, &packet_id);
dml_packet_parse_connect(data, len, cid, &packet_id);
break;
}
case DML_PACKET_REQ_DISC: {
uint8_t id[DML_ID_SIZE];
packet_id = 0;
dml_packet_send_disc(dc, ref_id, DML_PACKET_DISC_REQUESTED);
break;
}
case DML_PACKET_REQ_CERTIFICATE: {
void *cert;
size_t cert_size;
if (dml_packet_parse_req_disc(data, len, id))
if (dml_crypto_cert_get(&cert, &cert_size))
break;
dml_packet_send_disc(dc, id, DML_PACKET_DISC_REQUESTED);
if (!memcmp(id, ref_id, DML_ID_SIZE))
packet_id = 0;
dml_packet_send_certificate(dc, ref_id, cert, cert_size);
break;
}
case DML_PACKET_REQ_HEADER: {
uint8_t header_sig[DML_SIG_SIZE];
dml_crypto_sign(header_sig, header, header_size, dk);
dml_packet_send_header(dc, ref_id, header_sig, header, header_size);
break;
}
case DML_PACKET_REQ_REVERSE: {
uint8_t id[DML_ID_SIZE];
uint8_t id_me[DML_ID_SIZE];
uint8_t id_rev[DML_ID_SIZE];
uint8_t action;
if (dml_packet_parse_req_reverse(data, len, id, id_rev, &action))
if (dml_packet_parse_req_reverse(data, len, id_me, id_rev, &action))
break;
printf("Recevied reverse request %d\n", action);
struct dml_stream *ds_rev = dml_stream_by_id(id_rev);
if (!ds_rev)
break;
if (action & DML_PACKET_REQ_REVERSE_CONNECT)
reverse_connect(dc, id_rev);
else if (action & DML_PACKET_REQ_REVERSE_DISC)
reverse_disc(dc, id_rev);
if (action & DML_PACKET_REQ_REVERSE_CONNECT) {
bool do_connect = true;
struct dml_stream_priv *priv = dml_stream_priv_get(ds_rev);
if (do_connect && priv) {
struct dml_crypto_key *key = dml_stream_crypto_get(ds_rev);
if (priv->match_mime && key) {
connect(ds_rev);
}
}
} else if (action & DML_PACKET_REQ_REVERSE_DISC) {
struct dml_stream_priv *priv = dml_stream_priv_get(ds_rev);
if (priv && priv->connected) {
printf("Disconnect\n");
dml_packet_send_req_disc(dml_con, id_rev);
priv->connected = false;
}
}
break;
}
default: {
//todo verify signature
//todo generate new signature
dml_connection_send(dc, data, packet_id, len);
if (id < DML_PACKET_DATA)
break;
if (len < DML_SIG_SIZE + sizeof(uint64_t))
break;
uint64_t timestamp;
size_t payload_len;
void *payload_data;
struct dml_crypto_key *dk;
struct dml_stream *ds;
ds = dml_stream_by_data_id(id);
if (!ds) {
fprintf(stderr, "Could not find dml stream\n");
break;
}
struct dml_stream_priv *priv = dml_stream_priv_get(ds);
if (!priv || !priv->connected) {
fprintf(stderr, "Spurious data from %p\n", ds);
break;
}
dk = dml_stream_crypto_get(ds);
if (dml_packet_parse_data(data, len,
&payload_data, &payload_len, &timestamp, dk)) {
fprintf(stderr, "Decoding failed\n");
} else {
if (timestamp <= dml_stream_timestamp_get(ds)) {
fprintf(stderr, "Timestamp mismatch %"PRIx64" <= %"PRIx64"\n",
timestamp, dml_stream_timestamp_get(ds));
} else {
dml_stream_timestamp_set(ds, timestamp);
// fprintf(stderr, "Received %zd ok\n", payload_len);
recv_data(payload_data, payload_len);
}
free(payload_data);
}
break;
}
}
@ -163,10 +291,30 @@ void rx_packet(struct dml_connection *dc, void *arg,
return;
}
int client_reconnect(void *clientv)
{
struct dml_client *client = clientv;
if (dml_client_connect(client)) {
printf("Reconnect to DML server failed\n");
dml_poll_timeout(client, &(struct timespec){ 2, 0 });
}
return 0;
}
int client_connection_close(struct dml_connection *dc, void *arg)
{
//TODO timeout and reconnect!
return dml_connection_destroy(dc);
dml_con = NULL;
packet_id = 0;
dml_poll_add(arg, NULL, NULL, client_reconnect);
dml_poll_timeout(arg, &(struct timespec){ 1, 0 });
if (dc)
return dml_connection_destroy(dc);
else
return 0;
}
void client_connect(struct dml_client *client, void *arg)
@ -174,21 +322,83 @@ void client_connect(struct dml_client *client, void *arg)
struct dml_connection *dc;
int fd;
printf("Connected to DML server\n");
fd = dml_client_fd_get(client);
dc = dml_connection_create(fd, client, rx_packet, client_connection_close);
dml_packet_send_hello(dc, DML_PACKET_HELLO_LEAF, "dml_reflector " DML_VERSION);
dml_con = dc;
dml_packet_send_hello(dc,
DML_PACKET_HELLO_LEAF | DML_PACKET_HELLO_UPDATES,
"dml_reflector " DML_VERSION);
dml_packet_send_route(dc, ref_id, 0);
}
time_t prev_sec;
uint16_t prev_ctr;
void send_data(void *data, size_t size)
{
uint64_t timestamp;
struct timespec ts;
if (!packet_id)
return;
clock_gettime(CLOCK_REALTIME, &ts);
if (prev_sec != ts.tv_sec) {
prev_ctr = 0;
prev_sec = ts.tv_sec;
} else {
prev_ctr++;
if (prev_ctr > 50) {
/* No more than 50, probably multiple senders */
fprintf(stderr, "Dropping packet %d\n", prev_ctr);
return;
}
}
timestamp = ts.tv_sec << 16;
timestamp |= prev_ctr;
dml_packet_send_data(dml_con, packet_id, data, size, timestamp, dk);
}
static bool tx_state = false;
void recv_data(void *data, size_t size)
{
if (size < 8)
return;
uint8_t *datab = data;
// int mode = datab[6];
bool state = datab[7] & 0x1;
// printf("mode %d state %d\n", mode, state);
if (state != tx_state) {
char call[ETH_AR_CALL_SIZE];
int ssid;
eth_ar_mac2call(call, &ssid, data);
tx_state = state;
printf("State changed to %s by %s-%d\n", state ? "ON":"OFF", call, ssid);
}
send_data(data, size);
}
int main(int argc, char **argv)
{
struct dml_client *dc;
char *file = "dml_reflector.conf";
char *ca;
char *certificate;
char *key;
char *server;
char *ca;
if (argc > 1)
file = argv[1];
@ -197,15 +407,16 @@ int main(int argc, char **argv)
printf("Failed to load config file %s\n", file);
return -1;
}
name = dml_config_value("name", NULL, "example");
name = dml_config_value("name", NULL, "test_reflector");
alias = dml_config_value("alias", NULL, "0000");
description = dml_config_value("description", NULL, "Test reflector");
ca = dml_config_value("ca", NULL, ".");
server = dml_config_value("server", NULL, "localhost");
certificate = dml_config_value("certificate", NULL, "");
key = dml_config_value("key", NULL, "");
ca = dml_config_value("ca", NULL, ".");
if (dml_crypto_init(NULL, ca)) {
fprintf(stderr, "Failed to init crypto\n");
return -1;
@ -221,7 +432,8 @@ int main(int argc, char **argv)
return -1;
}
if (dml_id_gen(ref_id, DML_PACKET_DESCRIPTION_VERSION_0, bps, mime, name, alias, description))
if (dml_id_gen(ref_id, DML_PACKET_DESCRIPTION_VERSION_0, bps,
mime, name, alias, description))
return -1;
dc = dml_client_create(server, 0, client_connect, NULL);


+ 7
- 0
dml_reflector.conf View File

@ -0,0 +1,7 @@
name = ref.pirate.ampr.org
alias = 319999
certificate = pirate.ampr.org.cert.pem
key = k.pem
ca = ./ca/

+ 2
- 2
dml_stream_client.c View File

@ -38,7 +38,7 @@ uint8_t req_id[DML_ID_SIZE];
void rx_packet(struct dml_connection *dc, void *arg,
uint16_t id, uint16_t len, uint8_t *data)
{
fprintf(stderr, "got id: %d\n", id);
// fprintf(stderr, "got id: %d\n", id);
switch(id) {
case DML_PACKET_DESCRIPTION: {
if (!dml_stream_update_description(data, len))
@ -122,7 +122,7 @@ void rx_packet(struct dml_connection *dc, void *arg,
timestamp, dml_stream_timestamp_get(ds));
} else {
dml_stream_timestamp_set(ds, timestamp);
fprintf(stderr, "Received %zd ok\n", payload_len);
// fprintf(stderr, "Received %zd ok\n", payload_len);
write(1, payload_data, payload_len);
}
free(payload_data);


+ 9
- 3
dml_streamer_ogg.c View File

@ -51,7 +51,7 @@ struct dml_crypto_key *dk;
void rx_packet(struct dml_connection *dc, void *arg,
uint16_t id, uint16_t len, uint8_t *data)
{
printf("got id: %d\n", id);
// printf("got id: %d\n", id);
switch(id) {
case DML_PACKET_REQ_DESCRIPTION: {
@ -258,7 +258,7 @@ int ogg_in(void *arg)
printf("bitflags: %02x segments: %d serial: %08x ", ogg_page[5], ogg_segments, serial);
printf(" %02x\n", ogg_page[27 + ogg_segments]);
if (vorbis_header == serial) {
if (!(ogg_page[27 + ogg_segments] & 1)) {
printf("First vorbis data\n");
@ -283,7 +283,13 @@ int ogg_in(void *arg)
}
}
send_data(ogg_page, ogg_pos);
int i;
for (i = 0; i < ogg_pos; i += 1024) {
int size = ogg_pos - i;
if (size > 1024)
size = 1024;
send_data(ogg_page + i, size);
}
memmove(ogg_page, ogg_page + ogg_total_segments, ogg_pos - ogg_total_segments);
ogg_pos -= ogg_total_segments;


+ 25
- 18
dml_trx.c View File

@ -29,13 +29,14 @@
#include "trx_codec2.h"
#include "trx_control.h"
#include "eth_ar.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <openssl/pem.h>
uint8_t ref_id[DML_ID_SIZE];
@ -99,7 +100,7 @@ static int connect(struct dml_stream *ds)
void rx_packet(struct dml_connection *dc, void *arg,
uint16_t id, uint16_t len, uint8_t *data)
{
printf("got id: %d\n", id);
// printf("got id: %d\n", id);
switch(id) {
case DML_PACKET_ROUTE: {
@ -113,6 +114,10 @@ void rx_packet(struct dml_connection *dc, void *arg,
if (hops == 255) {
ds = dml_stream_by_id(rid);
if (ds) {
if (ds == cur_con) {
cur_con = NULL;
packet_id = 0;
}
stream_priv_free(dml_stream_priv_get(ds));
dml_stream_remove(ds);
}
@ -291,7 +296,7 @@ void rx_packet(struct dml_connection *dc, void *arg,
timestamp, dml_stream_timestamp_get(ds));
} else {
dml_stream_timestamp_set(ds, timestamp);
fprintf(stderr, "Received %zd ok\n", payload_len);
// fprintf(stderr, "Received %zd ok\n", payload_len);
recv_data(payload_data, payload_len);
}
free(payload_data);
@ -376,6 +381,8 @@ struct trx_codec2 *tc_me;
static bool rx_state = false;
static bool tx_state = false;
uint8_t mac_my[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
void recv_data(void *data, size_t size)
{
if (size < 8)
@ -383,14 +390,19 @@ void recv_data(void *data, size_t size)
uint8_t *datab = data;
int mode = datab[6];
// int mode = datab[6];
bool state = datab[7] & 0x1;
printf("mode %d state %d\n", mode, state);
// printf("mode %d state %d\n", mode, state);
if (state != tx_state) {
char call[ETH_AR_CALL_SIZE];
int ssid;
eth_ar_mac2call(call, &ssid, data);
trx_control_state_set(state);
tx_state = state;
printf("State changed to %s by %s-%d\n", state ? "ON":"OFF", call, ssid);
}
if (size > 8)
@ -404,12 +416,7 @@ int encode_cb(void *arg, uint8_t *encoded, size_t size)
if (!rx_state)
return 0;
data[0] = 0xff;
data[1] = 0xff;
data[2] = 0xff;
data[3] = 0xff;
data[4] = 0xff;
data[5] = 0xff;
memcpy(data, mac_my, 6);
data[6] = trx_codec2_mode_get(tc_me);
data[7] = rx_state;
memcpy(data + 8, encoded, size);
@ -423,14 +430,9 @@ int state_cb(bool state)
printf("state: %d\n", state);
if (state != rx_state) {
uint8_t data[8];
data[0] = 0xff;
data[1] = 0xff;
data[2] = 0xff;
data[3] = 0xff;
data[4] = 0xff;
data[5] = 0xff;
memcpy(data, mac_my, 6);
data[6] = trx_codec2_mode_get(tc_me);
data[7] = rx_state;
data[7] = state;
send_data(data, 8);
}
rx_state = state;
@ -491,6 +493,7 @@ int main(int argc, char **argv)
char *server;
char *ca;
char *controldev;
char *call;
if (argc > 1)
file = argv[1];
@ -502,6 +505,10 @@ int main(int argc, char **argv)
name = dml_config_value("name", NULL, "test_trx");
alias = dml_config_value("alias", NULL, "0000");
description = dml_config_value("description", NULL, "Test transceiver");
call = dml_config_value("callsign", NULL, NULL);
if (call) {
eth_ar_call2mac(mac_my, call, 0);
}
server = dml_config_value("server", NULL, "localhost");
certificate = dml_config_value("certificate", NULL, "");


+ 8
- 0
dml_trx.conf View File

@ -0,0 +1,8 @@
name = pirate.ampr.org
callsign = pirate
alias = 310000
certificate = pirate.ampr.org.cert.pem
key = k.pem
ca = ./ca/

+ 1
- 1
dmld.c View File

@ -429,7 +429,7 @@ void rx_packet(struct dml_connection *dc, void *arg,
{
struct connection *con = arg;
printf("%d\n", id);
// printf("%d\n", id);
switch (id) {
case DML_PACKET_HELLO:
dml_packet_parse_hello(data, len, &con->flags, NULL);


+ 102
- 0
eth_ar.c View File

@ -0,0 +1,102 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "eth_ar.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
static char alnum2code[37] = {
0, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
int eth_ar_call2mac(uint8_t mac[6], char *callsign, int ssid)
{
uint64_t add = 0;
int i;
if (ssid > 15 || ssid < 0)
return -1;
for (i = 7; i >= 0; i--) {
char c;
if (i >= strlen(callsign)) {
c = 0;
} else {
c = toupper(callsign[i]);
}
int j;
for (j = 0; j < sizeof(alnum2code); j++) {
if (alnum2code[j] == c)
break;
}
if (j == sizeof(alnum2code))
return -1;
add *= 37;
add += j;
}
mac[0] = ((add >> 42) & 0xc0) | (ssid << 2) | 0x02;
mac[1] = (add >> 32) & 0xff;
mac[2] = (add >> 24) & 0xff;
mac[3] = (add >> 16) & 0xff;
mac[4] = (add >> 8) & 0xff;
mac[5] = add & 0xff;
printf("%02x %02x %02x\n", (int)(add >> 42) & 0xc0, ssid << 2, 0x02);
printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", callsign, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return 0;
}
int eth_ar_mac2call(char *callsign, int *ssid, uint8_t mac[6])
{
uint64_t add;
int i;
if (!memcmp(mac, (uint8_t[6]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 6)) {
*ssid = 0;
strcpy(callsign, "BCAST");
return 0;
}
*ssid = (mac[0] & 0x0c0) >> 2;
add = (uint64_t)(mac[0] & 0xc0) << 42;
add |= (uint64_t)mac[1] << 32;
add |= mac[2] << 24;
add |= mac[3] << 16;
add |= mac[4] << 8;
add |= mac[5];
for (i = 0; i < 8; i++) {
int c = add % 37;
callsign[i] = alnum2code[c];
add /= 37;
if (!add) {
break;
}
}
callsign[i] = 0;
return 0;
}

+ 32
- 0
eth_ar.h View File

@ -0,0 +1,32 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_ETH_AR_H_
#define _INCLUDE_ETH_AR_H_
#include <stdint.h>
#define ETH_P_CODEC2 0x7300
#define ETH_AR_CALL_LEN_MAX 8
#define ETH_AR_CALL_SIZE 9
int eth_ar_call2mac(uint8_t mac[6], char *callsign, int ssid);
int eth_ar_mac2call(char *callsign, int *ssid, uint8_t mac[6]);
#endif /* _INCLUDE_ETH_AR_H_ */

+ 46
- 0
examples.txt View File

@ -0,0 +1,46 @@
dmld
DML router
Will listen on port 7373 for incomming connections.
Outgoing connections can be set in the configuration file dmld.conf
dml_list
Connects to a DML router and will output information on all routable
streams. (Handy for discovering IDs)
dml_trx
Tranceiver. Will create a stream with Codec2 encoded audio and can
connect to similar streams. Can control the PTT of a connected radio
via a serial port or receive DTMF and squelch info from a serial port.
Can connect to streams via aliases.
dml_reflector
Basic reflector. Will connect to Codec2 encoded audio streams when
requested and reflect them to all listeners.
dml_streamer_ogg
A simple stream server which expects an Ogg stream on stdin.
The stream can contain Vorbis (audio) and Theora (video) packets.
(Currently not more than one of each).
Reads configuration from dml_streamer_ogg.conf
dml_stream_client
Stream client. Expects an dml ID as command line argument and will
output stream data to stdout.
Stream audio with ogg:
ffmpeg -f alsa -i hw \
-codec:a vorbis -strict -2 -qscale:a 5 \
-f ogg - | ./dml_streamer_ogg
Receive ogg stream and play:
dml_stream_client <stream_id> | mplayer -

+ 7
- 0
key.txt View File

@ -4,4 +4,11 @@ openssl ecparam -genkey -name secp256r1 -out k.pem
# print private key and public key
openssl ec -in k.pem -noout -text
# private key to a pem file
openssl ec -in k.pem -pubout -out p.pem
# create a certificate request for key
openssl req -new -key k.pem -out req.pem
# rehash ca dir after installing certificate
c_rehash ./ca/

Loading…
Cancel
Save