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; }
