forked from osmocom/wireshark
From Julian Cable:
New dissector for ETSI DCP (ETSI TS 102 821). Code rearranged to look more like other Wireshark dissectors and some warnings/errors on Windows fixed. svn path=/trunk/; revision=19981
This commit is contained in:
parent
643dc7099d
commit
1509562c0f
|
@ -40,6 +40,7 @@ LIBWIRESHARK_SRC = \
|
|||
conversation.c \
|
||||
crc16.c \
|
||||
crc32.c \
|
||||
crcdrm.c \
|
||||
crypt-des.c \
|
||||
crypt-md4.c \
|
||||
crypt-md5.c \
|
||||
|
@ -73,6 +74,7 @@ LIBWIRESHARK_SRC = \
|
|||
radius_dict.c \
|
||||
range.c \
|
||||
reassemble.c \
|
||||
reedsolomon.c \
|
||||
req_resp_hdrs.c \
|
||||
sha1.c \
|
||||
sigcomp_state_hdlr.c \
|
||||
|
@ -119,6 +121,7 @@ LIBWIRESHARK_INCLUDES = \
|
|||
conversation.h \
|
||||
crc16.h \
|
||||
crc32.h \
|
||||
crcdrm.h \
|
||||
crypt-des.h \
|
||||
crypt-md4.h \
|
||||
crypt-md5.h \
|
||||
|
@ -168,6 +171,7 @@ LIBWIRESHARK_INCLUDES = \
|
|||
ptvcursor.h \
|
||||
range.h \
|
||||
reassemble.h \
|
||||
reedsolomon.h \
|
||||
report_err.h \
|
||||
req_resp_hdrs.h \
|
||||
rtp_pt.h \
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* drmcrc.c
|
||||
* another CRC 16
|
||||
* Copyright 2006, British Broadcasting Corporation
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "crcdrm.h"
|
||||
|
||||
unsigned long crc_drm(const char *data, size_t bytesize,
|
||||
unsigned short num_crc_bits, unsigned long crc_gen, int invert)
|
||||
{
|
||||
unsigned long crc_holder, ones, i, msb, databit;
|
||||
signed short j;
|
||||
|
||||
ones = (1 << num_crc_bits) - 1;
|
||||
crc_holder = ones;
|
||||
for (i=0; i<bytesize; i++)
|
||||
for (j=7; j>=0; j--)
|
||||
{
|
||||
crc_holder <<= 1;
|
||||
msb = crc_holder >> num_crc_bits;
|
||||
databit = (data[i] >> j) & 1;
|
||||
if ((msb ^ databit) != 0)
|
||||
crc_holder = crc_holder ^ crc_gen;
|
||||
crc_holder = crc_holder & ones;
|
||||
}
|
||||
if (invert)
|
||||
crc_holder = crc_holder ^ ones; /* invert checksum */
|
||||
return crc_holder;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _CRCDRM_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned long crc_drm(const char *data, size_t bytesize,
|
||||
unsigned short num_crc_bits, unsigned long crc_gen, int invert);
|
||||
#endif
|
|
@ -255,6 +255,7 @@ DISSECTOR_SRC = \
|
|||
packet-dcom-remact.c \
|
||||
packet-dcom-remunkn.c \
|
||||
packet-dcom-sysact.c \
|
||||
packet-dcp-etsi.c \
|
||||
packet-ddtp.c \
|
||||
packet-dec-bpdu.c \
|
||||
packet-dec-dnart.c \
|
||||
|
|
|
@ -0,0 +1,878 @@
|
|||
/* packet-dcp-etsi.c
|
||||
* Routines for ETSI Distribution & Communication Protocol
|
||||
* Copyright 2006, British Broadcasting Corporation
|
||||
*
|
||||
* $Id:$
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Protocol info
|
||||
* Ref: ETSI DCP (ETSI TS 102 821)
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <epan/packet.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/reassemble.h>
|
||||
#include <epan/crcdrm.h>
|
||||
#include <epan/reedsolomon.h>
|
||||
#include <string.h>
|
||||
|
||||
/* forward reference */
|
||||
|
||||
static gboolean dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
|
||||
static void dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
|
||||
static void dissect_pft (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
|
||||
static void dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
|
||||
|
||||
static dissector_table_t dcp_dissector_table;
|
||||
static dissector_table_t af_dissector_table;
|
||||
static dissector_table_t tpl_dissector_table;
|
||||
|
||||
static int proto_dcp_etsi = -1;
|
||||
static int proto_af = -1;
|
||||
static int proto_pft = -1;
|
||||
static int proto_tpl = -1;
|
||||
static dissector_handle_t af_handle;
|
||||
static dissector_handle_t pft_handle;
|
||||
static dissector_handle_t tpl_handle;
|
||||
static int hf_edcp_sync = -1;
|
||||
static int hf_edcp_len = -1;
|
||||
static int hf_edcp_seq = -1;
|
||||
static int hf_edcp_crcflag = -1;
|
||||
static int hf_edcp_maj = -1;
|
||||
static int hf_edcp_min = -1;
|
||||
static int hf_edcp_pt = -1;
|
||||
static int hf_edcp_crc = -1;
|
||||
static int hf_edcp_crc_ok = -1;
|
||||
static int hf_edcp_pft_pt = -1;
|
||||
static int hf_edcp_pseq = -1;
|
||||
static int hf_edcp_findex = -1;
|
||||
static int hf_edcp_fcount = -1;
|
||||
static int hf_edcp_fecflag = -1;
|
||||
static int hf_edcp_addrflag = -1;
|
||||
static int hf_edcp_plen = -1;
|
||||
static int hf_edcp_rsk = -1;
|
||||
static int hf_edcp_rsz = -1;
|
||||
static int hf_edcp_source = -1;
|
||||
static int hf_edcp_dest = -1;
|
||||
static int hf_edcp_hcrc = -1;
|
||||
static int hf_edcp_hcrc_ok = -1;
|
||||
static int hf_edcp_c_max = -1;
|
||||
static int hf_edcp_rx_min = -1;
|
||||
static int hf_edcp_rs_corrected = -1;
|
||||
static int hf_edcp_rs_ok = -1;
|
||||
static int hf_edcp_pft_payload = -1;
|
||||
|
||||
static int hf_tpl_tlv = -1;
|
||||
static int hf_tpl_ptr = -1;
|
||||
|
||||
static int hf_edcp_fragments = -1;
|
||||
static int hf_edcp_fragment = -1;
|
||||
static int hf_edcp_fragment_overlap = -1;
|
||||
static int hf_edcp_fragment_overlap_conflicts = -1;
|
||||
static int hf_edcp_fragment_multiple_tails = -1;
|
||||
static int hf_edcp_fragment_too_long_fragment = -1;
|
||||
static int hf_edcp_fragment_error = -1;
|
||||
static int hf_edcp_reassembled_in = -1;
|
||||
|
||||
/* Initialize the subtree pointers */
|
||||
static gint ett_edcp = -1;
|
||||
static gint ett_af = -1;
|
||||
static gint ett_pft = -1;
|
||||
static gint ett_tpl = -1;
|
||||
static gint ett_edcp_fragment = -1;
|
||||
static gint ett_edcp_fragments = -1;
|
||||
|
||||
static GHashTable *dcp_fragment_table = NULL;
|
||||
static GHashTable *dcp_reassembled_table = NULL;
|
||||
|
||||
static const fragment_items dcp_frag_items = {
|
||||
/* Fragment subtrees */
|
||||
&ett_edcp_fragment,
|
||||
&ett_edcp_fragments,
|
||||
/* Fragment fields */
|
||||
&hf_edcp_fragments,
|
||||
&hf_edcp_fragment,
|
||||
&hf_edcp_fragment_overlap,
|
||||
&hf_edcp_fragment_overlap_conflicts,
|
||||
&hf_edcp_fragment_multiple_tails,
|
||||
&hf_edcp_fragment_too_long_fragment,
|
||||
&hf_edcp_fragment_error,
|
||||
/* Reassembled in field */
|
||||
&hf_edcp_reassembled_in,
|
||||
/* Tag */
|
||||
"Message fragments"
|
||||
};
|
||||
|
||||
/** initialise the DCP protocol. Details follow
|
||||
* here.
|
||||
*/
|
||||
static void
|
||||
dcp_init_protocol(void)
|
||||
{
|
||||
fragment_table_init (&dcp_fragment_table);
|
||||
reassembled_table_init (&dcp_reassembled_table);
|
||||
}
|
||||
|
||||
|
||||
/** Dissect a DCP packet. Details follow
|
||||
* here.
|
||||
* \param[in,out] tvb The buffer containing the packet
|
||||
* \param[in,out] pinfo The packet info structure
|
||||
* \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
|
||||
static void
|
||||
*/
|
||||
static gboolean
|
||||
dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
|
||||
{
|
||||
guint8 *sync;
|
||||
proto_tree *dcp_tree = NULL;
|
||||
sync = tvb_get_string (tvb, 0, 2);
|
||||
if((sync[0]!='A' && sync[0]!='P') || sync[1]!='F')
|
||||
return FALSE;
|
||||
|
||||
pinfo->current_proto = "DCP (ETSI)";
|
||||
|
||||
/* Clear out stuff in the info column */
|
||||
if (check_col (pinfo->cinfo, COL_INFO)) {
|
||||
col_clear (pinfo->cinfo, COL_INFO);
|
||||
}
|
||||
if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
|
||||
col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP (ETSI)");
|
||||
/*col_append_fstr (pinfo->cinfo, COL_INFO, " tvb %d", tvb_length(tvb));*/
|
||||
}
|
||||
|
||||
if(tree) {
|
||||
proto_item *ti = NULL;
|
||||
ti = proto_tree_add_item (tree, proto_dcp_etsi, tvb, 0, -1, FALSE);
|
||||
dcp_tree = proto_item_add_subtree (ti, ett_edcp);
|
||||
}
|
||||
|
||||
dissector_try_string(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree);
|
||||
g_free (sync);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define PFT_RS_N_MAX 207
|
||||
#define PFT_RS_K 255
|
||||
#define PFT_RS_P (PFT_RS_K - PFT_RS_N_MAX)
|
||||
|
||||
|
||||
static
|
||||
void rs_deinterleave(const guint8 *input, guint8 *output, guint16 plen, guint32 fcount)
|
||||
{
|
||||
guint fidx;
|
||||
for(fidx=0; fidx<fcount; fidx++)
|
||||
{
|
||||
int r;
|
||||
for (r=0; r<plen; r++)
|
||||
{
|
||||
output[fidx+r*fcount] = input[fidx*plen+r];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
|
||||
guint32 c_max, guint16 rsk, guint16 rsz)
|
||||
{
|
||||
guint32 i, index_coded = 0, index_out = 0;
|
||||
int err_corr;
|
||||
for (i=0; i<c_max; i++)
|
||||
{
|
||||
memcpy(output+index_out, deinterleaved+index_coded, rsk);
|
||||
index_coded += rsk;
|
||||
memcpy(output+index_out+PFT_RS_N_MAX, deinterleaved+index_coded, PFT_RS_P);
|
||||
index_coded += PFT_RS_P;
|
||||
err_corr = eras_dec_rs(output+index_out, NULL, 0);
|
||||
if (err_corr<0) {
|
||||
return FALSE;
|
||||
}
|
||||
index_out += rsk;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static tvbuff_t *
|
||||
dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
|
||||
guint32 findex,
|
||||
guint32 fcount,
|
||||
guint16 seq,
|
||||
gint offset,
|
||||
guint16 plen,
|
||||
gboolean fec,
|
||||
guint16 rsk,
|
||||
guint16 rsz,
|
||||
fragment_data *fd
|
||||
)
|
||||
{
|
||||
guint16 decoded_size;
|
||||
guint32 c_max;
|
||||
guint32 rx_min;
|
||||
gboolean first, last, decoded = TRUE;
|
||||
tvbuff_t *new_tvb=NULL;
|
||||
|
||||
first = findex == 0;
|
||||
last = fcount == (findex+1);
|
||||
decoded_size = fcount*plen;
|
||||
c_max = fcount*plen/(rsk+PFT_RS_P); /* rounded down */
|
||||
rx_min = c_max*rsk/plen;
|
||||
if(rx_min*plen<c_max*rsk)
|
||||
rx_min++;
|
||||
if (fd)
|
||||
new_tvb = process_reassembled_data (tvb, offset, pinfo,
|
||||
"Reassembled Message",
|
||||
fd, &dcp_frag_items,
|
||||
NULL, tree);
|
||||
else {
|
||||
guint fragments=0;
|
||||
guint32 *got = g_malloc(fcount*sizeof(guint32));
|
||||
|
||||
fragment_data *fd = fragment_get(pinfo, seq, dcp_fragment_table);
|
||||
fragment_data *fd_head;
|
||||
for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) {
|
||||
if(fd_head->data) {
|
||||
got[fragments] = fd_head->offset;
|
||||
fragments++;
|
||||
}
|
||||
}
|
||||
if(fragments>=rx_min) {
|
||||
guint i,j;
|
||||
fragment_data *frag=NULL;
|
||||
guint8 *dummy_data = (guint8*) g_malloc (plen);
|
||||
tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen);
|
||||
/* try and decode with missing fragments */
|
||||
if(tree)
|
||||
proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
|
||||
fcount, fragments, rx_min
|
||||
);
|
||||
memset(dummy_data, 0, plen);
|
||||
for(i=0,j=0; i<fragments; i++,j++) {
|
||||
while(j<got[i]) {
|
||||
frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,
|
||||
dcp_fragment_table, dcp_reassembled_table, j, plen, (j+1!=fcount));
|
||||
if(tree) {
|
||||
proto_tree_add_text (tree, tvb, 0, -1, "missing %d", j);
|
||||
if(frag) {
|
||||
proto_tree_add_text (tree, tvb, 0, -1, "fragment %d was what we needed", j);
|
||||
break;
|
||||
} else {
|
||||
proto_tree_add_text (tree, tvb, 0, -1, "added %d but still not reassembled", j);
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if(frag)
|
||||
new_tvb = process_reassembled_data (tvb, offset, pinfo,
|
||||
"Reassembled Message",
|
||||
frag, &dcp_frag_items,
|
||||
NULL, tree);
|
||||
}
|
||||
g_free(got);
|
||||
}
|
||||
if(new_tvb) {
|
||||
tvbuff_t *dtvb = NULL;
|
||||
const guint8 *input = tvb_get_ptr(new_tvb, 0, -1);
|
||||
guint16 reassembled_size = tvb_length(new_tvb);
|
||||
guint8 *deinterleaved = (guint8*) g_malloc (reassembled_size);
|
||||
guint8 *output = (guint8*) g_malloc (decoded_size);
|
||||
rs_deinterleave(input, deinterleaved, plen, fcount);
|
||||
|
||||
dtvb = tvb_new_real_data(deinterleaved, reassembled_size, reassembled_size);
|
||||
tvb_set_child_real_data_tvbuff(tvb, dtvb);
|
||||
add_new_data_source(pinfo, dtvb, "Deinterleaved");
|
||||
tvb_set_free_cb(dtvb, g_free);
|
||||
|
||||
decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz);
|
||||
if(tree)
|
||||
proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded);
|
||||
|
||||
new_tvb = tvb_new_real_data(output, decoded_size, decoded_size);
|
||||
tvb_set_child_real_data_tvbuff(dtvb, new_tvb);
|
||||
add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data");
|
||||
tvb_set_free_cb(new_tvb, g_free);
|
||||
}
|
||||
return new_tvb;
|
||||
}
|
||||
|
||||
|
||||
/** Handle a PFT packet which has the fragmentation header. This uses the
|
||||
* standard ethereal methods for reassembling fragments. If FEC is used,
|
||||
* the FEC is handled too. For the moment, all the fragments must be
|
||||
* available but this could be improved.
|
||||
* \param[in,out] tvb The buffer containing the current fragment
|
||||
* \param[in,out] pinfo The packet info structure
|
||||
* \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
|
||||
* \param[in] findex the fragment count
|
||||
* \param[in] fcount the number of fragments
|
||||
* \param[in] seq the sequence number of the reassembled packet
|
||||
* \param[in] offset the offset into the tvb of the fragment
|
||||
* \param[in] plen the length of each fragment
|
||||
* \param[in] fec is fec used
|
||||
* \param[in] rsk the number of useful bytes in each chunk
|
||||
* \param[in] rsz the number of padding bytes in each chunk
|
||||
*/
|
||||
static tvbuff_t *
|
||||
dissect_pft_fragmented(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
|
||||
guint32 findex,
|
||||
guint32 fcount,
|
||||
guint16 seq,
|
||||
gint offset,
|
||||
guint16 plen,
|
||||
gboolean fec,
|
||||
guint16 rsk,
|
||||
guint16 rsz
|
||||
)
|
||||
{
|
||||
gboolean first, last;
|
||||
tvbuff_t *new_tvb=NULL;
|
||||
fragment_data *frag_edcp = NULL;
|
||||
pinfo->fragmented = TRUE;
|
||||
first = findex == 0;
|
||||
last = fcount == (findex+1);
|
||||
frag_edcp = fragment_add_seq_check (
|
||||
tvb, offset, pinfo,
|
||||
seq,
|
||||
dcp_fragment_table, dcp_reassembled_table,
|
||||
findex,
|
||||
plen,
|
||||
!last);
|
||||
if(fec) {
|
||||
new_tvb = dissect_pft_fec_detailed(
|
||||
tvb, pinfo, tree, findex, fcount, seq, offset, plen, fec, rsk, rsz, frag_edcp
|
||||
);
|
||||
} else {
|
||||
new_tvb = process_reassembled_data (tvb, offset, pinfo,
|
||||
"Reassembled Message",
|
||||
frag_edcp, &dcp_frag_items,
|
||||
NULL, tree);
|
||||
}
|
||||
if (check_col (pinfo->cinfo, COL_INFO)) {
|
||||
if(new_tvb) {
|
||||
col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
|
||||
} else {
|
||||
if(last) {
|
||||
col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembly failure)");
|
||||
} else {
|
||||
col_append_fstr (pinfo->cinfo, COL_INFO, " (Message fragment %u)", findex);
|
||||
}
|
||||
}
|
||||
if(first)
|
||||
col_append_str (pinfo->cinfo, COL_INFO, " (first)");
|
||||
if(last)
|
||||
col_append_str (pinfo->cinfo, COL_INFO, " (last)");
|
||||
}
|
||||
return new_tvb;
|
||||
}
|
||||
|
||||
/** Dissect a PFT packet. Details follow
|
||||
* here.
|
||||
* \param[in,out] tvb The buffer containing the packet
|
||||
* \param[in,out] pinfo The packet info structure
|
||||
* \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
|
||||
*/
|
||||
static void
|
||||
dissect_pft(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
|
||||
{
|
||||
guint16 plen;
|
||||
gint offset = 0;
|
||||
guint16 seq, payload_len, hcrc;
|
||||
guint32 findex, fcount;
|
||||
proto_tree *pft_tree = NULL;
|
||||
proto_item *ti = NULL, *li = NULL;
|
||||
tvbuff_t *next_tvb = NULL;
|
||||
gboolean fec = FALSE;
|
||||
guint16 rsk=0, rsz=0;
|
||||
|
||||
pinfo->current_proto = "DCP-PFT";
|
||||
if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
|
||||
col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-PFT");
|
||||
}
|
||||
|
||||
if (tree) { /* we are being asked for details */
|
||||
ti = proto_tree_add_item (tree, proto_pft, tvb, 0, -1, FALSE);
|
||||
pft_tree = proto_item_add_subtree (ti, ett_pft);
|
||||
proto_tree_add_item (pft_tree, hf_edcp_sync, tvb, offset, 2, FALSE);
|
||||
}
|
||||
offset += 2;
|
||||
seq = tvb_get_ntohs (tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_item (pft_tree, hf_edcp_pseq, tvb, offset, 2, FALSE);
|
||||
}
|
||||
offset += 2;
|
||||
findex = tvb_get_ntoh24 (tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_item (pft_tree, hf_edcp_findex, tvb, offset, 3, FALSE);
|
||||
}
|
||||
offset += 3;
|
||||
fcount = tvb_get_ntoh24 (tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_item (pft_tree, hf_edcp_fcount, tvb, offset, 3, FALSE);
|
||||
}
|
||||
offset += 3;
|
||||
plen = tvb_get_ntohs (tvb, offset);
|
||||
payload_len = plen & 0x3fff;
|
||||
if (tree) {
|
||||
proto_tree_add_item (pft_tree, hf_edcp_fecflag, tvb, offset, 2, FALSE);
|
||||
proto_tree_add_item (pft_tree, hf_edcp_addrflag, tvb, offset, 2, FALSE);
|
||||
li = proto_tree_add_item (pft_tree, hf_edcp_plen, tvb, offset, 2, FALSE);
|
||||
}
|
||||
offset += 2;
|
||||
if (plen & 0x8000) {
|
||||
fec = TRUE;
|
||||
rsk = tvb_get_guint8 (tvb, offset);
|
||||
if (tree)
|
||||
proto_tree_add_item (pft_tree, hf_edcp_rsk, tvb, offset, 1, FALSE);
|
||||
offset += 1;
|
||||
rsz = tvb_get_guint8 (tvb, offset);
|
||||
if (tree)
|
||||
proto_tree_add_item (pft_tree, hf_edcp_rsz, tvb, offset, 1, FALSE);
|
||||
offset += 1;
|
||||
}
|
||||
if (plen & 0x4000) {
|
||||
if (tree)
|
||||
proto_tree_add_item (pft_tree, hf_edcp_source, tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
if (tree)
|
||||
proto_tree_add_item (pft_tree, hf_edcp_dest, tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
}
|
||||
if (tree) {
|
||||
proto_item *ci = NULL;
|
||||
guint header_len = offset+2;
|
||||
const guint8 *crc_buf = tvb_get_ptr(tvb, 0, header_len);
|
||||
unsigned long c = crc_drm(crc_buf, header_len, 16, 0x11021, 1);
|
||||
ci = proto_tree_add_item (pft_tree, hf_edcp_hcrc, tvb, offset, 2, FALSE);
|
||||
proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
|
||||
proto_tree_add_boolean(pft_tree, hf_edcp_hcrc_ok, tvb, offset, 2, c==0xe2f0);
|
||||
}
|
||||
hcrc = tvb_get_ntohs (tvb, offset);
|
||||
offset += 2;
|
||||
if (fcount > 1) { /* fragmented*/
|
||||
gboolean save_fragmented = pinfo->fragmented;
|
||||
guint16 real_len = tvb_length(tvb)-offset;
|
||||
proto_tree_add_item (pft_tree, hf_edcp_pft_payload, tvb, offset, real_len, FALSE);
|
||||
if(real_len != payload_len) {
|
||||
if(li)
|
||||
proto_item_append_text(li, " (length error (%d))", real_len);
|
||||
}
|
||||
next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree,
|
||||
findex, fcount, seq, offset, real_len,
|
||||
fec, rsk, rsz
|
||||
);
|
||||
pinfo->fragmented = save_fragmented;
|
||||
} else {
|
||||
next_tvb = tvb_new_subset (tvb, offset, -1, -1);
|
||||
}
|
||||
if(next_tvb) {
|
||||
dissect_af(next_tvb, pinfo, tree);
|
||||
}
|
||||
}
|
||||
|
||||
/** Dissect an AF Packet. Parse an AF packet, checking the CRC if the CRC valid
|
||||
* flag is set and calling any registered sub dissectors on the payload type.
|
||||
* Currently only a payload type 'T' is defined which is the tag packet layer.
|
||||
* If any others are defined then they can register themselves.
|
||||
* \param[in,out] tvb The buffer containing the packet
|
||||
* \param[in,out] pinfo The packet info structure
|
||||
* \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
|
||||
*/
|
||||
static void
|
||||
dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
|
||||
{
|
||||
gint offset = 0;
|
||||
proto_item *ti = NULL;
|
||||
proto_item *li = NULL;
|
||||
proto_item *ci = NULL;
|
||||
proto_tree *af_tree = NULL;
|
||||
guint8 ver, pt;
|
||||
guint32 payload_len;
|
||||
tvbuff_t *next_tvb = NULL;
|
||||
|
||||
pinfo->current_proto = "DCP-AF";
|
||||
if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
|
||||
col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-AF");
|
||||
}
|
||||
|
||||
if (tree) { /* we are being asked for details */
|
||||
ti = proto_tree_add_item (tree, proto_af, tvb, 0, -1, FALSE);
|
||||
af_tree = proto_item_add_subtree (ti, ett_af);
|
||||
proto_tree_add_item (af_tree, hf_edcp_sync, tvb, offset, 2, FALSE);
|
||||
}
|
||||
offset += 2;
|
||||
payload_len = tvb_get_ntohl(tvb, offset);
|
||||
if (tree) {
|
||||
guint32 real_payload_len = tvb_length(tvb)-12;
|
||||
li = proto_tree_add_item (af_tree, hf_edcp_len, tvb, offset, 4, FALSE);
|
||||
if(real_payload_len < payload_len) {
|
||||
proto_item_append_text (li, " (wrong len claims %d is %d)",
|
||||
payload_len, real_payload_len
|
||||
);
|
||||
} else if(real_payload_len > payload_len) {
|
||||
proto_item_append_text (li, " (%d bytes in packet after end of AF frame)",
|
||||
real_payload_len-payload_len
|
||||
);
|
||||
}
|
||||
}
|
||||
offset += 4;
|
||||
if (tree)
|
||||
proto_tree_add_item (af_tree, hf_edcp_seq, tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
ver = tvb_get_guint8 (tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_item (af_tree, hf_edcp_crcflag, tvb, offset, 1, FALSE);
|
||||
proto_tree_add_item (af_tree, hf_edcp_maj, tvb, offset, 1, FALSE);
|
||||
proto_tree_add_item (af_tree, hf_edcp_min, tvb, offset, 1, FALSE);
|
||||
}
|
||||
offset += 1;
|
||||
pt = tvb_get_guint8 (tvb, offset);
|
||||
if (tree)
|
||||
proto_tree_add_item (af_tree, hf_edcp_pt, tvb, offset, 1, FALSE);
|
||||
offset += 1;
|
||||
next_tvb = tvb_new_subset (tvb, offset, payload_len, -1);
|
||||
offset += payload_len;
|
||||
if (tree)
|
||||
ci = proto_tree_add_item (af_tree, hf_edcp_crc, tvb, offset, 2, FALSE);
|
||||
if (ver & 0x80) { /* crc valid */
|
||||
guint len = offset+2;
|
||||
const guint8 *crc_buf = tvb_get_ptr(tvb, 0, len);
|
||||
unsigned long c = crc_drm(crc_buf, len, 16, 0x11021, 1);
|
||||
if (tree) {
|
||||
proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
|
||||
proto_tree_add_boolean(af_tree, hf_edcp_crc_ok, tvb, offset, 2, c==0xe2f0);
|
||||
}
|
||||
}
|
||||
offset += 2;
|
||||
dissector_try_port(af_dissector_table, pt, next_tvb, pinfo, tree);
|
||||
}
|
||||
|
||||
/** Dissect the Tag Packet Layer.
|
||||
* Split the AF packet into its tag items. Each tag item has a 4 character
|
||||
* tag, a length in bits and a value. The *ptr tag is dissected in the routine.
|
||||
* All other tags are listed and may be handled by other dissectors.
|
||||
* Child dissectors are tied to the parent tree, not to this tree, so that
|
||||
* they appear at the same level as DCP.
|
||||
* \param[in,out] tvb The buffer containing the packet
|
||||
* \param[in,out] pinfo The packet info structure
|
||||
* \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
|
||||
*/
|
||||
static void
|
||||
dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
|
||||
{
|
||||
proto_tree *tpl_tree = NULL;
|
||||
guint offset=0;
|
||||
char *prot=NULL;
|
||||
guint16 maj, min;
|
||||
|
||||
pinfo->current_proto = "DCP-TPL";
|
||||
if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
|
||||
col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-TPL");
|
||||
}
|
||||
|
||||
if(tree) {
|
||||
proto_item *ti = NULL;
|
||||
ti = proto_tree_add_item (tree, proto_tpl, tvb, 0, -1, FALSE);
|
||||
tpl_tree = proto_item_add_subtree (ti, ett_tpl);
|
||||
}
|
||||
while(offset<tvb_length(tvb)) {
|
||||
guint32 bits;
|
||||
guint32 bytes;
|
||||
char *tag = (char*)tvb_get_string (tvb, offset, 4); offset += 4;
|
||||
bits = tvb_get_ntohl(tvb, offset); offset += 4;
|
||||
bytes = bits / 8;
|
||||
if(bits % 8)
|
||||
bytes++;
|
||||
if(tree) {
|
||||
proto_item *i = NULL;
|
||||
const guint8 *p = tvb_get_ptr(tvb, offset, bytes);
|
||||
if(strcmp(tag, "*ptr")==0) {
|
||||
prot = (char*)tvb_get_string (tvb, offset, 4);
|
||||
maj = tvb_get_ntohs(tvb, offset+4);
|
||||
min = tvb_get_ntohs(tvb, offset+6);
|
||||
i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
|
||||
offset-8, bytes+8, p, "%s %s rev %d.%d", tag, prot, maj, min);
|
||||
} else {
|
||||
i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
|
||||
offset-8, bytes+8, p, "%s (%u bits)", tag, bits);
|
||||
}
|
||||
}
|
||||
offset += bytes;
|
||||
}
|
||||
if(prot) {
|
||||
if(tree) {
|
||||
dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent);
|
||||
} else {
|
||||
dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
proto_reg_handoff_dcp_etsi (void)
|
||||
{
|
||||
static int Initialized = FALSE;
|
||||
|
||||
if (!Initialized) {
|
||||
af_handle = create_dissector_handle(dissect_af, proto_af);
|
||||
pft_handle = create_dissector_handle(dissect_pft, proto_pft);
|
||||
tpl_handle = create_dissector_handle(dissect_tpl, proto_tpl);
|
||||
heur_dissector_add("udp", dissect_dcp_etsi, proto_dcp_etsi);
|
||||
dissector_add_string("dcp-etsi.sync", "AF", af_handle);
|
||||
dissector_add_string("dcp-etsi.sync", "PF", pft_handle);
|
||||
/* if there are ever other payload types ...*/
|
||||
dissector_add("dcp-af.pt", 'T', tpl_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
proto_register_dcp_etsi (void)
|
||||
{
|
||||
module_t *dcp_module;
|
||||
static hf_register_info hf_edcp[] = {
|
||||
{&hf_edcp_sync,
|
||||
{"sync", "dcp-etsi.sync",
|
||||
FT_STRING, BASE_NONE, NULL, 0,
|
||||
"AF or PF", HFILL}
|
||||
}
|
||||
};
|
||||
static hf_register_info hf_af[] = {
|
||||
{&hf_edcp_len,
|
||||
{"length", "dcp-af.len",
|
||||
FT_UINT32, BASE_DEC, NULL, 0,
|
||||
"length in bytes of the payload", HFILL}
|
||||
},
|
||||
{&hf_edcp_seq,
|
||||
{"frame count", "dcp-af.seq",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Logical Frame Number", HFILL}
|
||||
},
|
||||
{&hf_edcp_crcflag,
|
||||
{"crc flag", "dcp-af.crcflag",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x80,
|
||||
"Frame is protected by CRC", HFILL}
|
||||
},
|
||||
{&hf_edcp_maj,
|
||||
{"Major Revision", "dcp-af.maj",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x70,
|
||||
"Major Protocol Revision", HFILL}
|
||||
},
|
||||
{&hf_edcp_min,
|
||||
{"Minor Revision", "dcp-af.min",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0f,
|
||||
"Minor Protocol Revision", HFILL}
|
||||
},
|
||||
{&hf_edcp_pt,
|
||||
{"Payload Type", "dcp-af.pt",
|
||||
FT_STRING, BASE_NONE, NULL, 0,
|
||||
"T means Tag Packets, all other values reserved", HFILL}
|
||||
},
|
||||
{&hf_edcp_crc,
|
||||
{"CRC", "dcp-af.crc",
|
||||
FT_UINT16, BASE_HEX, NULL, 0,
|
||||
"CRC", HFILL}
|
||||
},
|
||||
{&hf_edcp_crc_ok,
|
||||
{"CRC OK", "dcp-af.crc_ok",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0,
|
||||
"AF CRC OK", HFILL}
|
||||
}
|
||||
};
|
||||
|
||||
static hf_register_info hf_pft[] = {
|
||||
{&hf_edcp_pft_pt,
|
||||
{"Sub-protocol", "dcp-pft.pt",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Always AF", HFILL}
|
||||
},
|
||||
{&hf_edcp_pseq,
|
||||
{"Sequence No", "dcp-pft.seq",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"PFT Sequence No", HFILL}
|
||||
},
|
||||
{&hf_edcp_findex,
|
||||
{"Fragment Index", "dcp-pft.findex",
|
||||
FT_UINT24, BASE_DEC, NULL, 0,
|
||||
"Index of the fragment within one AF Packet", HFILL}
|
||||
},
|
||||
{&hf_edcp_fcount,
|
||||
{"Fragment Count", "dcp-pft.fcount",
|
||||
FT_UINT24, BASE_DEC, NULL, 0,
|
||||
"Number of fragments produced from this AF Packet", HFILL}
|
||||
},
|
||||
{&hf_edcp_fecflag,
|
||||
{"FEC", "dcp-pft.fec",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x8000,
|
||||
"When set the optional RS header is present", HFILL}
|
||||
},
|
||||
{&hf_edcp_addrflag,
|
||||
{"Addr", "dcp-pft.addr",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x4000,
|
||||
"When set the optional transport header is present", HFILL}
|
||||
},
|
||||
{&hf_edcp_plen,
|
||||
{"fragment length", "dcp-pft.len",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x3fff,
|
||||
"length in bytes of the payload of this fragment", HFILL}
|
||||
},
|
||||
{&hf_edcp_rsk,
|
||||
{"RSk", "dcp-pft.rsk",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"The length of the Reed Solomon data word", HFILL}
|
||||
},
|
||||
{&hf_edcp_rsz,
|
||||
{"RSz", "dcp-pft.rsz",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"The number of padding bytes in the last Reed Solomon block", HFILL}
|
||||
},
|
||||
{&hf_edcp_source,
|
||||
{"source addr", "dcp-pft.source",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"PFT source identifier", HFILL}
|
||||
},
|
||||
{&hf_edcp_dest,
|
||||
{"dest addr", "dcp-pft.dest",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"PFT destination identifier", HFILL}
|
||||
},
|
||||
{&hf_edcp_hcrc,
|
||||
{"header CRC", "dcp-pft.crc",
|
||||
FT_UINT16, BASE_HEX, NULL, 0,
|
||||
"PFT Header CRC", HFILL}
|
||||
},
|
||||
{&hf_edcp_hcrc_ok,
|
||||
{"PFT CRC OK", "dcp-pft.crc_ok",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0,
|
||||
"PFT Header CRC OK", HFILL}
|
||||
},
|
||||
{&hf_edcp_fragments,
|
||||
{"Message fragments", "dcp-pft.fragments",
|
||||
FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_fragment,
|
||||
{"Message fragment", "dcp-pft.fragment",
|
||||
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_fragment_overlap,
|
||||
{"Message fragment overlap", "dcp-pft.fragment.overlap",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_fragment_overlap_conflicts,
|
||||
{"Message fragment overlapping with conflicting data",
|
||||
"dcp-pft.fragment.overlap.conflicts",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_fragment_multiple_tails,
|
||||
{"Message has multiple tail fragments",
|
||||
"dcp-pft.fragment.multiple_tails",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_fragment_too_long_fragment,
|
||||
{"Message fragment too long", "dcp-pft.fragment.too_long_fragment",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_fragment_error,
|
||||
{"Message defragmentation error", "dcp-pft.fragment.error",
|
||||
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_reassembled_in,
|
||||
{"Reassembled in", "dcp-pft.reassembled.in",
|
||||
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
|
||||
{&hf_edcp_c_max,
|
||||
{"C max", "dcp-pft.cmax",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Maximum number of RS chunks sent", HFILL}
|
||||
},
|
||||
{&hf_edcp_rx_min,
|
||||
{"Rx min", "dcp-pft.rxmin",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Minimum number of fragments needed for RS decode", HFILL}
|
||||
},
|
||||
{&hf_edcp_rs_corrected,
|
||||
{"RS Symbols Corrected", "dcp-pft.rs_corrected",
|
||||
FT_INT16, BASE_DEC, NULL, 0,
|
||||
"Number of symbols corrected by RS decode or -1 for failure", HFILL}
|
||||
},
|
||||
{&hf_edcp_rs_ok,
|
||||
{"RS decode OK", "dcp-pft.rs_ok",
|
||||
FT_BOOLEAN, BASE_NONE, NULL, 0,
|
||||
"successfully decoded RS blocks", HFILL}
|
||||
},
|
||||
{&hf_edcp_pft_payload,
|
||||
{"payload", "dcp-pft.payload",
|
||||
FT_BYTES, BASE_HEX, NULL, 0,
|
||||
"PFT Payload", HFILL}
|
||||
}
|
||||
};
|
||||
|
||||
static hf_register_info hf_tpl[] = {
|
||||
{&hf_tpl_tlv,
|
||||
{"tag", "dcp-tpl.tlv",
|
||||
FT_BYTES, BASE_HEX, NULL, 0,
|
||||
"Tag Packet", HFILL}
|
||||
},
|
||||
{&hf_tpl_ptr,
|
||||
{"Type", "dcp-tpl.ptr",
|
||||
FT_STRING, BASE_NONE, NULL, 0,
|
||||
"Protocol Type & Revision", HFILL}
|
||||
}
|
||||
};
|
||||
|
||||
/* Setup protocol subtree array */
|
||||
static gint *ett[] = {
|
||||
&ett_edcp,
|
||||
&ett_af,
|
||||
&ett_pft,
|
||||
&ett_tpl,
|
||||
&ett_edcp_fragment,
|
||||
&ett_edcp_fragments
|
||||
};
|
||||
|
||||
if (proto_dcp_etsi == -1) {
|
||||
proto_dcp_etsi = proto_register_protocol ("ETSI Distribution & Communication Protocol (for DRM)", /* name */
|
||||
"DCP (ETSI)", /* short name */
|
||||
"dcp-etsi" /* abbrev */
|
||||
);
|
||||
proto_af = proto_register_protocol ("DCP Application Framing Layer", "DCP-AF", "dcp-af");
|
||||
proto_pft = proto_register_protocol ("DCP Protection, Fragmentation & Transport Layer", "DCP-PFT", "dcp-pft");
|
||||
proto_tpl = proto_register_protocol ("DCP Tag Packet Layer", "DCP-TPL", "dcp-tpl");
|
||||
|
||||
|
||||
}
|
||||
dcp_module = prefs_register_protocol (proto_dcp_etsi, proto_reg_handoff_dcp_etsi);
|
||||
proto_register_field_array (proto_dcp_etsi, hf_edcp, array_length (hf_edcp));
|
||||
proto_register_field_array (proto_af, hf_af, array_length (hf_af));
|
||||
proto_register_field_array (proto_pft, hf_pft, array_length (hf_pft));
|
||||
proto_register_field_array (proto_tpl, hf_tpl, array_length (hf_tpl));
|
||||
proto_register_subtree_array (ett, array_length (ett));
|
||||
|
||||
/* subdissector code */
|
||||
dcp_dissector_table = register_dissector_table("dcp-etsi.sync",
|
||||
"DCP Sync", FT_STRING, BASE_NONE);
|
||||
af_dissector_table = register_dissector_table("dcp-af.pt",
|
||||
"AF Payload Type", FT_UINT8, BASE_DEC);
|
||||
|
||||
tpl_dissector_table = register_dissector_table("dcp-tpl.ptr",
|
||||
"AF Payload Type", FT_STRING, BASE_NONE);
|
||||
|
||||
register_init_routine(dcp_init_protocol);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,672 @@
|
|||
/*
|
||||
* Reed-Solomon coding and decoding
|
||||
* Phil Karn (karn@ka9q.ampr.org) September 1996
|
||||
* Separate CCSDS version create Dec 1998, merged into this version May 1999
|
||||
*
|
||||
* This file is derived from my generic RS encoder/decoder, which is
|
||||
* in turn based on the program "new_rs_erasures.c" by Robert
|
||||
* Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy
|
||||
* (harit@spectra.eng.hawaii.edu), Aug 1995
|
||||
|
||||
* Copyright 1999 Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU public license
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "reedsolomon.h"
|
||||
|
||||
#ifdef CCSDS
|
||||
/* CCSDS field generator polynomial: 1+x+x^2+x^7+x^8 */
|
||||
int Pp[MM+1] = { 1, 1, 1, 0, 0, 0, 0, 1, 1 };
|
||||
|
||||
#else /* not CCSDS */
|
||||
/* MM, KK, B0, PRIM are user-defined in rs.h */
|
||||
|
||||
/* Primitive polynomials - see Lin & Costello, Appendix A,
|
||||
* and Lee & Messerschmitt, p. 453.
|
||||
*/
|
||||
#if(MM == 2)/* Admittedly silly */
|
||||
int Pp[MM+1] = { 1, 1, 1 };
|
||||
|
||||
#elif(MM == 3)
|
||||
/* 1 + x + x^3 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 1 };
|
||||
|
||||
#elif(MM == 4)
|
||||
/* 1 + x + x^4 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 5)
|
||||
/* 1 + x^2 + x^5 */
|
||||
int Pp[MM+1] = { 1, 0, 1, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 6)
|
||||
/* 1 + x + x^6 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 7)
|
||||
/* 1 + x^3 + x^7 */
|
||||
int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 8)
|
||||
/* 1+x^2+x^3+x^4+x^8 */
|
||||
int Pp[MM+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 9)
|
||||
/* 1+x^4+x^9 */
|
||||
int Pp[MM+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 10)
|
||||
/* 1+x^3+x^10 */
|
||||
int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 11)
|
||||
/* 1+x^2+x^11 */
|
||||
int Pp[MM+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 12)
|
||||
/* 1+x+x^4+x^6+x^12 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 13)
|
||||
/* 1+x+x^3+x^4+x^13 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 14)
|
||||
/* 1+x+x^6+x^10+x^14 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 15)
|
||||
/* 1+x+x^15 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
#elif(MM == 16)
|
||||
/* 1+x+x^3+x^12+x^16 */
|
||||
int Pp[MM+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 };
|
||||
|
||||
#else
|
||||
#error "Either CCSDS must be defined, or MM must be set in range 2-16"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef STANDARD_ORDER /* first byte transmitted is index of x**(KK-1) in message poly*/
|
||||
/* definitions used in the encode routine*/
|
||||
#define MESSAGE(i) data[KK-(i)-1]
|
||||
#define REMAINDER(i) bb[NN-KK-(i)-1]
|
||||
/* definitions used in the decode routine*/
|
||||
#define RECEIVED(i) data[NN-1-(i)]
|
||||
#define ERAS_INDEX(i) (NN-1-eras_pos[i])
|
||||
#define INDEX_TO_POS(i) (NN-1-(i))
|
||||
#else /* first byte transmitted is index of x**0 in message polynomial*/
|
||||
/* definitions used in the encode routine*/
|
||||
#define MESSAGE(i) data[i]
|
||||
#define REMAINDER(i) bb[i]
|
||||
/* definitions used in the decode routine*/
|
||||
#define RECEIVED(i) data[i]
|
||||
#define ERAS_INDEX(i) eras_pos[i]
|
||||
#define INDEX_TO_POS(i) i
|
||||
#endif
|
||||
|
||||
|
||||
/* This defines the type used to store an element of the Galois Field
|
||||
* used by the code. Make sure this is something larger than a char if
|
||||
* if anything larger than GF(256) is used.
|
||||
*
|
||||
* Note: unsigned char will work up to GF(256) but int seems to run
|
||||
* faster on the Pentium.
|
||||
*/
|
||||
typedef int gf;
|
||||
|
||||
/* index->polynomial form conversion table */
|
||||
static gf Alpha_to[NN + 1];
|
||||
|
||||
/* Polynomial->index form conversion table */
|
||||
static gf Index_of[NN + 1];
|
||||
|
||||
/* No legal value in index form represents zero, so
|
||||
* we need a special value for this purpose
|
||||
*/
|
||||
#define A0 (NN)
|
||||
|
||||
/* Generator polynomial g(x) in index form */
|
||||
static gf Gg[NN - KK + 1];
|
||||
|
||||
static int RS_init; /* Initialization flag */
|
||||
|
||||
/* Compute x % NN, where NN is 2**MM - 1,
|
||||
* without a slow divide
|
||||
*/
|
||||
/* static inline gf*/
|
||||
static gf
|
||||
modnn(int x)
|
||||
{
|
||||
while (x >= NN) {
|
||||
x -= NN;
|
||||
x = (x >> MM) + (x & NN);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#define min_(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define CLEAR(a,n) {\
|
||||
int ci;\
|
||||
for(ci=(n)-1;ci >=0;ci--)\
|
||||
(a)[ci] = 0;\
|
||||
}
|
||||
|
||||
#define COPY(a,b,n) {\
|
||||
int ci;\
|
||||
for(ci=(n)-1;ci >=0;ci--)\
|
||||
(a)[ci] = (b)[ci];\
|
||||
}
|
||||
|
||||
#define COPYDOWN(a,b,n) {\
|
||||
int ci;\
|
||||
for(ci=(n)-1;ci >=0;ci--)\
|
||||
(a)[ci] = (b)[ci];\
|
||||
}
|
||||
|
||||
static void init_rs(void);
|
||||
|
||||
#ifdef CCSDS
|
||||
/* Conversion lookup tables from conventional alpha to Berlekamp's
|
||||
* dual-basis representation. Used in the CCSDS version only.
|
||||
* taltab[] -- convert conventional to dual basis
|
||||
* tal1tab[] -- convert dual basis to conventional
|
||||
|
||||
* Note: the actual RS encoder/decoder works with the conventional basis.
|
||||
* So data is converted from dual to conventional basis before either
|
||||
* encoding or decoding and then converted back.
|
||||
*/
|
||||
static unsigned char taltab[NN+1],tal1tab[NN+1];
|
||||
|
||||
static unsigned char tal[] = { 0x8d, 0xef, 0xec, 0x86, 0xfa, 0x99, 0xaf, 0x7b };
|
||||
|
||||
/* Generate conversion lookup tables between conventional alpha representation
|
||||
* (@**7, @**6, ...@**0)
|
||||
* and Berlekamp's dual basis representation
|
||||
* (l0, l1, ...l7)
|
||||
*/
|
||||
static void
|
||||
gen_ltab(void)
|
||||
{
|
||||
int i,j,k;
|
||||
|
||||
for(i=0;i<256;i++){/* For each value of input */
|
||||
taltab[i] = 0;
|
||||
for(j=0;j<8;j++) /* for each column of matrix */
|
||||
for(k=0;k<8;k++){ /* for each row of matrix */
|
||||
if(i & (1<<k))
|
||||
taltab[i] ^= tal[7-k] & (1<<j);
|
||||
}
|
||||
tal1tab[taltab[i]] = i;
|
||||
}
|
||||
}
|
||||
#endif /* CCSDS */
|
||||
|
||||
#if PRIM != 1
|
||||
static int Ldec;/* Decrement for aux location variable in Chien search */
|
||||
|
||||
static void
|
||||
gen_ldec(void)
|
||||
{
|
||||
for(Ldec=1;(Ldec % PRIM) != 0;Ldec+= NN)
|
||||
;
|
||||
Ldec /= PRIM;
|
||||
}
|
||||
#else
|
||||
#define Ldec 1
|
||||
#endif
|
||||
|
||||
/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
|
||||
lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
|
||||
polynomial form -> index form index_of[j=alpha**i] = i
|
||||
alpha=2 is the primitive element of GF(2**m)
|
||||
HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
|
||||
Let @ represent the primitive element commonly called "alpha" that
|
||||
is the root of the primitive polynomial p(x). Then in GF(2^m), for any
|
||||
0 <= i <= 2^m-2,
|
||||
@^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
|
||||
where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
|
||||
of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
|
||||
example the polynomial representation of @^5 would be given by the binary
|
||||
representation of the integer "alpha_to[5]".
|
||||
Similarily, index_of[] can be used as follows:
|
||||
As above, let @ represent the primitive element of GF(2^m) that is
|
||||
the root of the primitive polynomial p(x). In order to find the power
|
||||
of @ (alpha) that has the polynomial representation
|
||||
a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
|
||||
we consider the integer "i" whose binary representation with a(0) being LSB
|
||||
and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
|
||||
"index_of[i]". Now, @^index_of[i] is that element whose polynomial
|
||||
representation is (a(0),a(1),a(2),...,a(m-1)).
|
||||
NOTE:
|
||||
The element alpha_to[2^m-1] = 0 always signifying that the
|
||||
representation of "@^infinity" = 0 is (0,0,0,...,0).
|
||||
Similarily, the element index_of[0] = A0 always signifying
|
||||
that the power of alpha which has the polynomial representation
|
||||
(0,0,...,0) is "infinity".
|
||||
|
||||
*/
|
||||
|
||||
static void
|
||||
generate_gf(void)
|
||||
{
|
||||
register int i, mask;
|
||||
|
||||
mask = 1;
|
||||
Alpha_to[MM] = 0;
|
||||
for (i = 0; i < MM; i++) {
|
||||
Alpha_to[i] = mask;
|
||||
Index_of[Alpha_to[i]] = i;
|
||||
/* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
|
||||
if (Pp[i] != 0)
|
||||
Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */
|
||||
mask <<= 1; /* single left-shift */
|
||||
}
|
||||
Index_of[Alpha_to[MM]] = MM;
|
||||
/*
|
||||
* Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
|
||||
* poly-repr of @^i shifted left one-bit and accounting for any @^MM
|
||||
* term that may occur when poly-repr of @^i is shifted.
|
||||
*/
|
||||
mask >>= 1;
|
||||
for (i = MM + 1; i < NN; i++) {
|
||||
if (Alpha_to[i - 1] >= mask)
|
||||
Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
|
||||
else
|
||||
Alpha_to[i] = Alpha_to[i - 1] << 1;
|
||||
Index_of[Alpha_to[i]] = i;
|
||||
}
|
||||
Index_of[0] = A0;
|
||||
Alpha_to[NN] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain the generator polynomial of the TT-error correcting, length
|
||||
* NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0,
|
||||
* ... ,(2*TT-1)
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2.
|
||||
* g(x) = (x+@) (x+@**2)
|
||||
*
|
||||
* If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4.
|
||||
* g(x) = (x+1) (x+@) (x+@**2) (x+@**3)
|
||||
*/
|
||||
static void
|
||||
gen_poly(void)
|
||||
{
|
||||
register int i, j;
|
||||
|
||||
Gg[0] = 1;
|
||||
for (i = 0; i < NN - KK; i++) {
|
||||
Gg[i+1] = 1;
|
||||
/*
|
||||
* Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by
|
||||
* (@**(B0+i)*PRIM + x)
|
||||
*/
|
||||
for (j = i; j > 0; j--)
|
||||
if (Gg[j] != 0)
|
||||
Gg[j] = Gg[j - 1] ^ Alpha_to[modnn((Index_of[Gg[j]]) + (B0 + i) *PRIM)];
|
||||
else
|
||||
Gg[j] = Gg[j - 1];
|
||||
/* Gg[0] can never be zero */
|
||||
Gg[0] = Alpha_to[modnn(Index_of[Gg[0]] + (B0 + i) * PRIM)];
|
||||
}
|
||||
/* convert Gg[] to index form for quicker encoding */
|
||||
for (i = 0; i <= NN - KK; i++)
|
||||
Gg[i] = Index_of[Gg[i]];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* take the string of symbols in data[i], i=0..(k-1) and encode
|
||||
* systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[]
|
||||
* is input and bb[] is output in polynomial form. Encoding is done by using
|
||||
* a feedback shift register with appropriate connections specified by the
|
||||
* elements of Gg[], which was generated above. Codeword is c(X) =
|
||||
* data(X)*X**(NN-KK)+ b(X)
|
||||
*/
|
||||
|
||||
int
|
||||
encode_rs(dtype data[KK], dtype bb[NN-KK])
|
||||
{
|
||||
register int i, j;
|
||||
gf feedback;
|
||||
|
||||
#if DEBUG >= 1 && MM != 8
|
||||
/* Check for illegal input values */
|
||||
for(i=0;i<KK;i++)
|
||||
if(MESSAGE(i) > NN)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if(!RS_init)
|
||||
init_rs();
|
||||
|
||||
CLEAR(bb,NN-KK);
|
||||
|
||||
#ifdef CCSDS
|
||||
/* Convert to conventional basis */
|
||||
for(i=0;i<KK;i++)
|
||||
MESSAGE(i) = tal1tab[MESSAGE(i)];
|
||||
#endif
|
||||
|
||||
for(i = KK - 1; i >= 0; i--) {
|
||||
feedback = Index_of[MESSAGE(i) ^ REMAINDER(NN - KK - 1)];
|
||||
if (feedback != A0) { /* feedback term is non-zero */
|
||||
for (j = NN - KK - 1; j > 0; j--)
|
||||
if (Gg[j] != A0)
|
||||
REMAINDER(j) = REMAINDER(j - 1) ^ Alpha_to[modnn(Gg[j] + feedback)];
|
||||
else
|
||||
REMAINDER(j) = REMAINDER(j - 1);
|
||||
REMAINDER(0) = Alpha_to[modnn(Gg[0] + feedback)];
|
||||
} else { /* feedback term is zero. encoder becomes a
|
||||
* single-byte shifter */
|
||||
for (j = NN - KK - 1; j > 0; j--)
|
||||
REMAINDER(j) = REMAINDER(j - 1);
|
||||
REMAINDER(0) = 0;
|
||||
}
|
||||
}
|
||||
#ifdef CCSDS
|
||||
/* Convert to l-basis */
|
||||
for(i=0;i<NN;i++)
|
||||
MESSAGE(i) = taltab[MESSAGE(i)];
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful,
|
||||
* writes the codeword into data[] itself. Otherwise data[] is unaltered.
|
||||
*
|
||||
* Return number of symbols corrected, or -1 if codeword is illegal
|
||||
* or uncorrectable. If eras_pos is non-null, the detected error locations
|
||||
* are written back. NOTE! This array must be at least NN-KK elements long.
|
||||
*
|
||||
* First "no_eras" erasures are declared by the calling program. Then, the
|
||||
* maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
|
||||
* If the number of channel errors is not greater than "t_after_eras" the
|
||||
* transmitted codeword will be recovered. Details of algorithm can be found
|
||||
* in R. Blahut's "Theory ... of Error-Correcting Codes".
|
||||
|
||||
* Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
|
||||
* will result. The decoder *could* check for this condition, but it would involve
|
||||
* extra time on every decoding operation.
|
||||
*/
|
||||
|
||||
int
|
||||
eras_dec_rs(dtype data[NN], int eras_pos[NN-KK], int no_eras)
|
||||
{
|
||||
int deg_lambda, el, deg_omega;
|
||||
int i, j, r,k;
|
||||
gf u,q,tmp,num1,num2,den,discr_r;
|
||||
gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly
|
||||
* and syndrome poly */
|
||||
gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
|
||||
gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
|
||||
int syn_error, count;
|
||||
|
||||
if(!RS_init)
|
||||
init_rs();
|
||||
|
||||
#ifdef CCSDS
|
||||
/* Convert to conventional basis */
|
||||
for(i=0;i<NN;i++)
|
||||
RECEIVED(i) = tal1tab[RECEIVED(i)];
|
||||
#endif
|
||||
|
||||
#if DEBUG >= 1 && MM != 8
|
||||
/* Check for illegal input values */
|
||||
for(i=0;i<NN;i++)
|
||||
if(RECEIVED(i) > NN)
|
||||
return -1;
|
||||
#endif
|
||||
/* form the syndromes; i.e., evaluate data(x) at roots of g(x)
|
||||
* namely @**(B0+i)*PRIM, i = 0, ... ,(NN-KK-1)
|
||||
*/
|
||||
for(i=1;i<=NN-KK;i++){
|
||||
s[i] = RECEIVED(0);
|
||||
}
|
||||
for(j=1;j<NN;j++){
|
||||
if(RECEIVED(j) == 0)
|
||||
continue;
|
||||
tmp = Index_of[RECEIVED(j)];
|
||||
|
||||
/* s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*j)]; */
|
||||
for(i=1;i<=NN-KK;i++)
|
||||
s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
|
||||
}
|
||||
/* Convert syndromes to index form, checking for nonzero condition */
|
||||
syn_error = 0;
|
||||
for(i=1;i<=NN-KK;i++){
|
||||
syn_error |= s[i];
|
||||
/*printf("syndrome %d = %x\n",i,s[i]);*/
|
||||
s[i] = Index_of[s[i]];
|
||||
}
|
||||
|
||||
if (!syn_error) {
|
||||
/* if syndrome is zero, data[] is a codeword and there are no
|
||||
* errors to correct. So return data[] unmodified
|
||||
*/
|
||||
count = 0;
|
||||
goto finish;
|
||||
}
|
||||
CLEAR(&lambda[1],NN-KK);
|
||||
lambda[0] = 1;
|
||||
|
||||
if (no_eras > 0) {
|
||||
/* Init lambda to be the erasure locator polynomial */
|
||||
lambda[1] = Alpha_to[modnn(PRIM * ERAS_INDEX(0))];
|
||||
for (i = 1; i < no_eras; i++) {
|
||||
u = modnn(PRIM*ERAS_INDEX(i));
|
||||
for (j = i+1; j > 0; j--) {
|
||||
tmp = Index_of[lambda[j - 1]];
|
||||
if(tmp != A0)
|
||||
lambda[j] ^= Alpha_to[modnn(u + tmp)];
|
||||
}
|
||||
}
|
||||
#if DEBUG >= 1
|
||||
/* Test code that verifies the erasure locator polynomial just constructed
|
||||
Needed only for decoder debugging. */
|
||||
|
||||
/* find roots of the erasure location polynomial */
|
||||
for(i=1;i<=no_eras;i++)
|
||||
reg[i] = Index_of[lambda[i]];
|
||||
count = 0;
|
||||
for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
|
||||
q = 1;
|
||||
for (j = 1; j <= no_eras; j++)
|
||||
if (reg[j] != A0) {
|
||||
reg[j] = modnn(reg[j] + j);
|
||||
q ^= Alpha_to[reg[j]];
|
||||
}
|
||||
if (q != 0)
|
||||
continue;
|
||||
/* store root and error location number indices */
|
||||
root[count] = i;
|
||||
loc[count] = k;
|
||||
count++;
|
||||
}
|
||||
if (count != no_eras) {
|
||||
printf("\n lambda(x) is WRONG\n");
|
||||
count = -1;
|
||||
goto finish;
|
||||
}
|
||||
#if DEBUG >= 2
|
||||
printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
|
||||
for (i = 0; i < count; i++)
|
||||
printf("%d ", loc[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
for(i=0;i<NN-KK+1;i++)
|
||||
b[i] = Index_of[lambda[i]];
|
||||
|
||||
/*
|
||||
* Begin Berlekamp-Massey algorithm to determine error+erasure
|
||||
* locator polynomial
|
||||
*/
|
||||
r = no_eras;
|
||||
el = no_eras;
|
||||
while (++r <= NN-KK) { /* r is the step number */
|
||||
/* Compute discrepancy at the r-th step in poly-form */
|
||||
discr_r = 0;
|
||||
for (i = 0; i < r; i++){
|
||||
if ((lambda[i] != 0) && (s[r - i] != A0)) {
|
||||
discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
|
||||
}
|
||||
}
|
||||
discr_r = Index_of[discr_r]; /* Index form */
|
||||
if (discr_r == A0) {
|
||||
/* 2 lines below: B(x) <-- x*B(x) */
|
||||
COPYDOWN(&b[1],b,NN-KK);
|
||||
b[0] = A0;
|
||||
} else {
|
||||
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for (i = 0 ; i < NN-KK; i++) {
|
||||
if(b[i] != A0)
|
||||
t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
|
||||
else
|
||||
t[i+1] = lambda[i+1];
|
||||
}
|
||||
if (2 * el <= r + no_eras - 1) {
|
||||
el = r + no_eras - el;
|
||||
/*
|
||||
* 2 lines below: B(x) <-- inv(discr_r) *
|
||||
* lambda(x)
|
||||
*/
|
||||
for (i = 0; i <= NN-KK; i++)
|
||||
b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
|
||||
} else {
|
||||
/* 2 lines below: B(x) <-- x*B(x) */
|
||||
COPYDOWN(&b[1],b,NN-KK);
|
||||
b[0] = A0;
|
||||
}
|
||||
COPY(lambda,t,NN-KK+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert lambda to index form and compute deg(lambda(x)) */
|
||||
deg_lambda = 0;
|
||||
for(i=0;i<NN-KK+1;i++){
|
||||
lambda[i] = Index_of[lambda[i]];
|
||||
if(lambda[i] != A0)
|
||||
deg_lambda = i;
|
||||
}
|
||||
/*
|
||||
* Find roots of the error+erasure locator polynomial by Chien
|
||||
* Search
|
||||
*/
|
||||
COPY(®[1],&lambda[1],NN-KK);
|
||||
count = 0; /* Number of roots of lambda(x) */
|
||||
for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
|
||||
q = 1;
|
||||
for (j = deg_lambda; j > 0; j--){
|
||||
if (reg[j] != A0) {
|
||||
reg[j] = modnn(reg[j] + j);
|
||||
q ^= Alpha_to[reg[j]];
|
||||
}
|
||||
}
|
||||
if (q != 0)
|
||||
continue;
|
||||
/* store root (index-form) and error location number */
|
||||
root[count] = i;
|
||||
loc[count] = k;
|
||||
/* If we've already found max possible roots,
|
||||
* abort the search to save time
|
||||
*/
|
||||
if(++count == deg_lambda)
|
||||
break;
|
||||
}
|
||||
if (deg_lambda != count) {
|
||||
/*
|
||||
* deg(lambda) unequal to number of roots => uncorrectable
|
||||
* error detected
|
||||
*/
|
||||
count = -1;
|
||||
goto finish;
|
||||
}
|
||||
/*
|
||||
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
|
||||
* x**(NN-KK)). in index form. Also find deg(omega).
|
||||
*/
|
||||
deg_omega = 0;
|
||||
for (i = 0; i < NN-KK;i++){
|
||||
tmp = 0;
|
||||
j = (deg_lambda < i) ? deg_lambda : i;
|
||||
for(;j >= 0; j--){
|
||||
if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
|
||||
tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
|
||||
}
|
||||
if(tmp != 0)
|
||||
deg_omega = i;
|
||||
omega[i] = Index_of[tmp];
|
||||
}
|
||||
omega[NN-KK] = A0;
|
||||
|
||||
/*
|
||||
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
|
||||
* inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
|
||||
*/
|
||||
for (j = count-1; j >=0; j--) {
|
||||
num1 = 0;
|
||||
for (i = deg_omega; i >= 0; i--) {
|
||||
if (omega[i] != A0)
|
||||
num1 ^= Alpha_to[modnn(omega[i] + i * root[j])];
|
||||
}
|
||||
num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
|
||||
den = 0;
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
for (i = min_(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
|
||||
if(lambda[i+1] != A0)
|
||||
den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
|
||||
}
|
||||
if (den == 0) {
|
||||
#if DEBUG >= 1
|
||||
printf("\n ERROR: denominator = 0\n");
|
||||
#endif
|
||||
/* Convert to dual- basis */
|
||||
count = -1;
|
||||
goto finish;
|
||||
}
|
||||
/* Apply error to data */
|
||||
if (num1 != 0) {
|
||||
RECEIVED(loc[j]) ^= Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
|
||||
}
|
||||
}
|
||||
finish:
|
||||
#ifdef CCSDS
|
||||
/* Convert to dual- basis */
|
||||
for(i=0;i<NN;i++)
|
||||
RECEIVED(i) = taltab[RECEIVED(i)];
|
||||
#endif
|
||||
if(eras_pos != NULL){
|
||||
for(i=0;i<count;i++){
|
||||
if(eras_pos!= NULL)
|
||||
eras_pos[i] = INDEX_TO_POS(loc[i]);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
/* Encoder/decoder initialization - call this first! */
|
||||
static void
|
||||
init_rs(void)
|
||||
{
|
||||
generate_gf();
|
||||
gen_poly();
|
||||
#ifdef CCSDS
|
||||
gen_ltab();
|
||||
#endif
|
||||
#if PRIM != 1
|
||||
gen_ldec();
|
||||
#endif
|
||||
RS_init = 1;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Global definitions for Reed-Solomon encoder/decoder
|
||||
* Phil Karn KA9Q, September 1996
|
||||
*/
|
||||
/* Set one of these to enable encoder/decoder debugging and error checking,
|
||||
* at the expense of speed */
|
||||
/* #undef DEBUG 1*/
|
||||
/* #undef DEBUG 2*/
|
||||
#undef DEBUG
|
||||
|
||||
/* To select the CCSDS standard (255,223) code, define CCSDS. This
|
||||
* implies standard values for MM, KK, B0 and PRIM.
|
||||
*/
|
||||
/* #undef CCSDS 1*/
|
||||
#undef CCSDS
|
||||
#ifndef CCSDS
|
||||
|
||||
/* Otherwise, leave CCSDS undefined and set the parameters below:
|
||||
*
|
||||
* Set MM to be the size of each code symbol in bits. The Reed-Solomon
|
||||
* block size will then be NN = 2**M - 1 symbols. Supported values are
|
||||
* defined in rs.c.
|
||||
*/
|
||||
#define MM 8 /* Symbol size in bits */
|
||||
|
||||
/*
|
||||
* Set KK to be the number of data symbols in each block, which must be
|
||||
* less than the block size. The code will then be able to correct up
|
||||
* to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with
|
||||
* each error counting as two erasures.
|
||||
*/
|
||||
#define KK 207 /* Number of data symbols per block */
|
||||
|
||||
/* Set B0 to the first root of the generator polynomial, in alpha form, and
|
||||
* set PRIM to the power of alpha used to generate the roots of the
|
||||
* generator polynomial. The generator polynomial will then be
|
||||
* @**PRIM*B0, @**PRIM*(B0+1), @**PRIM*(B0+2)...@**PRIM*(B0+NN-KK)
|
||||
* where "@" represents a lower case alpha.
|
||||
*/
|
||||
#define B0 1 /* First root of generator polynomial, alpha form */
|
||||
#define PRIM 1 /* power of alpha used to generate roots of generator poly */
|
||||
#define STANDARD_ORDER
|
||||
|
||||
/* If you want to select your own field generator polynomial, you'll have
|
||||
* to edit that in rs.c.
|
||||
*/
|
||||
|
||||
#else /* CCSDS */
|
||||
/* Don't change these, they're CCSDS standard */
|
||||
#define MM 8
|
||||
#define KK 223
|
||||
#define B0 112
|
||||
#define PRIM 11
|
||||
#endif
|
||||
|
||||
#define NN ((1 << MM) - 1)
|
||||
|
||||
#if MM <= 8
|
||||
typedef unsigned char dtype;
|
||||
#else
|
||||
typedef unsigned int dtype;
|
||||
#endif
|
||||
|
||||
/* Reed-Solomon encoding
|
||||
* data[] is the input block, parity symbols are placed in bb[]
|
||||
* bb[] may lie past the end of the data, e.g., for (255,223):
|
||||
* encode_rs(&data[0],&data[223]);
|
||||
*/
|
||||
int encode_rs(dtype data[], dtype bb[]);
|
||||
|
||||
/* Reed-Solomon erasures-and-errors decoding
|
||||
* The received block goes into data[], and a list of zero-origin
|
||||
* erasure positions, if any, goes in eras_pos[] with a count in no_eras.
|
||||
*
|
||||
* The decoder corrects the symbols in place, if possible and returns
|
||||
* the number of corrected symbols. If the codeword is illegal or
|
||||
* uncorrectible, the data array is unchanged and -1 is returned
|
||||
*/
|
||||
int eras_dec_rs(dtype data[], int eras_pos[], int no_eras);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue