Hi,
* Holger Hans Peter Freyther <[email protected]> [2011-04-17 19:00]:
> On 04/04/2011 05:27 PM, Dennis Wehrle wrote:
[...] 
FWIW, your original patch and motivation also looks very 
reasonable to me!

> > The best solution for that is to store the number of septets at the database
> > (on the decoding process). Therefore i want to discuss if this is a suitable
> > solution. If we don't want to change the structure of the database i could
> > possible make a dirty hack (look if the "ud_hdr_ind" is set, get the "user
> > data header length" (udhl) from the user_data, count the number of septets
> > from "text - 1 - udhl - fill bits").
> > But i strongly recommend to change the database (i could do it).
> 
> Yes, please change the database. I think you want to increase the version of
> the database schema but I would not worry about having a migration inside the
> db.c code itself (we can have a script to update the schema and drop the SMS
> table..).

Imho the current database scheme for SMS is rather suboptimal in general
because it attempts to mix incomplete sms encoding values with decoded
user data.  As we have to properly encode the message anyway when sending 
from the vty it seems only reasonable to me to store UDL in the db as well.
This way it is very easy to do the decoding/encoding step with the already 
present data_coding_scheme value.

But thinking more about this... does it really make sense to store 
anything but control data and the actual PDU in the database? When sending 
a message from the vty the message is encoded anyway, so just inserting 
the PDU + control data should be sufficient. I'm not sure if OpenBSC has 
to be aware of things like UDHI, UDH, PID and thelike.

The only place where this is useful so far is for the debugging output. 
But what about moving this decoding for mere visual purposes to 
libosmocore completely and not store this information in the database at 
all?

Cheers
Nico
P.S. attached is a submit decoder I used in the past one 
could use as a basis for the proposed libosmocore function.
/* rudimentary SMS_SUBMIT decoder - 2010
   The file is licenced under Revision 42 of the Beerware Licence
   Nico Golde <[email protected]> wrote this file. As long as you retain this
   notice you can do whatever you want with this stuff. If we meet some day,
   and you think this stuff is worth it, you can buy me a beer in return.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PDU_SIZE 160
#define IE_L_MAX 0xff + 1

typedef struct ie {
	struct ie_t *next;
	unsigned char ie_type;
	unsigned char data[IE_L_MAX];
	unsigned char ie_l;
} ie_t;

typedef struct udh {
	ie_t *head;
	unsigned char udh_l;
} udh_t;

typedef struct sms {
	unsigned int tp_rp   :1;
	unsigned int tp_udhi :1;
	unsigned int tp_srr  :1;
	unsigned int tp_vpf  :2;
	unsigned int tp_rd   :1;
	unsigned int tp_mti  :2;
	unsigned char msg_ref;
	unsigned char msisdn_l;
	unsigned char msisdn_t;
	unsigned char *msisdn;
	unsigned char tp_pid;
	unsigned char tp_dcs;
	unsigned char tp_vp;
	unsigned char tp_ud_l;
	udh_t *udh;
} sms_t;

unsigned char *
read_pdu(char *pdu){
	unsigned char *p = malloc(PDU_SIZE);
	unsigned char *ret = p;
	unsigned char tmp;
	char foo[3] = { 0, 0, 0 };
	char *ptr = NULL;
	memset(p, 0, PDU_SIZE);

	for(ptr = pdu; ptr && *ptr; ptr += 2){
		memcpy(foo, ptr, 2);
		sscanf(foo, "%hhx", &tmp);
		memcpy(p, &tmp, 1);
		p++;
	}

	return ret;
}

unsigned char *
decode_msisdn(unsigned char *ptr, unsigned char len){
	int i;
	unsigned char *ret = NULL;
	unsigned char *tmp = NULL;
	if((ret = malloc(len)) == NULL)
		return NULL;

	memset(ret, 0, len);
	tmp = ret;

	for(i = 0; i< (len / 2) + (len % 2);i++){
		*ret = (ptr[i] & 0x0f) + 48;
		if((ptr[i] >> 4) != 0x0f){
			ret++;
			*ret = (ptr[i] >> 4) + 48;
			ret++;
		}
	}

	return tmp;
}

unsigned char *
parse_pdu_header(sms_t *csms, unsigned char *ptr){
	unsigned char *tmp;
	csms->tp_rp   = (*ptr & (1<<7)) ? 1 : 0;
	csms->tp_udhi = (*ptr & (1<<6)) ? 1 : 0;
	csms->tp_srr  = (*ptr & (1<<5)) ? 1 : 0;
	csms->tp_vpf  = (*ptr & (1<<4)) | (*ptr & (1<<3)) ? 1 : 0;
	csms->tp_rd   = (*ptr & (1<<2)) ? 1 : 0;
	csms->tp_mti  = (*ptr & (1<<1)) | (*ptr & (1<<0));

	ptr++;
	csms->msg_ref = *ptr;
	ptr++;
	csms->msisdn_l = *ptr;
	ptr++;
	csms->msisdn_t = *ptr;
	ptr++;
	tmp = ptr;

	csms->msisdn = malloc(csms->msisdn_l + 1);
	if(!csms->msisdn)
		return NULL;

	memcpy(csms->msisdn, ptr, csms->msisdn_l);
	csms->msisdn[csms->msisdn_l] = 0;

	ptr += csms->msisdn_l / 2 + (csms->msisdn_l % 2);
	csms->tp_pid = *ptr;
	ptr++;
	csms->tp_dcs = *ptr;

	/* optional flag, not implemented
		ptr++;
		sms->tp_vp = *ptr;
	*/

	ptr++;
	csms->tp_ud_l = *ptr;
	ptr++;
	return ptr;
}

ie_t *
add_information_element(unsigned char *ptr, unsigned char iel, unsigned char iet){
	ie_t *ie = malloc(sizeof(ie_t));
	if(!ie)
		return NULL;

	ie->ie_l = iel;
	ie->ie_type = iet;
	memset(ie->data, 0, ie->ie_l);
	memcpy(ie->data, ptr, ie->ie_l);

	return ie;
}

ie_t *
parse_information_elements(unsigned char *ptr, unsigned char udh_l){
	ie_t *ie = NULL;
	ie_t *ret = NULL;
	ie_t *tmp = NULL;
	unsigned char iel;
	unsigned char iet;
	unsigned char i = 0;

	while(i < udh_l){
		iet = *ptr;
		ptr++;
		iel = *ptr;
		ptr++;
		ie = add_information_element(ptr, iel, iet);
		if(ret == NULL)
			ret = ie;
		else
			tmp->next = (struct ie_t*) ie;

		tmp = ie;
		ie = (ie_t *) ie->next;

		ptr += iel;
		i += iel + 2;
	}

	return ret;
}

void
print_udh(sms_t *csms){
	udh_t *udh = csms->udh;
	ie_t *ie = udh->head;
	int i;
	while(ie){
		ie_t *tmp = ie;
		printf("IEL: %0.2x, IET: %0.2x, ", ie->ie_l, ie->ie_type);
		printf("IED: ");
		for(i = 0; i < ie->ie_l; i++){
			printf("%0.2x", ie->data[i]);
		}
		ie = (ie_t *) tmp->next;
		printf("\n");
	}
}

void
print_ud(sms_t *csms, unsigned char *ptr){
	size_t l = csms->tp_ud_l;
	size_t i;

	/* 7 bit encoding...  */
	if(!(csms->tp_dcs >> 2) & 0x03)
		l = l*7/8 + 1;

	if(csms->tp_udhi){
		l = l - csms->udh->udh_l - 1;
	}

	printf("decoding %0.2x hex bytes user data\n", l);

	for(i = 0; i < l; i++){
		printf("%0.2x", ptr[i]);
	}
	printf("\n");
}

unsigned char *
parse_udh(sms_t *csms, unsigned char *ptr){
	udh_t *udh;
	csms->udh = malloc(sizeof(udh_t));
	udh = csms->udh;

	if(!udh)
		return NULL;

	udh->udh_l = *ptr;
	ptr++;
	udh->head = parse_information_elements(ptr, udh->udh_l);

	if(!udh->head){
		printf("error in parsing information elements\n");
		return NULL;
	}

	ptr += udh->udh_l;

	return ptr;
}

void
destroy_sms(sms_t *csms){
	ie_t *ie = NULL;
	ie_t *tmp;
	if(csms->tp_udhi){
		ie = csms->udh->head;
		while(ie){
			tmp = (ie_t *) ie->next;
			free(ie);
			ie = tmp;
		}
	}
	free(csms->msisdn);
	free(csms->udh);
	free(csms);
}

int
main(int argc, char **argv){
	unsigned char *ptr;
	sms_t *csms = NULL;

	if(argc < 2){
		printf("%s <pdu>\n", argv[0]);
		return -1;
	}

	if(strlen(argv[1]) / 2 > PDU_SIZE){
		printf("input PDU too large\n");
		return -2;
	}

	printf("input pdu len: %u\n", strlen(argv[1]) / 2);
	if((csms = malloc(sizeof(sms_t))) == NULL){
		perror("malloc()");
		return -3;
	}

	memset(csms, 0, sizeof(sms_t));

	ptr = read_pdu(argv[1]);
	ptr = parse_pdu_header(csms, ptr);

	if(!ptr){
		printf("something went wrong while decoding the PDU header, submit pdu without smsc byte?\n");
		return -4;
	}

	if(csms->tp_mti != 0x1){
		printf("no valid submit PDU, FAIL\n");
		return -5;
	}

	printf("TP-RP: %0.2x\n", csms->tp_rp);
	printf("TP-UDHI: %0.2x\n", csms->tp_udhi);
	printf("TP-SRR: %0.2x\n", csms->tp_srr);
	printf("TP-VPF: %0.2x\n", csms->tp_vpf);
	printf("TP-RD: %0.2x\n", csms->tp_rd);
	printf("TP-MTI: %0.2x\n", csms->tp_mti);
	printf("MSISDN_L: %0.2x\n", csms->msisdn_l);
	printf("MSISDN_T: %0.2x\n", csms->msisdn_t);
	printf("MSISDN: %s\n", decode_msisdn(csms->msisdn, csms->msisdn_l));
	printf("TP-PID: %0.2x\n", csms->tp_pid);
	printf("TP-DCS: %0.2x\n", csms->tp_dcs);
	/*printf("TP-VP: %x\n", csms->tp_vp);*/
	printf("TP-UDL: %0.2x\n", csms->tp_ud_l);
	if(csms->tp_udhi){
		ptr = parse_udh(csms, ptr);
		printf("UDHL: %0.2x\n", csms->udh->udh_l);
		print_udh(csms);
	}

	/* should point into user data at this point */
	print_ud(csms, ptr);

	destroy_sms(csms);

	return 0;

}

Reply via email to